您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Improve Diamond Hunt 1 and fix some inconsistencies
// ==UserScript== // @name DH1 Fixed // @namespace FileFace // @description Improve Diamond Hunt 1 and fix some inconsistencies // @version 1.36.0 // @author Zorbing // @license ISC; http://opensource.org/licenses/ISC // @grant none // @run-at document-start // @include http://www.diamondhunt.co/DH1/game.php // ==/UserScript== /** * ISC License (ISC) * * Copyright (c) 2017, Martin Boekhoff * * Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby * granted, provided that the above copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * * Source: http://opensource.org/licenses/ISC */ (function () { 'use strict'; const settings = { reorderFarming: { title: 'Set seed orders coherent' , defaultValue: true , requiresReload: true } , applyNewItemStyle: { title: 'Apply a new item style' , defaultValue: true , requiresReload: true } , applyNewKeyItemStyle: { title: 'Apply a new key item and machinery style' , defaultValue: true , requiresReload: true } , improveDialogBtns: { title: 'Improve button captions in dialogs' , defaultValue: true } , improveMachineryDialog: { title: 'Improve the machinery dialog' , defaultValue: true , requiresReload: 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 , requiresReload: true } , hideEquipment: { title: 'Hide inferiour equipment (only up to gold)' , defaultValue: true } , hideUnnecessaryPrice: { title: 'Hide "0 coins"-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 pm tabs' , defaultValue: true , requiresReload: true } , addSubTabs: { title: 'Add sub tabs' , defaultValue: true } }; let fullyLoaded = false; function notify(title, options) { if (!getSetting('showNotifications')) { // notifications disabled: return stub notification return Promise.resolve({ close: () => {} }); } if (!("Notification" in window) || Notification.permission === 'denied') { return Promise.reject('Notification permission denied'); } if (Notification.permission === 'granted') { return Promise.resolve(new Notification(title, options)); } return Notification.requestPermission().then(() => notify(title, options)); }; /** * 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; }; } /** * global misc functions */ const itemInfo = { oil: { name: 'Oil' , plural: false , img: 'oil.png' } , sand: { name: 'Sand' , plural: false , img: 'minerals/sand.png' } , stone: { name: 'Stone' , plural: false , img: 'stone.png' } , copper: { name: 'Copper' , plural: false , img: 'minerals/copper.png' } , tin: { name: 'Tin' , plural: false , img: 'minerals/tin.png' } , iron: { name: 'Iron' , plural: false , img: 'minerals/iron.png' } , silver: { name: 'Silver' , plural: false , img: 'minerals/silver.png' } , gold: { name: 'Gold' , plural: false , img: 'minerals/gold.png' } , marble: { name: 'Marble' , plural: false , img: 'minerals/marble.png' } , drill: { name: 'Mining Drill' , img: 'shop/mining-drill.png' } , superstardustpotion: { name: 'Super Stardust Potion' , img: 'brewing/superstardustpotion.png' } , sandcollector: { name: 'Sand Collector' , img: 'crafting/sandcollector.png' } , titanium: { name: 'Titanium' , plural: false , img: 'minerals/titanium.png' } , promethium: { name: 'Promethium' , plural: false , img: 'minerals/promethium.png' } , sapphire: { name: 'Sapphire' , img: 'minerals/sapphire.png' } , emerald: { name: 'Emerald' , img: 'minerals/emerald.png' } , ruby: { name: 'Ruby' , img: 'minerals/ruby.png' } , diamond: { name: 'Diamond' , img: 'minerals/diamond.png' } , bronzebar: { name: 'Bronze Bar' , img: 'minerals/bronzebar.png' } , ironbar: { name: 'Iron Bar' , img: 'minerals/ironbar.png' } , silverbar: { name: 'Silver Bar' , img: 'minerals/silverbar.png' } , goldbar: { name: 'Gold Bar' , img: 'minerals/goldbar.png' } , bronzenails: { name: 'Bronze Nail' , img: 'crafting/bronzenails.png' } , ironnails: { name: 'Iron Nail' , img: 'crafting/ironnails.png' } , silvernails: { name: 'Silver Nail' , img: 'crafting/silvernails.png' } , goldnails: { name: 'Gold Nail' , img: 'crafting/goldnails.png' } , quartz: { name: 'Quartz' , plural: false , img: 'minerals/quartz.png' } , flint: { name: 'Flint' , plural: false , img: 'minerals/flint.png' } , dottedgreenleafseeds: { name: 'Dotted Green Leaf Seed' , img: 'farming/spotted-green-leaf-seed.png' } , greenleafseeds: { name: 'Green Leaf Seed' , img: 'farming/greenleafseed.png' } , limeleafseeds: { name: 'Lime Leaf Seed' , img: 'farming/limeleafseed.png' } , goldleafseeds: { name: 'Gold Leaf Seed' , img: 'farming/goldleafseed.png' } , blewitmushroomtreeseeds: { name: 'Blewit Mushroom Tree Seed' , img: 'farming/blewitmushroomtreeseeds.png' } , crystalleafseeds: { name: 'Crystal Leaf Seed' , img: 'farming/crystalleafseed.png' } , redmushroom: { name: 'Red Mushroom' , img: 'brewing/redmushroom.png' } , snapegrass: { name: 'Snape Grass' , plural: false , img: 'brewing/snapegrass.png' } , redmushroomseeds: { name: 'Red Mushroom Seed' , img: 'farming/redmushroomseed.png' } , blewitmushroomseeds: { name: 'Snape Grass Seed' , img: 'farming/snapegrassseed.png' } , snapegrassseeds: { name: 'Snape Grass Seed' , img: 'farming/snapegrassseed.png' } , stardustseeds: { name: 'Stardust Seed' , img: 'farming/stardustseed.png' } , ancientfurnace: { name: 'Ancient Furnace' , img: 'crafting/ancientfurnace.gif' } , goldfurnace: { name: 'Gold Furnace' , img: 'crafting/goldfurnace.gif' } , promethiumfurnace: { name: 'Promethium Furnace' , img: 'crafting/promethiumfurnace.gif' } , silverfurnace: { name: 'Silver Furnace' , img: 'crafting/silverfurnace.gif' } , vial: { name: 'Vial of Water' , plural: false , img: 'brewing/vialofwater.png' } , stardustpotion: { name: 'Stardust Potion' , img: 'brewing/stardustpotion.png' } , stardust: { name: 'Stardust' , plural: false , img: 'minerals/stardust.png' } , coins: { name: 'Coin' , img: 'pic_coin_bigstack.png' } , donorcoins: { name: 'Donor Coin' , img: 'donor_coin.png' } , unbounddonorcoins: { name: 'Donor Coin' , img: 'donor_coin.png' } , pumpjack: { name: 'Pumpjack' , img: 'shop/pumpjack.png' } , oilpipe: { name: 'Oil Pipe' , img: 'shop/oil-pipe.png' } , treasurechestkey: { name: 'Treasure Key' , img: 'misc-items/treasureKey.png' } , sapphirekey: { name: 'Sapphire Key' , img: 'misc-items/sapphireKey.png' } , emeraldkey: { name: 'Emerald Key' , img: 'misc-items/emeraldKey.png' } , rubykey: { name: 'Ruby Key' , img: 'misc-items/rubyKey.png' } , dragonkey: { name: 'Dragon Key' , img: 'misc-items/dragonKey.png' } , roadheader: { name: 'Road Header' , img: 'shop/vip/roadheader.png' } , giantdrill: { name: 'Giant Drill' , img: 'shop/vip/giantdrill.png' } , crusher: { name: 'Crusher' , img: 'shop/crusher.gif' } , dottedgreenleaf: { name: 'Dotted Green Leaf' , img: 'brewing/dottedgreenleaf.png' } , oilbarrel: { name: 'Oil Barrel' , img: 'crafting/oilbarrel.png' } , greenleaf: { name: 'Green Leaf' , img: 'brewing/greenleaf.png' } , limeleaf: { name: 'Lime Leaf' , img: 'brewing/limeleaf.png' } , goldleaf: { name: 'Gold Leaf' , img: 'brewing/goldleaf.png' } , crystalleaf: { name: 'Crystal Leaf' , img: 'brewing/crystalleaf.png' } , blewitmushroom: { name: 'Blewit Mushroom' , img: 'brewing/blewitmushroom.png' } , trowel: { name: 'Trowel' , img: 'farming/trowel.png' } , upgradeoilpipe: { name: 'Oil Pipe Upgrade Orb' , img: 'crafting/upgradeoilpipe.png' } , upgradeenchantedhammer: { name: 'Enchanted Hammer Upgrade Orb' , img: 'crafting/upgradeenchantedhammer.png' } , upgradefurnaceorb: { name: 'Furnace Upgrade Orb' , img: 'crafting/upgradefurnaceorb.png' } , upgradeenchantedrake: { name: 'Enchanted Rake Upgrade Orb' , img: 'farming/upgradeenchantedrake.png' } , redmushroomtreeseeds: { name: 'Red Mushroom Tree Seed' , img: 'farming/redmushroomtreeseeds.png' } , stardusttreeseeds: { name: 'Stardust Tree Seed' , img: 'farming/stardusttreeseed.png' } , rocket: { name: 'Rocket' , img: 'crafting/rocket.png' } , promethiumbar: { name: 'Promethium Bar' , img: 'minerals/promethiumbar.png' } , upgradepumpjackorb: { name: 'Blue Pumpjack Upgrade Orb' , img: 'crafting/upgradepumpjackorb.png' } , upgradewrenchorb: { name: 'Wrench Upgrade Orb' , img: 'crafting/upgradewrenchorb.png' } , oilfactory: { name: 'Oil Factory' , img: 'shop/oilfactory.png' } , orboftransformation: { name: 'Orb of Transformation' , plural: 'Orbs of Transformation' , img: 'minerals/orb.png' } , emptyblueorb: { name: 'Empty Blue Orb' , img: 'crafting/anyorb.png' } , emptygreenorb: { name: 'Empty Green Orb' , img: 'crafting/anyorb2.png' } , diamondminers: { name: 'Diamond Pickaxe' , img: 'pickaxes/diamond_pickaxe.png' } , stripedleafseeds: { name: 'Striped Leaf Seed' , img: 'farming/stripedleafseed.png' } , stripedleaf: { name: 'Striped Leaf' , img: 'brewing/stripedleaf.png' } , stripedcrystalleafseeds: { name: 'Striped Crystal Leaf Seed' , img: 'farming/stripedcrystalleafseed.png' } , stripedcrystalleaf: { name: 'Striped Crystal Leaf' , img: 'brewing/stripedcrystalleaf.png' } , bucketwheelexcavator: { name: 'Bucket-wheel Excavator' , img: 'shop/excavators.png' } , brewingkit: { name: 'Brewing Kit' , img: 'brewing/brewingkit.png' } , supercompostpotion: { name: 'Super Compost Potion' , img: 'brewing/supercompostpotion.png' } , megastardustpotion: { name: 'Mega Stardust Potion' , img: 'brewing/megastardustpotion.png' } , robot: { name: 'Robot' , img: 'crafting/robot.png' } , greenpumpjackorb: { name: 'Green Pumpjack Upgrade Orb' , img: 'crafting/greenpumpjackorb.png' } , greenwizardorb: { name: 'Green Wizard Upgrade Orb' , img: 'crafting/greenwizardorb.png' } , redbrewingkitorb: { name: 'Red Brewing Kit Upgrade Orb' , img: 'crafting/redbrewingkitorb.png' } , runite: { name: 'Runite' , img: 'minerals/runite.png' } , runitebar: { name: 'Runite Bar' , img: 'minerals/runitebar.png' } , potato: { name: 'Potato' , plural: 'Potatoes' , img: 'exploring/potato.png' } , wheat: { name: 'Wheat' , plural: false , img: 'exploring/wheat.png' } , strawberry: { name: 'Strawberry' , img: 'exploring/strawberry.png' } , strawberrypie: { name: 'Strawberry Pie' , img: 'exploring/strawberrypie.png' } , greenmushroom: { name: 'Green Mushroom' , img: 'exploring/greenmushroom.png' } , mashedpotatoes: { name: 'Mashed Potatoes' , plural: false , img: 'exploring/mashedpotatoes.png' } , silveroven: { name: 'Silver Oven' , img: 'exploring/silveroven.png' } , goldoven: { name: 'Gold Oven' , img: 'exploring/goldoven.png' } , promethiumoven: { name: 'Promethium Oven' , img: 'exploring/promethiumoven.png' } , runiteoven: { name: 'Runite Oven' , img: 'exploring/runiteoven.png' } , flour: { name: 'Flour' , plural: false , img: 'exploring/flour.png' } , rocketfuelorb: { name: 'Rocket Fuel Orb' , img: 'crafting/rocketfuelorb.png' } , superchestpotion: { name: 'Super Chest Potion' , img: 'brewing/superchestpotion.png' } , chestpotion: { name: 'Chest Potion' , img: 'brewing/chestpotion.png' } , bread: { name: 'Bread' , img: 'exploring/bread.png' } , shrimp: { name: 'Shrimp' , img: 'exploring/shrimp.png' } , sardine: { name: 'Sardine' , img: 'exploring/sardine.png' } , tuna: { name: 'Tuna' , img: 'exploring/tuna.png' } , swordfish: { name: 'Swordfish' , plural: false , img: 'exploring/swordfish.png' } , shark: { name: 'Shark' , img: 'exploring/shark.png' } , lava: { name: 'Lava' , plural: false , img: 'exploring/lava.png' } , explorerspotion: { name: 'Exploring Potion' , img: 'brewing/explorerspotion.png' } , whale: { name: 'Whale' , img: 'exploring/whale.png' } , strangeleaf: { name: 'Strange Leaf' , img: 'exploring/strangeleaf.png' } , fishingpotion: { name: 'Fishing Potion' , img: 'brewing/fishingpotion.png' } , superorboftransformation: { name: 'Super Orb of Transformation' , plural: 'Super Orbs of Transformation' , img: 'minerals/upgradedorb.png' } , moonstone: { name: 'Moonstone' , img: 'minerals/moonstone.png' } , purewaterpotion: { name: 'Pure Water' , plural: false , img: 'exploring/purewater.png' } , amuletofthesea: { name: 'Amulet of the Sea' , plural: 'Amulets of the Sea' , img: 'exploring/equipement/amuletofthesea.png' } , appletreeseeds: { name: 'Apple Tree Seed' , img: 'farming/appletreeseed.png' } , apple: { name: 'Apple' , img: 'exploring/apple.png' } , ironsword: { name: 'Iron Sword' , img: 'exploring/equipement/ironsword.png' } , goldbody: { name: 'Gold Body' , img: 'exploring/equipement/goldbody.png' } , ironbody: { name: 'Iron Body' , img: 'exploring/equipement/ironbody.png' } , runitehelmet: { name: 'Runite Helmet' , img: 'exploring/equipement/runitehelmet.png' } , promethiumbody: { name: 'Promethium Body' , img: 'exploring/equipement/promethiumbody.png' } , rawshrimp: { name: 'Raw Shrimp' , img: 'exploring/rawshrimp.png' } , rawshark: { name: 'Raw Shark' , img: 'exploring/rawshark.png' } , rawbread: { name: 'Raw Bread' , img: 'exploring/rawbread.png' } , frozenhorn: { name: 'Horn' , img: 'exploring/horn.png' } , pumpkinsigil: { name: 'Halloween 2015 Sigil' , img: 'sigils/halloween2015.png' } , treesigil: { name: 'Christmas 2016 Sigil' , img: 'sigils/christmas2016.png' } , santahatsigil: { name: 'Christmas 2015 Sigil' , img: 'sigils/christmas2015.png' } , exploringorb: { name: 'Exploring Upgrade Orb' , img: 'crafting/exploringorb.png' } , whaletooth: { name: 'Whale Tooth' , plural: 'Whale Teeth' , img: 'exploring/whaletooth.png' } , cactuswater: { name: 'Cactus Water' , plural: false , img: 'exploring/cactuswater.png' } , swampwater: { name: 'Swamp Water' , plural: false , img: 'exploring/swampwater.png' } , tnt: { name: 'TNT' , plural: false , img: 'crafting/tnt.png' } , emptyessence: { name: 'Empty Essence' , img: 'magic/emptyessence.png' } , chargedmineralessence: { name: 'Charged Mineral Essence' , img: 'magic/chargedmineralessence.png' } , chargedmetallicessence: { name: 'Charged Metallic Essence' , img: 'magic/chargedmetallicessence.png' } , chargedoilessence: { name: 'Charged Oil Essence' , img: 'magic/chargedoilessence.png' } , chargedenergyessence: { name: 'Charged Energy Essence' , img: 'magic/chargedenergyessence.png' } , chargednatureessence: { name: 'Charged Nature Essence' , img: 'magic/chargednatureessence.png' } , chargedorbessence: { name: 'Charged Orb Essence' , img: 'magic/chargedorbessence.png' } , chargedgemessence: { name: 'Charged Gem Essence' , img: 'magic/chargedgemessence.png' } , magicpage1: { name: '1st Magic Page' , img: 'magic/magicpage1.png' } , magicpage2: { name: '2nd Magic Page' , img: 'magic/magicpage2.png' } , magicpage3: { name: '3rd Magic Page' , img: 'magic/magicpage3.png' } , magicpage4: { name: '4th Magic Page' , img: 'magic/magicpage4.png' } , magicpage5: { name: '5th Magic Page' , img: 'magic/magicpage5.png' } , magicpage6: { name: '6th Magic Page' , img: 'magic/magicpage6.png' } , dottedgreenroots: { name: 'Dotted Green Root' , img: 'farming/dottedgreenroots.png' } , greenroots: { name: 'Green Root' , img: 'farming/greenroots.png' } , limeroots: { name: 'Lime Root' , img: 'farming/limeroots.png' } , goldroots: { name: 'Gold Root' , img: 'farming/goldroots.png' } , stripedgoldroots: { name: 'Striped Gold Root' , img: 'farming/stripedgoldroots.png' } , crystalroots: { name: 'Crystal Root' , img: 'farming/crystalroots.png' } , stripedcrystalroots: { name: 'Striped Crystal Root' , img: 'farming/stripedcrystalroots.png' } , purewaterring: { name: 'Pure Water Ring' , img: 'exploring/equipement/purewaterring.png' } , coinring: { name: 'Coin Ring' , img: 'exploring/equipement/coinring.png' } , lavaring: { name: 'Lava Ring' , img: 'exploring/equipement/lavaring.png' } , promethiumhelmet: { name: 'Promethium Helmet' , img: 'exploring/equipement/promethiumhelmet.png' } , promethiumlegs: { name: 'Promethium Legs' , img: 'exploring/equipement/promethiumlegs.png' } , promethiumsword: { name: 'Promethium Sword' , img: 'exploring/equipement/promethiumsword.png' } , a: { name: 'Runite Helmet' , img: 'exploring/equipement/runitehelmet.png' } , runitebody: { name: 'Runite Body' , img: 'exploring/equipement/runitebody.png' } , runitelegs: { name: 'Runite Legs' , img: 'exploring/equipement/runitelegs.png' } , runitesword: { name: 'Runite Sword' , img: 'exploring/equipement/runitesword.png' } , ancientshield: { name: 'Ancient Shield' , img: 'exploring/equipement/ancientshield.png' } , redpumpjack: { name: 'Red Pumpjack Upgrade' , img: 'crafting/redpumpjack.png' } , essenceseeds: { name: 'Essence Seed' , img: 'farming/essenceseed.png' } , giantbwe: { name: 'Giant Bucket-wheel Excavator' , img: 'crafting/giantbwe.png' } , redfactoryorb: { name: 'Red Factory Upgrade Orb' , img: 'crafting/redfactoryorb.png' } , essencetreeseeds: { name: 'Essence Tree Seed' , img: 'farming/essencetreeseed.png' } , vendorrerollscroll: { name: 'Vendor Reroll Scroll' , img: 'exploring/vendorrerollscroll.png' } , goldstaff: { name: 'Gold Staff' , img: 'magic/goldstaff.png' } , promethiumstaff: { name: 'Promethium Staff' , img: 'magic/promethiumstaff.png' } , runitestaff: { name: 'Runite Staff' , img: 'magic/runitestaff.png' } , goldwand: { name: 'Gold Wand' , img: 'magic/goldwand.png' } , promethiumwand: { name: 'Promethium Wand' , img: 'magic/promethiumwand.png' } , runitewand: { name: 'Runite Wand' , img: 'magic/runitewand.png' } , ancientbar: { name: 'Ancient Bar' , img: 'minerals/ancientbar.png' } , ancientcrystal: { name: 'Ancient Crystal' , img: 'exploring/ancientcrystal.png' } , ancientoven: { name: 'Ancient Oven' , img: 'exploring/ancientoven.png' } , dragonstone: { name: 'Dragonstone' , img: 'minerals/dragonstone.png' } , dragonsword: { name: 'Dragon Sword' , img: 'exploring/equipement/dragonsword.png' } , dragonhelmet: { name: 'Dragon Helmet' , img: 'exploring/equipement/dragonhelmet.png' } , superrobot: { name: 'Super Robot' , img: 'crafting/superrobot.png' } , promethiumwrench: { name: 'Promethium Wrench' , pluarl: 'Promethium Wrenches' , img: 'crafting/promethiumwrench.png' } , dragonchest: { name: 'Dragon Chest' , img: 'misc-items/dragonChest.png' } , dragonaxe: { name: 'Dragon Axe' , img: 'dragonsquest/dragonaxe.png' } , dragonfishingrod: { name: 'Dragon Fishing Rod' , img: 'dragonsquest/dragonfishingrod.png' } , dragonpickaxe: { name: 'Dragon Pickaxe' , img: 'dragonsquest/dragonpickaxe.png' } , dragonpumpjacks: { name: 'Dragon Pumpjack' , img: 'dragonsquest/dragonpumpjacks.png' } , dragonstaff: { name: 'Dragon Staff' , img: 'dragonsquest/dragonstaff.png' } , dragonwand: { name: 'Dragon Wand' , img: 'dragonsquest/dragonwand.png' } , eel: { name: 'Eel' , img: 'exploring/eel.png' } , eastereggsigil: { name: 'Easter 2016 Sigil' , img: 'sigils/easter2016.png' } , rawsardine: { name: 'Raw Sardine' , img: 'exploring/rawsardine.png' } , rawtuna: { name: 'Raw Tuna' , img: 'exploring/rawtuna.png' } , rawswordfish: { name: 'Raw Swordfish' , plural: false , img: 'exploring/rawswordfish.png' } , raweel: { name: 'Raw Eel' , img: 'exploring/raweel.png' } , rawwhale: { name: 'Raw Whale' , img: 'exploring/rawwhale.png' } , rawrainbowfish: { name: 'Raw Rainbow Fish' , img: 'exploring/rawrainbowfish.png' } , tunacooker: { name: 'Tuna Cooker' , img: 'exploring/tunacooker.png' } , swordfishcooker: { name: 'Swordfish Cooker' , img: 'exploring/swordfishcooker.png' } , sharkcooker: { name: 'Shark Cooker' , img: 'exploring/sharkcooker.png' } , whalecooker: { name: 'Whale Cooker' , img: 'exploring/whalecooker.png' } , rainbowfishcooker: { name: 'Rainbow Fish Cooker' , img: 'exploring/rainbowfishcooker.png' } , fishingnet: { name: 'Fishing Net' , img: 'exploring/fishingnet.png' } , mapofthesea: { name: 'Map of the Sea' , plural: 'Maps of the Sea' , img: 'exploring/mapofthesea.png' } , dragonamulet: { name: 'Dragon Amulet' , img: 'exploring/equipement/dragonamulet.png' } , dragonbody: { name: 'Dragon Body' , img: 'exploring/equipement/dragonbody.png' } , treasurechestkey2: { name: 'Ghost Key' , img: 'misc-items/ghostKey.png' } , ghostsigil: { name: 'Halloween 2016 Sigil' , img: 'sigils/halloween2016.png' } , ghostpipe1: { name: '1st Ghost Pipe' , img: 'crafting/ghostpipe1.png' } , ghostpipe2: { name: '2nd Ghost Pipe' , img: 'crafting/ghostpipe2.png' } , ghostpipe3: { name: '3rd Ghost Pipe' , img: 'crafting/ghostpipe3.png' } , ghostpipe4: { name: '4th Ghost Pipe' , img: 'crafting/ghostpipe4.png' } , ghostpipe5: { name: '5th Ghost Pipe' , img: 'crafting/ghostpipe5.png' } , ghostpipe6: { name: '6th Ghost Pipe' , img: 'crafting/ghostpipe6.png' } , ghostpipesheet: { name: 'Ghost Pipe Sheet' , img: 'crafting/ghostpipesheet.png' } , dragonoven: { name: 'Dragon Oven' , img: 'exploring/dragonoven.png' } , dragonfurnace: { name: 'Dragon Furnace' , img: 'crafting/dragonfurnace.gif' } , grouptasktokens: { name: 'Group Task Token' , img: 'icons/grouptasktokens.png' } , arrowhead: { name: 'Arrowhead' , img: 'exploring/arrowhead.png' } , beetlefossil: { name: 'Beetle Fossil' , img: 'exploring/beetleFossil.png' } , goldbranch: { name: 'Gold Branch' , img: 'exploring/goldBranch.png' } , seashell: { name: 'Seashell' , img: 'exploring/seashell.png' } , seaweed: { name: 'Seaweed' , img: 'exploring/seaweed.png' } , sharkfin: { name: 'Shark\'s Fin' , img: 'exploring/sharkfin.png' } , redsand: { name: 'Red Sand' , img: 'exploring/redsand.png' } , swamptar: { name: 'Swamp Tar' , img: 'exploring/swamptar.png' } , seedpotion: { name: 'Seed Potion' , img: 'brewing/seedPotion.png' } , reddirt: { name: 'Red Dirt' , img: 'exploring/redDirt.png' } , carvedtreebark: { name: 'Carved Tree Bark' , img: 'exploring/carvedTreeBark.png' } }; function createTemplateWrapper(str) { const tmp = document.createElement('templateWrapper'); tmp.innerHTML = str; return tmp; } function formatNumber(num) { // return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); return parseFloat(num).toLocaleString('en'); } function formatNumbersInText(text) { return text.replace(/\d(?:[\d',\.]*\d)?/g, (numStr) => { return formatNumber(parseInt(numStr.replace(/\D/g, ''), 10)); }); } function imgSrc2Info(str) { const match = str.match(/(?:^|")images\/(.+?([^\/]+)\.(?:png|gif|jpe?g))(?:"|$)/); if (match) { const keyFromImg = match[2].toLowerCase(); if (itemInfo.hasOwnProperty(keyFromImg)) { return itemInfo[keyFromImg]; } const imgLowerCase = match[1].toLowerCase(); for (let key in itemInfo) { if (itemInfo[key].img == imgLowerCase) { return itemInfo[key]; } } console.warn('unknown image key:', str, match); return { name: match[2].replace(/-|_/g, ' ') .replace(/([a-z])([A-Z])/g, (wholeMatch, m1, m2) => { return m1 + ' ' + m2.toLowerCase(); }) , img: match[1].toLowerCase() }; } return {}; } function imgSrc2Name(str) { return imgSrc2Info(str).name || null; } function imgSrc2NamePlural(str, num) { const info = imgSrc2Info(str); if (!info.hasOwnProperty('name')) { return null; } if (num == 1 || info.plural === false) { return info.name; } if (!info.hasOwnProperty('plural')) { return info.name.replace(/([^aeiou])y$/, '$1ie') + 's'; } if (typeof info.plural === 'function') { return info.plural(num); } return info.plural; } /** * settings */ function getSettingName(key) { return 'setting.' + key; } const observedSettings = new Map(); function observeSetting(key, fn) { if (!observedSettings.has(key)) { observedSettings.set(key, new Set()); } observedSettings.get(key).add(fn); } function unobserveSetting(key, fn) { if (!observedKeys.has(key)) { return false; } return observedKeys.get(key).delete(fn); } function getSetting(key) { if (!settings.hasOwnProperty(key)) { return; } const name = getSettingName(key); return localStorage.hasOwnProperty(name) ? JSON.parse(localStorage.getItem(name)) : settings[key].defaultValue; } function setSetting(key, newValue) { if (!settings.hasOwnProperty(key)) { return; } const oldValue = getSetting(key); localStorage.setItem(getSettingName(key), JSON.stringify(newValue)); if (oldValue !== newValue) { (observedSettings.get(key) || []).forEach(fn => fn(key, oldValue, newValue)); } } function initSettings() { if (!localStorage.hasOwnProperty('setSoundToggleDefault')) { const defaultSound = 'off'; localStorage.setItem('soundToggle', defaultSound); localStorage.setItem('setSoundToggleDefault', true); document.getElementById('sound-toggle').innerHTML = defaultSound; } const settingStyle = document.createElement('style'); settingStyle.innerHTML = ` #settings-tab td.setting { color: pink; } #settings-tab td.setting label { cursor: pointer; } #settings-tab td.setting label:hover { color: red; } #settings-tab td.setting.reload::after { color: orange; content: '*'; float: right; margin: 0 3px; } `; document.head.appendChild(settingStyle); 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 "DH1 Fixed"<br> <span style="font-size: 0.9rem;">(* changes require reloading the tab)</span> </th>`; for (let key in settings) { const row = table.insertRow(-1); row.innerHTML = `<td class="setting ${settings[key].requiresReload ? 'reload' : ''}"> <input type="checkbox" id="userscript-${key}" ${getSetting(key) ? 'checked="checked"' : ''}> <label for="userscript-${key}"> ${settings[key].title} </label> </td>`; const checkbox = document.getElementById('userscript-' + key); checkbox.addEventListener('change', () => { setSetting(key, checkbox.checked); }); } 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 */ const oilKeyItems = { 'handheldOilPump': { oilPerSecond: () => 1 * parseInt(window.miners, 10) , observeList: [ 'miners' ] } , 'bindedOilPipe': { oilPerSecond: () => [100, 200, 300][window.bindedUpgradeOilPipe] , observeList: [ 'bindedUpgradeOilPipe' ] } , 'bindedPumpJack': { oilPerSecond: () => { const pumpjackProduction = 30 + (window.bindedRedPumpJack > 0 ? 15 : 0) + (window.bindedDragonPumpjacks > 0 ? 15 : 0); return pumpjackProduction * parseInt(window.bindedPumpJack, 10); } , observeList: [ 'bindedRedPumpJack' , 'bindedDragonPumpjacks' ] } , 'bindedOilFactory': { oilPerSecond: () => 2 * parseInt(window.oilFactoryWorkers, 10) , observeList: [ 'oilFactoryWorkers' ] } , 'bindedOilRefinery': { oilPerSecond: () => Math.min(5e-6 * parseInt(window.oil, 10), 500) , observeList: [ 'oil' ] } , 'bindedGhostPipeSheet': { oilPerSecond: () => { let ghostPipes = 0; for (let i = 1; i <= 6; i++) { if (window['bindedGhostPipe' + i] > 0) { ghostPipes++; } } return ghostPipes == 6 ? 200 * 6 : 100 * ghostPipes; } , observeList: [ 'bindedGhostPipe1' , 'bindedGhostPipe2' , 'bindedGhostPipe3' , 'bindedGhostPipe4' , 'bindedGhostPipe5' , 'bindedGhostPipe6' ] } }; 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); // add display for oil per second const oilStyle = document.createElement('style'); oilStyle.innerHTML = ` .oil-production-wrapper { color: black; display: block; font-size: 14px; } .oil-production-wrapper::before { content: '+'; } .oil-production-wrapper::after { content: '/s'; } #key-item-bindedOilRefinery-box > .text-wrapper, #key-item-bindedGhostPipeSheet-box > .text-wrapper { display: none; } `; document.head.appendChild(oilStyle); function updateOilProduction(key, el) { if (window[key] > 0) { const oilProd = Math.floor(oilKeyItems[key].oilPerSecond() * 10) / 10; el.textContent = formatNumber(oilProd); } } const oilImages = document.querySelectorAll('.item-box-title img[src="images/oil.png"]'); for (let i = 0; i < oilImages.length; i++) { const img = oilImages[i]; const boxTitle = img.parentElement; const key = boxTitle.parentElement.id.replace(/^key-item-(.+)-box$/, '$1'); if (oilKeyItems.hasOwnProperty(key)) { const info = oilKeyItems[key]; const oilWrapper = document.createElement('span'); oilWrapper.className = 'oil-production-wrapper'; const oilProduction = document.createElement('span'); oilProduction.className = 'oil-production'; oilWrapper.appendChild(oilProduction); boxTitle.insertBefore(oilWrapper, img); oilWrapper.appendChild(img); updateOilProduction(key, oilProduction); info.observeList.unshift(key); observe(info.observeList, () => updateOilProduction(key, oilProduction)); } } const oldOpenBindedOilFactoryDialogue = window.openBindedOilFactoryDialogue; window.openBindedOilFactoryDialogue = () => { const maxWorkers = window.bindedRedFactoryOrb > 0 ? 300 : 100; window.miscMultipleInput( 'How many factory workers do you wish to hire?<br>You can hire up to ' + maxWorkers + '.<br><br>' + 'Costs: 1<img src="images/pic_coin2.png" width="20px" height="20px" style="vertical-align: middle"> per worker' , 'oilFactoryWorkers' , '0' , 'MISC_MULTIPLE=' ); } } /** * 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) { if (key.startsWith('mega')) { const title = { 'megaDottedGreenLeafSeeds': 'Mega Dotted Green Leaf Seed (Stops dying at level 85)' , 'megaGreenLeafSeeds': 'Mega Green Leaf Seed (Stops dying at level 95)' , 'megaLimeLeafSeeds': 'Mega Lime Leaf Seed (Stops dying at level 95)' }[key]; if (title) { btn.title = title; } } else { btn.title = btn.title.replace('dieing', 'dying'); } btnParent.insertBefore(btn, btnEl); btnParent.insertBefore(document.createTextNode(' '), btnEl); btnEl = btn; } } const oldSelectSeedForPlanter = window.selectSeedForPlanter; window.selectSeedForPlanter = (seedChosen) => { oldSelectSeedForPlanter(seedChosen); localStorage.setItem('farming.plantingSeed', seedChosen); } const seed = localStorage.getItem('farming.plantingSeed'); if (window.bindedPlanter >= 1 && seed != null) { window.selectSeedForPlanter(seed); } } /** * 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); valueTextNode.textContent = ' ' + formatNumbersInText(valueTextNode.textContent.trim()); } 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 imageSrc2BindedMachineVar(src) { return { 'wooden_slave': 'miners' , 'rocket': 'bindedRocket' , 'mining-drill': 'bindedDrill' , 'crusher': 'bindedCrusher' , 'giantDrill': 'bindedGiantDrill' , 'roadHeader': 'bindedRoadHeader' , 'excavators': 'bindedBucketWheelExcavator' , 'diamond_pickaxe': 'bindedDiamondMiners' , 'giantBWE': 'bindedGiantBWE' }[src.replace(/^(?:.*\/)?([^\/]+)\.[^\.\/]+$/, '$1')]; } const redColor = 'hsla(0, 100%, 75%, 1)'; const lightRedColor = 'hsla(0, 100%, 90%, 1)'; 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 highEnough = level <= miningLevel; const machineImg = row.cells[3].querySelector('img'); const machineVar = imageSrc2BindedMachineVar(machineImg.src); const hasMachine = window[machineVar] > 0; const fulfilled = highEnough && hasMachine; row.cells[2].style.color = highEnough ? '' : 'red'; machineImg.style.border = hasMachine ? '' : '2px solid red'; row.cells[2].style.backgroundColor = fulfilled ? '' : lightRedColor; row.cells[3].style.backgroundColor = fulfilled ? '' : lightRedColor; row.style.backgroundColor = fulfilled ? '' : redColor; } } 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 filterMarket(category, text) { const tableAlone = document.getElementById('market-buy-table'); const itemRows = tableAlone.rows; const dataBox = document.getElementById('market-data-box'); for (let i = 1; i < itemRows.length; i++) { const row = itemRows[i]; const itemType = row.getAttribute('item-type'); const showCategory = category == 'all' || category == itemType; const itemTitle = row.title.toLowerCase(); const showText = itemTitle.includes(text.toLowerCase()); row.style.display = (showCategory && showText) ? '' : 'none'; } dataBox.style.display = 'none'; if (category == 'data') { document.getElementById('globals-taxes').textContent = formatNumber(window.globalTaxes); dataBox.style.display = 'inline-block'; } } const itemCategories = { minerals: { title: 'Minerals' , items: [ 'stone' , 'copper' , 'tin' , 'iron' , 'silver' , 'gold' , 'quartz' , 'flint' , 'marble' , 'titanium' , 'moonStone' , 'promethium' , 'runite' , 'sapphire' , 'emerald' , 'ruby' , 'diamond' , 'dragonPickaxe' ] } , bindables: { title: 'Crafting/Machinery + bars' , items: [ 'oil' , 'oilBarrel' , 'oilPipe' , 'pumpJack' , 'redPumpJack' , 'dragonPumpjacks' , 'oilFactory' , 'ghostPipeSheet' , 'ghostPipe1' , 'ghostPipe2' , 'ghostPipe3' , 'ghostPipe4' , 'ghostPipe5' , 'ghostPipe6' , 'trowel' , 'brewingKit' , 'silverFurnace' , 'goldFurnace' , 'ancientFurnace' , 'promethiumFurnace' , 'dragonFurnace' , 'promethiumWrench' , 'drill' , 'crusher' , 'giantDrill' , 'roadHeader' , 'bucketWheelExcavator' , 'sandCollector' , 'rocket' , 'robot' , 'bronzeBar' , 'ironBar' , 'silverBar' , 'goldBar' , 'promethiumBar' , 'runiteBar' ] } , seeds: { title: 'Seeds' , items: [ 'redMushroomSeeds' , 'dottedGreenLeafSeeds' , 'greenLeafSeeds' , 'redMushroomTreeSeeds' , 'blewitMushroomSeeds' , 'limeLeafSeeds' , 'blewitMushroomTreeSeeds' , 'snapeGrassSeeds' , 'starDustSeeds' , 'appleTreeSeeds' , 'goldLeafSeeds' , 'starDustTreeSeeds' , 'stripedLeafSeeds' , 'essenceSeeds' , 'crystalLeafSeeds' , 'essenceTreeSeeds' , 'stripedCrystalLeafSeeds' ] } , brewing: { title: 'Leafs + Brewing' , items: [ 'dottedGreenLeaf' , 'greenLeaf' , 'limeLeaf' , 'goldLeaf' , 'stripedLeaf' , 'crystalLeaf' , 'stripedCrystalLeaf' , 'redMushroom' , 'blewitMushroom' , 'greenMushroom' , 'snapeGrass' , 'strangeLeaf' , 'whaleTooth' , 'vial' , 'pureWaterPotion' , 'cactusWater' , 'swampWater' , 'starDustPotion' , 'superStarDustPotion' , 'megaStarDustPotion' , 'superCompostPotion' , 'explorersPotion' , 'chestPotion' , 'superChestPotion' ] } , exploring: { title: 'Exploring' , items: [ 'silverOven' , 'goldOven' , 'promethiumOven' , 'runiteOven' , 'ancientOven' , 'dragonOven' , 'potato' , 'strawberry' , 'wheat' , 'apple' , 'strawberryPie' , 'rawShrimp' , 'shrimp' , 'rawSardine' , 'sardine' , 'rawTuna' , 'tuna' , 'tunaCooker' , 'rawSwordfish' , 'swordfish' , 'swordfishCooker' , 'rawShark' , 'shark' , 'sharkCooker' , 'rawWhale' , 'whale' , 'whaleCooker' , 'rawEel' , 'eel' , 'rawRainbowFish' , 'rainbowFishCooker' , 'dragonFishingRod' , 'fishingNet' ] } , equipement: { title: 'Equipement' , items: [ 'promethiumHelmet' , 'runiteHelmet' , 'dragonHelmet' , 'promethiumBody' , 'runiteBody' , 'dragonBody' , 'promethiumLegs' , 'runiteLegs' , 'promethiumSword' , 'runiteSword' , 'dragonSword' , 'ancientShield' , 'amuletOfTheSea' , 'dragonAmulet' , 'coinRing' , 'lavaRing' , 'pureWaterRing' ] } , magic: { title: 'Magic' , items: [ 'goldStaff' , 'promethiumStaff' , 'runiteStaff' , 'dragonStaff' , 'goldWand' , 'promethiumWand' , 'runiteWand' , 'dragonWand' , 'emptyEssence' , 'chargedMineralEssence' , 'chargedMetallicEssence' , 'chargedOilEssence' , 'chargedEnergyEssence' , 'chargedNatureEssence' , 'chargedOrbEssence' , 'chargedGemEssence' , 'dottedGreenRoots' , 'greenRoots' , 'limeRoots' , 'goldRoots' , 'stripedGoldRoots' , 'crystalRoots' , 'stripedCrystalRoots' ] } , orbs: { title: 'Orbs' , items: [ 'orbOfTransformation' , 'superOrbOfTransformation' , 'upgradeEnchantedRake' , 'upgradeWrenchOrb' , 'upgradeOilPipe' , 'exploringOrb' , 'upgradeFurnaceOrb' , 'upgradePumpJackOrb' , 'upgradeEnchantedHammer' , 'greenPumpjackOrb' , 'greenWizardOrb' , 'rocketFuelOrb' , 'redBrewingKitOrb' , 'redFactoryOrb' ] } , misc: { title: 'Misc' , items: [ 'starDust' , 'unboundDonorCoins' , 'pumpkinSigil' , 'santaHatSigil' , 'easterEggSigil' , 'ghostSigil' , 'treeSigil' , 'lava' , 'sapphireKey' , 'emeraldKey' , 'rubyKey' , 'treasureChestKey' , 'dragonKey' , 'treasureChestKey2' , 'tnt' , 'vendorRerollScroll' , 'ancientCrystal' , 'dragonAxe' ] } }; function fixMarket() { // 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 oldLoadTradableTable = window.loadTradableTable; window.loadTradableTable = () => { const tradableTable = document.getElementById('selling-tradable-table'); while (tradableTable.childNodes.length > 0) { tradableTable.removeChild(tradableTable.firstChild); } window.platinumTradables = []; const itemList = window.tradableItems; const itemPrefix = 'tradable-item-'; for (let i = 0; i < itemList.length; i++) { const item = itemList[i]; const tradableData = item.split('~'); const itemVarName = tradableData[0]; const lowerLimit = tradableData[1]; const upperLimit = tradableData[2]; const isPlatinum = tradableData[3]; if (document.getElementById(itemPrefix + itemVarName) != null) { continue; } const isPlat = parseInt(isPlatinum, 10) == 1; if (isPlat) { window.platinumTradables.push(itemVarName); } const inputEl = document.createElement('input'); inputEl.type = 'image'; inputEl.title = itemVarName; inputEl.src = window.getImagePath(itemVarName); inputEl.id = itemPrefix + itemVarName; inputEl.addEventListener('click', () => { window.setItemNameToTradeInSlot(itemVarName, lowerLimit + '-' + upperLimit, (isPlat ? '1' : '0')); }); inputEl.addEventListener('contextmenu', () => { window.setItemNameToTradeInSlotLimits(itemVarName, lowerLimit + '-' + upperLimit, (isPlat ? '1' : '0')); }); tradableTable.appendChild(inputEl); } // add categories for market items const tmp = document.createElement('div'); tradableTable.insertBefore(tmp, tradableTable.firstChild); for (let key in itemCategories) { const category = itemCategories[key]; const h3 = document.createElement('h3'); h3.textContent = category.title; tradableTable.insertBefore(h3, tmp); for (let item of category.items) { const el = document.getElementById('tradable-item-' + item); if (el) { tradableTable.insertBefore(el, tmp); } } } tradableTable.removeChild(tmp); }; if (window.hasOwnProperty('tradableItems')) { window.loadTradableTable(); } // add style for category tabs const style = document.createElement('style'); style.innerHTML = ` #selling-tradable-table h3 { margin-bottom: .25rem; margin-top: .75rem; } #selling-tradable-table input[type="image"] { margin-right: .5rem; height: 50px; width: 50px; } #selling-tradable-table #tradable-item-trowel { height: 16.7px; width: 50px; } #selling-tradable-table #tradable-item-orbOfTransformation, #selling-tradable-table #tradable-item-superOrbOfTransformation { margin-left: -12.5px; margin-right: calc(.5rem - 12.5px); width: 65px; } #selling-tradable-table #tradable-item-upgradeEnchantedHammer { margin-left: -4px; margin-right: calc(.5rem - 4px); width: 58px; } #td-filter-market.selected { background: -webkit-linear-gradient(#800000, #390000); background: -o-linear-gradient(#800000, #390000); background: -moz-linear-gradient(#800000, #390000); background: linear-gradient(#800000, #390000); } `; document.head.appendChild(style); let lastFilterText = ''; let lastFilterCategory = 'all'; window.filterBuyables = (text) => { lastFilterText = text; filterMarket(lastFilterCategory, lastFilterText); }; window.setFilterTable = (itemFilter) => { const row = document.querySelector('.market-filter-tbl-button'); const oldBtn = row.querySelector('td.selected'); if (oldBtn) { oldBtn.classList.remove('selected'); } const filterBtn = row.querySelector(`td[onclick^="setFilterTable('${itemFilter}')"]`); if (filterBtn) { filterBtn.classList.add('selected'); } lastFilterCategory = window.itemFilterGlobal = itemFilter; }; window.filterTable = () => { filterMarket(lastFilterCategory, lastFilterText); }; const oldApplyToBuyingTable = window.applyToBuyingTable; window.applyToBuyingTable = (...args) => { const ret = oldApplyToBuyingTable(...args); filterMarket(lastFilterCategory, lastFilterText); return ret; }; window.setFilterTable(lastFilterCategory); // add "clear search"-button const searchInput = document.querySelector('input[onkeyup^="filterBuyables"]'); searchInput.id = 'market-search'; const tmpWrapper = createTemplateWrapper(`<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() { for (var i = 1; i < maxLevelVirtual; i++) { levelXp[i-1] = calcLevelXp(i); } const oldFns = { getLevel: window.getLevel , getVirtualLevel: window.getVirtualLevel , getGlobalLevel: window.getGlobalLevel }; const newFns = { getLevel: getLevel , getVirtualLevel: getVirtualLevel , getGlobalLevel: getGlobalLevel }; function switch2FastLevelCalculation() { const fns = getSetting('useFastLevelCalculation') ? newFns : oldFns; window.getLevel = fns.getLevel; window.getVirtualLevel = fns.getVirtualLevel; window.getGlobalLevel = fns.getGlobalLevel; } switch2FastLevelCalculation(); observeSetting('useFastLevelCalculation', () => switch2FastLevelCalculation()); } /** * fix inventory */ function fixInventory() { 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 }); } const smeltingBarRequirements = { glass: { oil: 12 , ores: ['sand'] } , bronze: { oil: 1 , ores: ['copper', 'tin'] } , iron: { oil: 50 , ores: ['iron'] } , silver: { oil: 150 , ores: ['silver'] } , gold: { oil: 500 , ores: ['gold'] } , promethium: { oil: 10e3 , ores: ['promethium'] } }; function fixMachinery() { const oldSetSmeltingBarAgain = window.setSmeltingBarAgain; let smeltingValue = null; window.setSmeltingBarAgain = (barType, amountElement) => { // update max amount of ore const requirements = smeltingBarRequirements[barType] || { oil: 1, ores: [] }; const value = parseInt(amountElement.value, 10); const furnaceMax = window.getFurnaceCapacityAgain(window.bindedFurnaceLevel); const maxOil = parseInt(window.oil, 10) / requirements.oil; const maxResource = requirements.ores .map((name) => parseInt(window[name], 10)) .reduce((p, c) => Math.min(p, c), Number.MAX_SAFE_INTEGER) ; const max = Math.min(furnaceMax, maxOil, maxResource); amountElement.max = max; if (max < value) { smeltingValue = value; amountElement.value = max; } else if (smeltingValue != null) { amountElement.value = smeltingValue; } oldSetSmeltingBarAgain(barType, amountElement); localStorage.setItem('smelting.bar', barType); localStorage.setItem('smelting.amount', window.amountToSmeltGlobal); }; if (localStorage.getItem('smelting.bar') != null) { window.barTypeSelectedToSmeltGlobal = localStorage.getItem('smelting.bar'); } if (localStorage.getItem('smelting.amount') != null) { window.amountToSmeltGlobal = localStorage.getItem('smelting.amount'); } const oldChangeSmeltingValue = window.changeSmeltingValue; window.changeSmeltingValue = () => { smeltingValue = null; window.setSmeltingBarAgain( window.barTypeSelectedToSmeltGlobal , document.getElementById('smeltingAmountRequested') ); }; const oldOpenFurnaceDialogue = window.openFurnaceDialogue; window.openFurnaceDialogue = () => { const ret = oldOpenFurnaceDialogue(); if (furnacePerc == 0) { const amountInput = document.getElementById('smeltingAmountRequested'); if (amountInput.type != 'number') { amountInput.type = 'number'; amountInput.style.width = '69px'; amountInput.min = '0'; amountInput.addEventListener('mouseup', (event) => window.changeSmeltingValue()); } amountInput.max = window.getFurnaceCapacityAgain(window.bindedFurnaceLevel); window.changeSmeltingValue(); } return ret; }; const oldRapairMachinery = window.rapairMachinery; window.rapairMachinery = () => { oldRapairMachinery(); document.getElementById('perc-all-cost').innerHTML = formatNumber(window.getRepairCost('all', 0)); }; 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 } , 'miningPotion': { level: 20 , limeLeaf: 5 , dottedGreenLeaf: 20 , blewitMushroom: 50 } }; 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; // fix alignment of brewing items const style = document.createElement('style'); style.innerHTML = ` #brewing-tab center > .item-box-spot { text-align: left; } `; document.head.appendChild(style); 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'); 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>'; const tmpEl = createTemplateWrapper(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'] , diamondMiners: ['diamondMiners', 'bindedDiamondMiners'] , robot: ['robot', 'bindedRobot'] , oilRefinery: ['oilRefinery', 'bindedOilRefinery'] , superRobot: ['superRobot', 'bindedSuperRobot'] , superTNT: ['superTNT', 'dragonFlagBlewUpWall'] // , fishingRod: ['bronzeRod', 'ironRod', 'goldRod', 'promethiumRod', 'fishingRod', 'dragonFishingRod', 'bindedDragonFishingRod'] , fishingRod: ['fishingRod', 'dragonFishingRod', 'bindedDragonFishingRod'] , fishingBoat: ['fishingBoat', 'bindedFishingBoat'] , largeFishingBoat: ['largeFishingBoat', 'bindedLargeFishingBoat'] }; function hideCraftingRecipes() { (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 = getSetting('hideSomeCraftRecipes') && i <= maxFurnaceLevel; row.style.display = hide ? 'none' : ''; keys2Observe.push(varName); } } if (init) { observe(keys2Observe, () => hideFurnaceRecipes(false)); observeSetting('hideSomeCraftRecipes', () => hideFurnaceRecipes(false)); } })(true); function hideRecipe(key, nameList, init = false) { const hide = getSetting('hideSomeCraftRecipes') && nameList.some(name => window[name] != 0); document.getElementById('craft-' + key).style.display = hide ? 'none' : ''; if (init) { observe(nameList, () => hideRecipe(key, nameList, false)); observeSetting('hideSomeCraftRecipes', () => 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 = getSetting('hideSomeCraftRecipes') && maxOvenLevel >= i; row.style.display = hide ? 'none' : ''; keys2Observe.push(ovenName, bindedOvenName); } } if (init) { observe(keys2Observe, () => hideOvenRecipes(false)); observeSetting('hideSomeCraftRecipes', () => 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) { const hide = getSetting('hideSomeCraftRecipes') && highestLevel >= i; row.style.display = hide ? '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)); } observeSetting('hideSomeCraftRecipes', () => 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 = getSetting('hideSomeCraftRecipes') && maxWandLevel >= i; wandRow.style.display = hide ? 'none' : ''; keys2Observe.push(wandName, bindedWandName); } } if (init) { observe(keys2Observe, () => hideWandRecipe(false)); observeSetting('hideSomeCraftRecipes', () => 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 = getSetting('hideSomeCraftRecipes') && maxStaffLevel >= i; staffRow.style.display = hide ? 'none' : ''; keys2Observe.push(staffName, bindedStaffName); } } if (init) { observe(keys2Observe, () => hideStaffRecipe(false)); observeSetting('hideSomeCraftRecipes', () => hideStaffRecipe(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'); if (el) { const hide = getSetting('hideEquipment') && i < 4 && i < currentLevel; el.parentNode.style.display = hide ? 'none' : ''; } } if (init) { observe(key + 'SlotId', () => examineEquipmentRecipes(key, type, false)); observeSetting('hideEquipment', () => 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); for (let key in equipmentTypes) { examineEquipmentRecipes(key, equipmentTypes[key], true); } } /** * improve dialog buttons */ function improveDialogBtns() { function isOnlyMessageBox(yesButtonVal) { return getSetting('improveDialogBtns') && (yesButtonVal == null || yesButtonVal == ''); } const oldOpenDialogue = window.openDialogue; window.openDialogue = (title, message, yesButtonVal) => { const [okBtn, cancelBtn] = document.querySelectorAll('#dialog #buttonCommandYes ~ input[type="button"]'); // restore default state const empty = isOnlyMessageBox(yesButtonVal); okBtn.style.display = empty ? 'none' : ''; okBtn.value = 'OK'; cancelBtn.value = empty ? 'Close' : 'Cancel'; if (getSetting('improveDialogBtns')) { 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'; } else if (/^OPEN_LOOT=/.test(yesButtonVal)) { okBtn.value = 'Open'; } } 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 = isOnlyMessageBox(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 (getSetting('improveDialogBtns') && varname == 'key-item-bindedRocket-box' && window.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 (getSetting('improveDialogBtns') && window.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 (getSetting('improveDialogBtns') && window.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, div[id^="miningEngineer-"][id$="-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"], div[id^="miningEngineer-"][id$="-tab"] span.shop-box-ach span[id^="perk"], #magicBookPages, #item-treasureMap-box > span:last-child, #item-treasureMap2-box > span:last-child, #item-ghostSpawned1-box > span:last-child { 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; } #fishingRodAmount { display: none; } #hasMapOfTheSea-fishermen { position: absolute; bottom: 3px; left: calc(50% - 10px); } 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; } body.hide-zero-price span[class^="inventory-item-box"] span[id$="-price"]:empty, body.hide-zero-price #sandstone-price, body.hide-zero-price #moonStone-price, body.hide-zero-price #glass-price, body.hide-zero-price #promethiumBar-price, body.hide-zero-price #runiteBar-price, body.hide-zero-price #ancientBar-price, body.hide-zero-price #lava-price, body.hide-zero-price #brewingKitBinded-price, body.hide-zero-price #stripedLeaf-price, body.hide-zero-price #stripedCrystalLeaf-price, body.hide-zero-price #greenMushroom-price, body.hide-zero-price #whaleTooth-price, body.hide-zero-price #snapeGrass-price, body.hide-zero-price #strangeLeaf-price, body.hide-zero-price #pureWaterPotion-price, body.hide-zero-price #cactusWater-price, body.hide-zero-price #swampWater-price, body.hide-zero-price #ghostEssence-price, body.hide-zero-price #ghostRemains-price, body.hide-zero-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"]:not(.inventory-item-box-smaller) 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, div[id^="miningEngineer-"][id$="-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; } img[src^="images/perks/"][height="80px"] { top: 45px; } img[src^="images/perks/"][width="80px"] { left: 36px; } span.shop-box-ach span[id^="perk"] > img[src="images/spinning-gear-off.gif"] { background-color: white; position: absolute; left: 3px; } span.shop-box-ach span[id^="perk"] > img[src^="images/division/"] { position: absolute; right: 3px; } `; 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' + ', div[id^="miningEngineer-"][id$="-tab"] span.shop-box-ach br' ); let i = 0; while (brs[i] != null) { if (!brs[i].parentNode) { i++; continue; } 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]; if (box.id && box.id.startsWith('shop-enchanted')) { const boxTitle = box.querySelector('.box-title'); boxTitle.firstChild.textContent += ' '; } 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--; } } } } // add wrapper elements for the perk-levels in mining engineer tab const perks = document.querySelectorAll('div[id^="miningEngineer-"][id$="-tab"] span.shop-box-ach'); for (let i = 0; i < perks.length; i++) { const perk = perks[i]; const childNodes = perk.childNodes; let foundImg = false; let wrapperInserted = false; let wrapper = document.createElement('span'); wrapper.id = perk.getAttribute('onclick') .replace(/send\('([^']+)'\)/, '$1') .replace(/[=~]/g, '-') .toLowerCase() ; for (let j = 0; j < childNodes.length; j++) { const child = childNodes[j]; if (!foundImg && child.tagName == 'IMG') { foundImg = true; } else if (foundImg) { if (!wrapperInserted) { perk.insertBefore(wrapper, child); j++; wrapperInserted = true; } wrapper.appendChild(child); j--; } } } // fix tooltip const perkEl = document.querySelector(`span.activate-tooltip[tooltip="Giants drills mine 40% more quartz."]`); perkEl.setAttribute('tooltip', 'Giants drills mine 40% more iron.'); function setVisibilityOfUnnecessaryPrices() { const hide = getSetting('hideUnnecessaryPrice'); document.body.classList[hide ? 'add' : 'remove']('hide-zero-price'); } setVisibilityOfUnnecessaryPrices(); observeSetting('hideUnnecessaryPrice', () => setVisibilityOfUnnecessaryPrices()); } /** * 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: 1; } .tooltip { 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; } span.text-wrapper .small-perc-bar-inner[style*="background-color: yellow;"] { background-color: rgba(255, 255, 0, 1) !important; } span.text-wrapper .small-perc-bar-inner[style*="background-color: red;"] { background-color: rgba(255, 0, 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 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 = getSetting('hideMaxRecipes') && amount >= max(); row.style.display = hide ? 'none' : ''; if (init) { observe(key, () => hideMachineRecipe(key, max, false)); observe(bindedKey, () => hideMachineRecipe(key, max, false)); observeSetting('hideMaxRecipes', () => hideMachineRecipe(key, max, false)); } } } function defaultMaxFn() { return 10; } function calcPumpjackMax() { let maxPumpjacks = 10; if (window.bindedUpgradePumpJackOrb == 1) { maxPumpjacks += 5; } if (window.bindedGreenPumpjackOrb == 1) { maxPumpjacks += 10; } return maxPumpjacks; } function hideMaxRecipes() { const machinery = ['drill', 'crusher', 'giantDrill', 'sandCollector', 'roadHeader', 'bucketWheelExcavator', 'giantBWE']; for (let key of machinery) { hideMachineRecipe(key, defaultMaxFn, true); } // handle pump jacks with its upgrades 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); } // thanks /u/Vomera for suggesting this 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); // add wrapper for collected number of magic book pages const magicBookBox = document.getElementById('item-magicBook-box'); const magicBookChildren = magicBookBox.childNodes; const magicPagesWrapper = document.createElement('span'); magicPagesWrapper.id = 'magicBookPages'; let foundImg = false; for (let i = 0; i < magicBookChildren.length; i++) { const child = magicBookChildren[i]; if (!foundImg && child.tagName == 'IMG') { foundImg = true; } else if (foundImg) { magicPagesWrapper.appendChild(child); i--; } } magicBookBox.appendChild(magicPagesWrapper); // improve tooltip of spell book const magicBook = magicBookBox.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 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); }; let startingText = new Map(); function updateEnergy() { const exploringEls = document.querySelectorAll( '.inventory-item-box-exploring' + ', .inventory-item-box-exploring-artifact' ); for (let i = 0; i < exploringEls.length; i++) { const el = exploringEls[i]; const firstChild = el.firstChild; if (firstChild.nodeType != Node.TEXT_NODE) { continue; } const id = el.id.replace(/^item-(.+)-box$/, '$1'); if (!startingText.has(id)) { startingText.set(id, firstChild.textContent); } let text = startingText.get(id); if (['shrimp', 'sardine', 'tuna', 'swordfish', 'eel', 'shark', 'whale', 'rainbowFish'].includes(id) && /\+\d(?:[\d',\.]*\d[kK]?)?\s*E(?:nergy)?/.test(text)) { // TODO: is amuletSlotId == 2 for enchantedAmuletOfTheSea? const mult = window.amuletSlotId == 1 ? 1.1 : window.amuletSlotId == 2 ? 1.15 : 1; text = text.replace(/\d(?:[\d',\.]*\d)?/, (numStr) => { return Math.floor(parseInt(numStr.replace(/\D/g, ''), 10) * mult); }); } firstChild.textContent = formatNumbersInText(text); } } updateEnergy(); observe('amuletSlotId', () => updateEnergy()); // fix energy format in cooking table const cookingTable = document.querySelector('#cooking-tab table.table-stats'); const cookingRows = cookingTable.rows; for (let i = 0; i < cookingRows.length; i++) { const row = cookingRows[i]; const descriptionCell = row.cells[row.cells.length - 2]; descriptionCell.textContent = formatNumbersInText(descriptionCell.textContent); } // 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; xpNode.textContent = formatNumbersInText(xpNode.textContent); } // 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); }; // fix xp-numbers in crafting tables function fixNumbersInCraftingTables(tabName) { const table = document.querySelector('#' + tabName + '-tab table.table-stats'); const rows = table.rows; for (let i = 0; i < rows.length; i++) { const row = rows[i]; if (row.cells.length <= 1 || row.querySelector(':scope > th') != null) { continue; } const lastCell = row.cells[row.cells.length-1]; lastCell.textContent = formatNumbersInText(lastCell.textContent); } } fixNumbersInCraftingTables('brewing'); fixNumbersInCraftingTables('cooking'); fixNumbersInCraftingTables('spellbook'); // fix cost numbers in game shop function fixNumersInNpcShop() { const costEls = document.querySelectorAll('#npc-store-tab span[id^="shop-"][id$="-cost"]'); for (let i = 0; i < costEls.length; i++) { const costEl = costEls[i].firstChild; costEl.textContent = formatNumbersInText(costEl.textContent); } } const oldLoadNpcShop = window.loadNpcShop; window.loadNpcShop = () => { oldLoadNpcShop(); fixNumersInNpcShop(); }; // fix stardust numbers of wizard tab const wizardBoxes = document.querySelectorAll('#wizard-tab .inventory-item-box'); for (let i = 0; i < wizardBoxes.length; i++) { const secondChild = wizardBoxes[i].childNodes[1]; if (secondChild.nodeType != Node.TEXT_NODE) { continue; } secondChild.textContent = formatNumbersInText(secondChild.textContent); } const globalLevelEl3 = document.getElementById('level-global-3'); if (globalLevelEl3) { const rankNode = globalLevelEl3.parentNode.firstChild; rankNode.textContent = formatNumbersInText(rankNode.textContent); } // fix group task shop const oldLoadGroupTaskShop = window.loadGroupTaskShop; function fixElementsTextContent(el) { const num = parseInt(el.textContent, 10); if (!isNaN(num)) { el.textContent = formatNumber(num); } } window.loadGroupTaskShop = () => { oldLoadGroupTaskShop(); fixElementsTextContent(document.getElementById('group-task-tokens-value')); fixElementsTextContent(document.getElementById('grp-shop-badge-price')); }; } /** * initialize notifications * * thanks /u/Vomera for the idea */ function observeTimer(k, onComplete, zero = 0) { observe(k, (key, oldValue, newValue) => { if (oldValue > zero && newValue == zero) { onComplete(key); } }); } function notifyClickable(title, options) { return notify(title, options).then((n) => { n.onclick = (...args) => { window.focus(); n.close(); }; return n; }); } // use notification2Tab on tab change (window.openTab) const notification2Tab = new Map(); const notificationMap = new Map(); function notifyTabClickable(title, options, tabName) { if (notificationMap.has(title)) { notificationMap.get(title).close(); } return notifyClickable(title, options).then((n) => { if (!notification2Tab.has(tabName)) { notification2Tab.set(tabName, new Set()); } const closeObj = { close: () => { n.close(); if (notificationMap.get(title) == closeObj) { notificationMap.delete(title); } notification2Tab.get(tabName).delete(closeObj); } }; notificationMap.set(title, closeObj); notification2Tab.get(tabName).add(closeObj); const oldOnclick = n.onclick; n.onclick = () => { oldOnclick(); window.openTab(tabName); }; return n; }); } function hideNotificationsFromTab(tabName) { if (notification2Tab.has(tabName)) { notification2Tab.get(tabName).forEach((n) => n.close()); } } function notifyCoop(msg) { window.send('OPEN_TAB=COOP'); return notifyTabClickable('Group Task', { body: msg.replace(/!$/, '.') , icon: 'images/icons/coop.png' }, 'coop'); } function notifyVendor() { /* "I have changed my items, come check them out."<br><br><img src="images/shop/vendor.png" width="120px" height="140px"> */ return notifyTabClickable('Vendor', { body: 'The vendor changed his items.' , icon: 'images/shop/vendor.png' }, 'vendor'); } 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 itemName = imgSrc2NamePlural(el.innerHTML, num); if (itemName) { loot.push(formatNumber(num) + ' ' + itemName); } else { loot.push(el.innerHTML); } } return notifyTabClickable('Fishing boat returns', { body: 'Your boat brings back: ' + loot.join(', ') , icon: 'images/exploring/fishingBoat.png' }, 'archaeology'); } function notifyRobot(msg) { /* <b>Your robot brings back:</b><br /><br />9,000,000 stone<br />2,250,000 copper<br />2,250,000 tin<br />675,000 iron<br />450,000 silver<br />180,000 gold<br />22,500 flint<br />4,500 marble<br />1,800 titanium<br />45 promethium<br /> */ return notifyTabClickable('Robot returns', { body: msg .replace('<br /><br />', ' ') .replace(/<br\s*\/?>(?=.)/g, ', ') .replace(/<[^>]+>/g, '') , icon: 'images/crafting/robot.png' }, 'repair'); } function notifyAchievement() { /* You have completed an achievement */ return notifyTabClickable('Achievement got', { body: 'You have completed an achievement.' , icon: 'images/shop/ach.png' }, 'ach'); } 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 (/Your robot brings back:/.test(msg)) { notifyRobot(msg); } else if (msg === 'You have completed an achievement') { notifyAchievement(); } else if (document.hidden || !document.hasFocus()) { notifyClickable('Message from server', { body: msg // , icon: 'images/minerals/diamond.png' }); } return Promise.reject(); } function initNotifications() { function requestNotificationPermission() { if (!getSetting('showNotifications') || Notification.permission !== 'default') { return; } Notification.requestPermission().then(function (result) { if (result == 'denied') { console.error('Permission to show notifications has been denied by the user.'); } }); } requestNotificationPermission(); observeSetting('showNotifications', () => requestNotificationPermission()); // don't send TAB_OFF when notifications have to be shown window.checkIfTabIsOpen = () => { if (!document.hidden || getSetting('showNotifications')) //open { if (tabOn == 0) { send('TAB_ON'); tabOn = 1; } } else //minimized { if (tabOn == 1) { send('TAB_OFF'); tabOn = 0; } } window.setTimeout(window.checkIfTabIsOpen, 500); }; 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; notifyTabClickable('Harvest', { body: 'One or more of your crops is ready for harvest.' , icon: 'images/icons/watering-can.png' }, 'farming'); }, 1); observeTimer('exploringTimer', (key) => { notifyTabClickable('Explorer ready', { body: 'Your explorer is back.' , icon: 'images/icons/archaeology.png' }, 'archaeology'); }); observeTimer('furnaceCurrentTimer', (key) => { notifyTabClickable('Furnace ready', { body: 'Your smelting has finished.' , icon: 'images/crafting/' + furnaceLevels[window.bindedFurnaceLevel] + 'Furnace.gif' }, 'repair'); }); observeTimer('rocketTimer', (key) => { notifyTabClickable('Rocket ready', { body: 'You landed on the moon.' , icon: 'images/crafting/rocket.png' }, 'repair'); }); observeTimer('robotTimer', (key) => { notifyTabClickable('Robot ready', { body: 'Your robot is back.' , icon: 'images/crafting/robot.png' }, 'repair'); }); observeTimer('fishingBoatTimer', (key) => { notifyTabClickable('Fishing boat ready', { body: 'Your fishing boat is back.' , icon: 'images/exploring/fishingBoat.png' }, 'archaeology'); }); observeTimer('largeFishingBoatTimer', (key) => { notifyTabClickable('Large fishing boat ready', { body: 'Your large fishing boat is back.' , icon: 'images/exploring/largeFishingBoat.png' }, '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 = ` .top-status-bar td.no-borders[width="27%"] { position: relative; } #span-oil ~ span { position: absolute; margin-left: 10px; top: 29px; } #span-oil + span { top: 5px; } 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; } .notification-timer-box { line-height: 52px; } #fishingBoat-timer > img:first-child { height: 40px; width: 53px; } #largeFishingBoat-timer > img:first-child { padding: 5px 5px 8px 0px !important; height: 40px; width: 56px; } `; document.head.appendChild(style); const oilPerSecond = document.getElementById('span-oilPerSecond'); oilPerSecond.previousSibling.textContent = '+'; oilPerSecond.nextSibling.textContent = ''; const oilLosePerSecond = document.getElementById('span-oilLosePerSecond'); oilLosePerSecond.previousSibling.textContent = ''; oilLosePerSecond.nextSibling.textContent = ''; } /** * 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 oldLoadCoop = window.loadCoop; window.loadCoop = (data) => { /** * There are some userscripts (DH QoL *cough*) which uses setting the innerHTML of the notification box parent * to add elements. * So the reference to the created element (above) isn't valid anymore and has to be refreshed after this * addition to the innerHTML. * This functions "appendChild" and "insertBefore" aren't there for no reason... :( * This error took me more than 4 hours to find and is just stupid (because someone is too lazy to create clean * and considerate software). * * Edit: * I don't know if anybody care to read my code, but I want to apologize for the comment above. * I love DHQoL (I didn't even spell it correctly - shame on me) and was more annoyed by my own incompetence * than by any behaviour of DHQoL. * Sorry for that unnecessary salty comment. */ const notifBox = document.getElementById('coop-notif'); const coopProgress = notifBox.querySelector('span.progress'); 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 historyPart = historyIndex == -1 ? [] : chatHistory.slice(0, historyIndex).reverse(); const msgBeforeUser = historyPart.find(d => isThisPm && isPM(d) || !isThisPm && !isPM(d)); const msgBeforeTime = historyPart.find(d => isThisPm && isPM(d) || !isThisPm && !isPM(d) && d.type != -1); let isSameUser = false; let isSameTime = false; if (msgBeforeUser) { const beforeUsername = msgBeforeUser.type == 2 ? window.username : msgBeforeUser.username; isSameUser = beforeUsername === msgUsername; } if (msgBeforeTime) { isSameTime = Math.floor(data.timestamp / 1000 / 60) - Math.floor(msgBeforeTime.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="${msgUsername}" 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[data-type="-1"] { font-size: 0.8rem; } .chat-msg .timestamp::before { color: hsla(0, 0%, 50%, 1); font-size: .9rem; } .chat-msg .timestamp[data-same-time="true"]::before { } #chat-toggle-timestamps: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"]'); function getChatValue(key) { if (key == 'autoscroll' || key == 'timestamps') { return JSON.parse(localStorage.getItem('chat.' + key) || 'true'); } return false; } function setChatValue(key, value) { if (key == 'autoscroll' || key == 'timestamps') { localStorage.setItem('chat.' + key, JSON.stringify(value)); if (key == 'autoscroll') { window.isAutoScrolling = value; } else if (key == 'timestamps') { window.showTimestamps = value; } return true; } return false; } for (let i = 0; i < toggles.length; i++) { const toggle = toggles[i]; const parent = toggle.parentNode; const toggleWhat = toggle.value.replace('Toggle ', ''); const toggleKey = toggleWhat.toLowerCase(); const id = 'chat-toggle-' + toggleKey; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.id = id; checkbox.value = toggleKey; const checkedValue = getChatValue(toggleKey); setChatValue(toggleKey, checkedValue); checkbox.checked = checkedValue; 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 (!setChatValue(checkbox.value, checkbox.checked)) { 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; function setChatBoxHeight(height) { document.getElementById('chat-area-div').style.height = height; const chatDivs = chatBoxArea.querySelectorAll('div[id^="chat-pm-"]'); for (let i = 0; i < chatDivs.length; i++) { chatDivs[i].style.height = height; } } window.chatBoxZoom = (zoom) => { oldChatBoxZoom(zoom); const height = document.getElementById('chat-area-div').style.height; localStorage.setItem('chat.height', height); setChatBoxHeight(height); }; setChatBoxHeight(localStorage.getItem('chat.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 * * thanks /u/Vomera */ const activityLogKey = 'activityLog'; const maxActivityLogLength = 200; let activityLog = []; const explorerReturns = 'Your explorer brings back:'; const explorerReturnsWithoutArtifacts = 'You find 0 artifacts (+0 xp)'; // unused atm function processExplorerMessage(msg) { const tmp = createTemplateWrapper( msg .replace(explorerReturns, '') .replace(explorerReturnsWithoutArtifacts, '') .replace(/<br\s*\/?>/g, '') .trim() ); // handle used artifact potion const artifactPotionEl = tmp.querySelector('center > img[src$="artifactPotion.png"]'); let artifactPotion = ''; if (artifactPotionEl) { artifactPotion = tmp.firstElementChild.textContent.trim().replace(/used/i, 'One artifact potion used'); tmp.removeChild(tmp.firstElementChild); } // handle loot bags and received artifacts const lootEls = tmp.querySelectorAll('span[class^="exploring-norm-loot"]'); const loot = []; const artifacts = []; for (let i = 0; i < lootEls.length; i++) { const el = lootEls[i]; const quantityStr = el.textContent.trim(); const num = parseInt(quantityStr, 10); const isArtifact = quantityStr.includes('xp'); const itemName = isArtifact ? imgSrc2Name(el.innerHTML) : imgSrc2NamePlural(el.innerHTML, num); if (itemName) { if (isArtifact) { artifacts.push(itemName + ' (' + quantityStr.replace(num.toString(), formatNumber(num)) + ')'); } else { loot.push(formatNumber(num) + ' ' + itemName); } } else { loot.push(el.innerHTML); } el.parentNode.removeChild(el); } const noArtifacts = msg.includes(explorerReturnsWithoutArtifacts); let newMsg = ''; if (tmp.textContent.trim() != '') { const regex = /<([^>\s]+)[^>]*>\s*<\/\1>/; let html = tmp.innerHTML; while (regex.test(html)) { html = html.replace(regex, ''); } newMsg += html + '. '; } if (artifactPotion != '') { newMsg += artifactPotion + '. '; } newMsg += explorerReturns + ' ' + loot.concat(artifacts).join(', '); if (noArtifacts) { newMsg += '. ' + explorerReturnsWithoutArtifacts; } return newMsg; } // unused atm function processGroupMessage(msg) { const tmp = createTemplateWrapper(msg); const tokenEl = tmp.querySelector('.basic-smallbox'); const tokenNum = parseInt(tokenEl.textContent, 10); let newMsg = tokenEl.textContent.trim() + ' ' + imgSrc2NamePlural(tokenEl.innerHTML, tokenNum); const infoSpan = tmp.querySelector(':scope > span'); if (infoSpan) { newMsg += ' - ' + infoSpan.textContent; } return newMsg; } /* <span style='color:green;'>1 products cooked</span><br /><br /><img src='images/icons/cookingskill.png' width='20px' height='20px' style='vertical-align:middle'> +630 xp <span style='color:green;'>1 products cooked</span><br /><br /><img src='images/icons/cookingskill.png' width='20px' height='20px' style='vertical-align:middle'> +720 xp <span style='color:green;'>5 products cooked</span><br /><br /><img src='images/icons/cookingskill.png' width='20px' height='20px' style='vertical-align:middle'> +180 xp <span style='color:green;'>3 products cooked</span><br /><br /><img src='images/icons/cookingskill.png' width='20px' height='20px' style='vertical-align:middle'> +1680 xp <span style='color:green;'>3 products cooked</span><br /><br /><img src='images/icons/cookingskill.png' width='20px' height='20px' style='vertical-align:middle'> +84 xp <span style='color:green;'>1 products cooked</span><br /><br /><img src='images/icons/cookingskill.png' width='20px' height='20px' style='vertical-align:middle'> +560 xp <span style='color:green;'>0 products cooked</span><br /><br /><span style='color:red;'>1 products burnt</span><br /><br /><img src='images/icons/cookingskill.png' width='20px' height='20px' style='vertical-align:middle'> +0 xp */ // unused atm function processCookingMessage(msg) { const tmp = createTemplateWrapper(msg); const products = []; const spans = tmp.querySelectorAll(':scope > span'); for (let i = 0; i < spans.length; i++) { products.push(spans[i].textContent.trim()); } products.push(tmp.lastChild.textContent); return products.join(', '); } /* <center><img width='150px' height='150px' src='images/misc-items/openChest.png'></center><br /><br /><span class='inventory-item-box-smaller'><img class='small-img' src='images/brewing/blewitmushroom.png'> Blewit Mushrooms (400)</span><br /> <center><img width='150px' height='150px' src='images/misc-items/openChest.png'></center><br /><br /><span class='inventory-item-box-smaller'><img class='small-img' src='images/minerals/goldbar.png'> Gold Bars (500)</span><br /><span class='inventory-item-box-smaller'><img class='small-img' src='images/crafting/upgradeFurnaceOrb.png'> Furnace Orb</span> */ // unused atm function processChestMessage(msg) { const tmp = createTemplateWrapper(msg); const lootEls = tmp.querySelectorAll('.inventory-item-box-smaller'); const loot = []; for (let i = 0; i < lootEls.length; i++) { const el = lootEls[i]; const match = el.textContent.match(/(.+) \((\d+)\)/); let num = 1; if (match) { num = parseInt(match[2]); } const itemName = imgSrc2Name(el.innerHTML, num); if (itemName) { loot.push(num + ' ' + itemName); } else { loot.push(el.textContent.trim()); } } return 'Opened Chest and got: ' + loot.join(', '); } /* "I have changed my items, come check them out."<br /><br /><img src='images/shop/vendor.png' width='120px' height='140px' /> */ const vendorChangedText = 'I have changed my items, come check them out.'; // unused atm function processVendorMessage(msg) { return 'The vendor has changed his items.'; } /* == collection of some messages: == You mix 1 potions. You mix 1 (+0) potions. You mix 1 (+1) potions. You have completed your group task! x has completed his group task. Machinery upgraded to level: 6 Your fix all your machinery You also use your glass blowing pipe. You do not have enough stardust +15000 stardust. Your upgraded rake shines as you harvest. You dont have this seed. New food item added. 1 artifact potions activated. You have completed an achievement You pour lava over your runite ore. Your account has been running for 5 Minutes You craft a key You craft a gold oven You craft a Brewing Kit <img src='images/icons/cookingskill.png' width='50px' height='50px'/><br /><br /> You need a skilling level of 40 to bind this. <span style='color:green;'>Item succesfully added to the market.</span> The wizard takes your orb and extracts its energy.<br /><br /><img height='200px' width='250px' src='images/shop/wizard2.png'><br /><br /><b>'I still need more power!'</b> The wizard takes your orb and extracts its energy.<br /><br /><img height='200px' width='250px' src='images/shop/wizard2.png'><br /><br /><b>'You may now use me to convert seeds into mega seeds!'</b> */ // unused atm function processMessage(msg) { if (msg.includes(explorerReturns)) { return processExplorerMessage(msg); } else if (msg.includes('icons/groupTaskTokens.png')) { return processGroupMessage(msg); } else if (msg.includes('products cooked')) { return processCookingMessage(msg); } else if (msg.includes('images/misc-items/openChest.png')) { return processChestMessage(msg); } else if (msg.includes(vendorChangedText)) { return processVendorMessage(msg); } return msg; } const autoreadMsgList = [ 'You also use your glass blowing pipe.' , 'New food item added.' , 'Your upgraded rake shines as you harvest.' , 'Your fix all your machinery' , 'Perk unlocked.' , 'You pour lava over your runite ore.' , 'You fill transform your oil into 1 container of rocket fuel.' , 'Item succesfully added to the market.' , 'products cooked' , 'Items purchased.' , 'You craft ' , 'Your account has been running for' , 'You don\'t have this seed.' , 'You gain some mining experience.' , 'You do not have enough stardust' , 'Your robot starts his journey.' ]; function add2ActivityLog(cmd) { const data = { type: cmd.type , time: (new Date()).getTime() // , msg: processMessage(msg) , msg: cmd.msg }; activityLog.push(data); activityLog = activityLog.slice(-maxActivityLogLength); localStorage.setItem(activityLogKey, JSON.stringify(activityLog)); return data; } const activityLogInputId = 'show-activity-log'; function updateActivity(data, triesLeft = 50) { const inputEl = document.getElementById(activityLogInputId); const activityLogLabel = document.getElementById('activity-log-label'); // delay this function call until the dom is fully loaded if (!activityLogLabel || !inputEl) { if (triesLeft > 0) { setTimeout(() => updateActivity(data, triesLeft-1), 100); } return; } const read = autoreadMsgList.some((str) => data.msg.indexOf(str) > -1); if (!inputEl.checked && !read) { activityLogLabel.dataset.new = parseInt(activityLogLabel.dataset.new, 10) + 1; } // add an entry for the given data to the activity list (DOM) const activityLogList = document.getElementById('activity-log'); const listItem = document.createElement('li'); listItem.dataset.time = (new Date(data.time)).toLocaleString(); listItem.innerHTML = data.msg; const before = activityLogList.firstElementChild; if (before) { activityLogList.insertBefore(listItem, before); } else { activityLogList.appendChild(listItem); } } function initActivityLog() { const gameScreen = document.getElementById('game-screen'); const table = document.querySelector('div.top-menu > table'); const row = table.rows[0]; // change text to reduce used size const onlineCell = row.cells[row.cells.length-2]; onlineCell.firstChild.textContent = 'Currently online: '; onlineCell.removeChild(onlineCell.lastChild); // insert activity log cell const cell = row.insertCell(-1); cell.classList.add('table-top'); // creat input and label const inputEl = document.createElement('input'); inputEl.id = activityLogInputId; inputEl.type = 'checkbox'; inputEl.style.display = 'none'; inputEl.addEventListener('change', function () { if (inputEl.checked) { logEl.dataset.new = 0; } }); document.body.insertBefore(inputEl, gameScreen); // create clickable text const logEl = document.createElement('label'); logEl.id = 'activity-log-label'; logEl.htmlFor = activityLogInputId; logEl.dataset.new = 0; logEl.textContent = 'Activity Log'; cell.appendChild(logEl); // add a container for the entry listing const logOverlay = document.createElement('label'); logOverlay.id = 'activity-log-overlay'; logOverlay.htmlFor = activityLogInputId; document.body.appendChild(logOverlay); const log = document.createElement('ul'); log.id = 'activity-log'; document.body.appendChild(log); const style = document.createElement('style'); style.innerHTML = ` #${activityLogInputId} { display: none; } body { overflow-y: scroll; } /* #game-screen { overflow: auto; position: absolute; bottom: 0; left: 0; top: 0; right: 0; } #${activityLogInputId}:checked + #game-screen { overflow: hidden; } */ #activity-log-label { cursor: pointer; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } #activity-log-label::after { content: ' (' attr(data-new) ')'; color: lime; } #activity-log-label[data-new="0"]::after { color: white; } #activity-log-overlay { background-color: transparent; color: transparent; pointer-events: none; position: fixed; bottom: 0; left: 0; top: 0; right: 0; transition: background-color .3s ease-out; z-index: 1000; } #${activityLogInputId}:checked ~ #activity-log-overlay { background-color: rgba(0, 0, 0, 0.4); pointer-events: all; } #activity-log { background-color: white; color: black; list-style: none; margin: 0; overflow-y: scroll; padding: .4rem .8rem; position: fixed; top: 0; right: 0; bottom: 0; transform: translateX(100%); transition: transform .3s ease-out; min-width: 15rem; width: 40%; max-width: 30rem; z-index: 1000; } #${activityLogInputId}:checked ~ #activity-log { transform: translateX(0%); } #activity-log::before { content: 'Activity Log'; display: block; font-size: 1rem; font-weight: bold; margin-bottom: 0.8rem; } #activity-log:empty::after { content: 'Activities will be listed here.'; } #activity-log li { border: 1px solid gray; border-radius: .2rem; margin: .2rem 0; padding: .4rem .8rem; } #activity-log li::before { color: gray; content: attr(data-time); display: block; font-size: 0.8rem; margin: -4px 0 4px -4px; } `; document.head.appendChild(style); activityLog = JSON.parse(localStorage.getItem(activityLogKey) || JSON.stringify(activityLog)); activityLog.forEach(d => updateActivity(d)); logEl.dataset.new = 0; } /** * improve tabs */ function highlightTab(tabName) { const tabKey = { 'gatherings': 'ores' , 'shop': 'market' , 'stats': 'skills' }[tabName] || tabName; const oldTab = document.querySelector('td[id^="table-tab-"].selected'); if (oldTab) { oldTab.classList.remove('selected'); } const newTab = document.getElementById('table-tab-' + tabKey); if (newTab) { newTab.classList.add('selected'); } const oldSubTabs = document.querySelector('#sub-tabs > .sub-tab-container.show'); if (oldSubTabs) { oldSubTabs.classList.remove('show'); } const subTabs = document.getElementById('sub-tabs-' + tabName); if (subTabs) { subTabs.classList.add('show'); // tidy up old sub tabs const oldSubTab = document.querySelector('.sub-tab-container > .selected'); if (oldSubTab) { oldSubTab.classList.remove('selected'); } subTabs.firstElementChild.classList.add('selected'); } } function highlightSubTab(tabName) { const oldSubTab = document.querySelector('.sub-tab-container > .selected'); if (oldSubTab) { oldSubTab.classList.remove('selected'); } document.getElementById('table-tab-' + tabName).classList.add('selected'); } const mainTabList = ['gatherings', 'key-items', 'repair', 'mining', 'crafting', 'farming', 'brewing', 'archaeology', 'magic', 'shop', 'stats', 'coop', 'settings']; const subTab2MainTab = { 'collectables': 'key-items' , 'ach': 'key-items' , 'vendor': 'key-items' , 'wizard': 'key-items' , 'dragon': 'key-items' , 'miningEngineer': 'repair' , 'ach-explore': 'archaeology' , 'archaeology-crafting': 'archaeology' , 'cooking': 'archaeology' , 'spellbook': 'magic' , 'magiccrafting': 'magic' , 'npc-store': 'shop' , 'donor-store': 'shop' , 'player-store': 'shop' }; function newOpenTab(tabName) { if (tabName == 'player-store') { window.marketRefreshOn = 1; window.send('OPEN_MARKET'); } else if (window.marketRefreshOn == 1) { window.send('CLOSE_MARKET'); window.marketRefreshOn = 0; } if (tabName == 'coop' && window.getGlobalLevel() < 100) { window.openDialogue('Global Level', 'You need a global level of at least 100 to start the CO-OP adventure!', ''); return; } else if (tabName == 'cooking' && window.cookingUnlocked == 0) { window.openDialogue('Skill Missing', 'You must unlock the cooking skill to cook food.', ''); return; } if (tabName == 'spellbook' && window.bindedMagicPage1 == 0 && window.bindedMagicPage2 == 0 && window.bindedMagicPage3 == 0 && window.bindedMagicPage4 == 0 && window.bindedMagicPage5 == 0) { window.openDialogue('Spellbook', 'You do not have any pages in your spellbook yet.', ''); return; } window.hideAllTabs(); const panelName = { 'shop': 'store' }[tabName] || tabName; const panelEl = document.getElementById(panelName + '-tab'); if (panelEl) { panelEl.style.display = 'block'; } if (mainTabList.includes(tabName)) { highlightTab(tabName); } if (subTab2MainTab.hasOwnProperty(tabName)) { // highlight the main tab (if the openTab call if from notification) const mainTabName = subTab2MainTab[tabName]; highlightTab(mainTabName); highlightSubTab(tabName); hideNotificationsFromTab(mainTabName); } hideNotificationsFromTab(tabName); if (tabName == 'itemStats') { window.loadAllStats(); } else if (tabName == 'archaeology' && mapOfTheSea > 0) { document.getElementById('hasMapOfTheSea-fishermen').style.display = ''; } else if (tabName == 'mining' && enchantedPickaxeStarDust > 0) { document.getElementById('charge-pickaxe-box').style.display = ''; } else if (tabName == 'crafting' && enchantedHammerStarDust > 0) { document.getElementById('uncharge-hammer-box').style.display = ''; } else if (tabName == 'collectables') { window.loadCollectables(); } else if (tabName == 'vendor') { if (vendorChangedFlag > 0) { window.send('RESET_VENDOR_CHANGED_FLAG'); } if (window.getLevel(craftingXp) >= 100 || window.getLevel(miningXp) >= 100 || window.getLevel(merchantingXp) >= 100 || window.getLevel(exploringXp) >= 100 || window.getLevel(brewingXp) >= 100 || window.getLevel(magicXp) >= 100) { if (window.dragonOrb == 0) { document.getElementById('vendor-item-box-quest').style.display = 'block'; window.openDialogue('Vendor', '<center><img src="images/shop/vendor.png" width="100px" height="200px" /><br /><br /> "I have something very special for you."</center>', ''); } } } else if (tabName == 'repair') { window.refreshRepairTab(); } else if (tabName == 'dragon') { if (window.dragonOrb == 0) { document.getElementById('dragon-tab').style.display = 'block'; return; } window.loadDragonTab(); } } function applyNewTabStyle() { const style = document.createElement('style'); style.innerHTML = ` #tab-tr > td, .sub-tab-container > span { background: -webkit-linear-gradient(black, grey); background: -o-linear-gradient(black, grey); background: -moz-linear-gradient(black, grey); background: linear-gradient(black, grey); cursor: pointer; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } #tab-tr > td:hover, .sub-tab-container > span:hover { background: -webkit-linear-gradient(red, grey); background: -o-linear-gradient(red, grey); background: -moz-linear-gradient(red, grey); background: linear-gradient(red, grey); } #tab-tr > td.selected, .sub-tab-container > span.selected, #table-tab-ach.selected { background: -webkit-linear-gradient(#800000, #390000); background: -o-linear-gradient(#800000, #390000); background: -moz-linear-gradient(#800000, #390000); background: linear-gradient(#800000, #390000); } #sub-tabs { font-size: 10pt; height: 43px; } body.hide-sub-tabs #sub-tabs { display: none; } .sub-tab-container { display: none; } .sub-tab-container.show { display: inline-block; } .sub-tab-container > span, #table-tab-ach { border: 0 solid #aaa; border-right-width: 1px; color: white; cursor: pointer; display: inline-block; line-height: 27px; padding: 8px 10px; } .sub-tab-container > span:first-child { border-left-width: 1px; } .sub-tab-container > span:not(:first-child)::before { background-repeat: no-repeat; background-size: 25px 25px; content: ''; display: inline-block; margin-right: .4rem; height: 25px; width: 25px; vertical-align: middle; } #sub-tabs.hide-tab-text .sub-tab-container > span:not(:first-child)::before { margin-right: 0; } .sub-tab-container > span::after { content: attr(data-tab-text); } #sub-tabs.hide-tab-text .sub-tab-container > span:not(:first-child)::after { display: none; } #sub-tabs-shop > span:not(:first-child)::before { display: none; } #table-tab-collectables::before { background-image: url('images/icons/collectables.png'); background-size: 32px 25px; width: 32px; } #table-tab-ach::before { background-image: url('images/shop/ach.png'); } #table-tab-vendor::before { background-image: url('images/shop/vendor.png'); } #table-tab-wizard::before { background-image: url('images/shop/superWizard.png'); background-size: 13px 25px; width: 13px; } #table-tab-dragon::before { background-image: url('images/crafting/dragonOrb.png'); } #table-tab-miningEngineer::before { background-image: url('images/shop/miningEngineer.png'); background-size: 19px 25px; width: 19px; } #table-tab-ach-explore::before { background-image: url('images/exploring/equipement/silverBody.png'); } #table-tab-archaeology-crafting::before, #table-tab-magiccrafting::before { background-image: url('images/icons/anvil.png'); background-size: 28px 25px; width: 28px; } #table-tab-cooking::before { background-image: url('images/icons/cookingskill_baw.png'); background-size: 17px 25px; width: 17px; } #table-tab-spellbook::before { background-image: url('images/magic/magicBook.png'); background-size: 32px 25px; width: 32px; } #sub-tabs.hide-tab-text .sub-tab-container > span#table-tab-npc-store::after, #sub-tabs.hide-tab-text .sub-tab-container > span#table-tab-donor-store::after, #sub-tabs.hide-tab-text .sub-tab-container > span#table-tab-player-store::after { display: initial; } `; document.head.appendChild(style); const subTabContainer = document.createElement('div'); subTabContainer.id = 'sub-tabs'; // add all sub-tabs function addSubContainer(parentKey, content) { const subContainer = document.createElement('div'); subContainer.className = 'sub-tab-container'; subContainer.id = 'sub-tabs-' + parentKey; subContainer.innerHTML = '<span>Overview</span>' + content; subTabContainer.appendChild(subContainer); } addSubContainer( 'key-items' , `<span id="table-tab-collectables" data-tab-text="Collectables"></span>` + `<span id="table-tab-ach" data-tab-text="Achievements"></span>` + `<span id="table-tab-vendor" data-tab-text="Vendor"></span>` + `<span id="table-tab-wizard" data-tab-text="Wizard"></span>` + `<span id="table-tab-dragon" data-tab-text="Dragon's Lair"></span>` ); addSubContainer( 'repair' , `<span id="table-tab-miningEngineer" data-tab-text="Mining Engineer"></span>` ); addSubContainer( 'archaeology' , `<span id="table-tab-ach-explore" data-tab-text="Equipment"></span>` + `<span id="table-tab-archaeology-crafting" data-tab-text="Craft"></span>` + `<span id="table-tab-cooking" data-tab-text="Cooking"></span>` ); addSubContainer( 'magic' , `<span id="table-tab-spellbook" data-tab-text="Cast Spell"></span>` + `<span id="table-tab-magiccrafting" data-tab-text="Craft"></span>` ); addSubContainer( 'shop' , `<span id="table-tab-npc-store" data-tab-text="Game Shop"></span>` + `<span id="table-tab-donor-store" data-tab-text="Donor Shop"></span>` + `<span id="table-tab-player-store" data-tab-text="Player Market"></span>` ); subTabContainer.addEventListener('click', (event) => { const target = event.target; const parent = target.parentNode; if (parent.classList.contains('sub-tab-container')) { const newTabName = (target.id ? target : parent).id .replace('table-tab-', '') .replace('sub-tabs-', '') ; if (newTabName != '') { window.openTab(newTabName); } } }); document.getElementById('tab-container').appendChild(subTabContainer); function handleTabTextVisibility() { const isOn = window.tabTextOff > 0; subTabContainer.classList[isOn ? 'add' : 'remove']('hide-tab-text'); } handleTabTextVisibility(); observe('tabTextOff', () => handleTabTextVisibility()); // fix on click handler const craftExploringBtn = document.querySelector('[onclick^="switchToCraftingExploringTab"]'); craftExploringBtn.setAttribute('onclick', "openTab('archaeology-crafting')"); } function checkSubTab(tabKey, windowKeys, init) { const fulfilled = windowKeys.some(key => window[key] > 0); document.getElementById('table-tab-' + tabKey).style.display = fulfilled ? '' : 'none'; if (init) { for (let key of windowKeys) { observe(key, () => checkSubTab(tabKey, windowKeys, false)); } } } function improveTabs() { applyNewTabStyle(); window.openTab = newOpenTab; newOpenTab('gatherings'); // observe some values to show sub tabs as soon as they are accessible checkSubTab('ach', ['achShop'], true); checkSubTab('vendor', ['hasVendor'], true); checkSubTab('wizard', ['wizard'], true); checkSubTab('dragon', ['dragonOrb'], true); checkSubTab('miningEngineer', ['miningEngineer'], true); checkSubTab('cooking', ['cookingUnlocked'], true); checkSubTab('spellbook', [ 'bindedMagicPage1' , 'bindedMagicPage2' , 'bindedMagicPage3' , 'bindedMagicPage4' , 'bindedMagicPage5' , 'bindedMagicPage6' ], true); function setVisibilityOfSubTabs() { const hide = !getSetting('addSubTabs'); document.body.classList[hide ? 'add' : 'remove']('hide-sub-tabs'); } setVisibilityOfSubTabs(); observeSetting('addSubTabs', () => setVisibilityOfSubTabs()); } /** * improve exploring dialog */ function improveExploringDialog() { const style = document.createElement('style'); style.innerHTML = ` div#dialog-explore-areas tr > td:nth-child(2) img { height: 38px; width: 63px; } `; document.head.appendChild(style); const table = document.querySelector('#dialog-explore-areas table.table-stats'); const rows = table.rows; for (let i = 0; i < rows.length; i++) { const row = rows[i]; if (i == 0) { const refCell = row.cells[2]; const levelTh = document.createElement('th'); levelTh.innerHTML = 'Level'; row.insertBefore(levelTh, refCell); const energyTh = document.createElement('th'); energyTh.innerHTML = 'Energy/XP Cost'; row.insertBefore(energyTh, refCell); refCell.textContent = 'Lair'; } else { const reqCell = row.cells[2]; const levelCell = row.insertCell(2); const img = reqCell.firstElementChild; const levelChild = img.nextSibling; const level = parseInt(levelChild.textContent.replace(/\D*(?=\d)/, ''), 10); const xpMatch = levelChild.textContent.match(/\((.+) XP\)/); levelCell.textContent = formatNumber(level); reqCell.removeChild(img); reqCell.removeChild(levelChild); if (levelChild.textContent.trim() == '') { reqCell.removeChild(levelChild.nextElementSibling); } const energyCell = row.insertCell(3); const energyText = reqCell.lastChild.textContent.replace(/\D*(?=\d)/, ''); const energy = parseInt(energyText, 10) * (/\d\s*M(\W|$)/.test(energyText) ? 1e6 : 1); const energyFactor = 1 - parseInt(window.exploringEnergyReductionPerc, 10) / 100; energyCell.textContent = formatNumber(Math.floor(energyFactor * energy)); if (xpMatch) { const xp = parseInt(xpMatch[1], 10) * (/\d\s*M(\W|$)/.test(xpMatch[1]) ? 1e6 : 1); energyCell.innerHTML += '<br>' + formatNumber(xp) + ' XP'; } reqCell.removeChild(reqCell.lastChild); if (reqCell.textContent.indexOf('Access to lair') != -1) { const br = reqCell.lastElementChild; const lairText = br.previousSibling; reqCell.removeChild(br); reqCell.removeChild(lairText); } const timeCell = row.cells[row.cells.length-1]; const timeMatch = timeCell.textContent.match(/(\d+)(?::(\d+))?\s*(min|h)\./); if (timeMatch) { const num1 = parseInt(timeMatch[1], 10); const num2 = parseInt(timeMatch[2] || '0', 10); const factor = { 'min': 60 , 'h': 3600 }[timeMatch[3]] || 1; const timeFactor = 1 - parseInt(window.exploringTimeReductionPerc, 10) / 100; const totalSeconds = Math.floor((num1 * factor + num2 * (factor / 60)) * timeFactor); const hours = Math.floor(totalSeconds / 3600); const minutes = Math.floor(totalSeconds / 60) % 60; const seconds = totalSeconds % 60; timeCell.textContent = (hours < 10 ? '0' : '') + hours + ':' + (minutes < 10 ? '0' : '') + minutes + ':' + (seconds < 10 ? '0' : '') + seconds ; } } } } /** * fix DH1 links */ function fixDH1Links() { const links = document.querySelectorAll('a[href]'); for (let i = 0; i < links.length; i++) { const link = links[i]; if (/^https?:\/\/(?:www\.)?diamondhunt\.co\/(?!DH1\/)/.test(link.href)) { link.href = link.href.replace(/(diamondhunt\.co\/)/, '$1DH1/'); } } } /** * init */ function init() { console.info('[%s] "DH1 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(); improveTabs(); improveExploringDialog(); fixDH1Links(); } class Command { static isMsg(type) { return type === 'QUESTION' || type === 'MESSAGE' || type === 'MSG_BOX'; } constructor(cmd) { this.type = cmd.replace(/=.+$/, ''); const restCmd = cmd.substr(this.type.length + 1); this.params = restCmd.split('~'); this.isMsg = Command.isMsg(this.type); this._msg = ''; if (this.isMsg) { this.msg = formatNumbersInText(this.params[0].trim()); } } get msg() { return this._msg; } set msg(newMsg) { this.params[0] = this._msg = newMsg; } prepare() { if (!this.isMsg) { return; } if (this.msg === 'You dont have this seed.') { this.type = 'MSG_BOX'; this.msg = `You don't have this seed.`; } else if (/Your account has been running for/.test(this.msg)) { /* Your account has been running for 234 Minutes => convert minutes into better readable format (hours and minutes) */ this.msg = this.msg.replace(/(\d+) Minutes/, (str, min) => { min = parseInt(min, 10); const hours = Math.floor(min / 60); min = min % 60; return (hours > 0 ? hours + ' hour' + (hours == 1 ? '' : 's') + ' and ' : '') + min + ' minute' + (min == 1 ? '' : 's'); }); } else { this.msg = this.msg.replace( `<img class='small-img' src='images/brewing/pic_coin.png'>` , `<img class='small-img' src='images/pic_coin_bigstack.png'>` ); } } toString() { return this.type + '=' + this.params.join('~'); } } document.addEventListener('DOMContentLoaded', () => { const oldLoadCommand = window.loadCommand; window.loadCommand = (cmdString) => { const cmd = new Command(cmdString); if (!fullyLoaded && cmd.type == 'ITEMS_DATA') { const ret = oldLoadCommand(cmdString); fullyLoaded = true; init(); return ret; } cmd.prepare(); // add message to activity log if (cmd.isMsg) { const data = add2ActivityLog(cmd); updateActivity(data); } if (cmd.msg === 'You have completed an achievement') { notifyMsg(cmd.msg) .catch(() => oldLoadCommand(cmd.toString())) ; return; } else if (cmd.type === 'MESSAGE') { notifyMsg(cmd.msg) .catch(() => oldLoadCommand(cmd.toString())) ; return; } return oldLoadCommand(cmd.toString()); }; }); /** * fix annoying errors in console caused by web socket events when DOM still loading */ function addMessageListenerFix() { const newScript = document.createElement('script'); newScript.textContent = ` if (window.webSocket != null) { const messageQueue = []; const oldOnMessage = webSocket.onmessage; webSocket.onmessage = (event) => messageQueue.push(event); document.addEventListener('DOMContentLoaded', () => { messageQueue.forEach(event => onMessage(event)); webSocket.onmessage = oldOnMessage; }); } `; document.head.appendChild(newScript); } function isWebSocketScript(script) { return script.textContent.includes('webSocket.onmessage'); } function fixWebSocketScript() { if (!document.head) { return; } const scripts = document.head.querySelectorAll('script'); let found = false; for (let i = 0; i < scripts.length; i++) { if (isWebSocketScript(scripts[i])) { addMessageListenerFix(); return; } } // create an observer instance const mutationObserver = new MutationObserver((mutationList) => { mutationList.forEach((mutation) => { if (mutation.addedNodes.length === 0) { return; } for (let i = 0; i < mutation.addedNodes.length; i++) { const node = mutation.addedNodes[i]; if (node.tagName == 'SCRIPT' && isWebSocketScript(node)) { mutationObserver.disconnect(); setTimeout(() => addMessageListenerFix()); return; } } }); }); mutationObserver.observe(document.head, { childList: true }); } fixWebSocketScript(); })();