您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Improve Diamond Hunt 2
// ==UserScript== // @name DH2 Fixed // @namespace FileFace // @description Improve Diamond Hunt 2 // @version 0.246.2 // @author Zorbing // @license ISC; http://opensource.org/licenses/ISC // @grant none // @run-at document-start // @include http://www.diamondhunt.co/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'; var version = '0.246.2'; var buildTime = new Date('2017-08-12T16:37:11.942Z'); var win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window; "use strict"; /** * observer */ var observer; (function (observer) { observer.GAME_TICK_KEY = 'dh2.gameTick'; var observedKeys = new Map(); function add(key, fn) { if (key instanceof Array) { for (var _i = 0, key_1 = key; _i < key_1.length; _i++) { var k = key_1[_i]; add(k, fn); } } else { if (!observedKeys.has(key)) { observedKeys.set(key, new Set()); } observedKeys.get(key).add(fn); } return fn; } observer.add = add; function notify(key, oldValue) { var newValue = getGameValue(key); if (observedKeys.has(key)) { observedKeys.get(key).forEach(function (fn) { return fn(key, oldValue, newValue); }); } } observer.notify = notify; function notifyTick() { notify(observer.GAME_TICK_KEY, Math.floor(now() / 1000)); } observer.notifyTick = notifyTick; function remove(key, fn) { if (key instanceof Array) { var ret = []; for (var _i = 0, key_2 = key; _i < key_2.length; _i++) { var k = key_2[_i]; ret.push(remove(k, fn)); } return ret; } if (!observedKeys.has(key)) { return false; } return observedKeys.get(key).delete(fn); } observer.remove = remove; function addTick(fn) { return add(observer.GAME_TICK_KEY, fn); } observer.addTick = addTick; function removeTick(fn) { return remove(observer.GAME_TICK_KEY, fn); } observer.removeTick = removeTick; })(observer || (observer = {})); /** * global constants */ var PLUS_MINUS_SIGN = String.fromCharCode(177); var TIER_LEVELS = ['empty', 'sapphire', 'emerald', 'ruby', 'diamond']; var TIER_NAMES = ['Standard', 'Sapphire', 'Emerald', 'Ruby', 'Diamond']; var TIER_ITEMS = ['pickaxe', 'shovel', 'hammer', 'axe', 'rake', 'trowel', 'fishingRod', 'chisel']; var ORB_ITEMS = ['pickaxe', 'shovel', 'hammer', 'axe', 'rake', 'trowel', 'fishingRod', 'chisel', 'oilPipe']; var TIER_ITEMS_NOT_BINDABLE = ['rake', 'trowel']; var FURNACE_LEVELS = ['stone', 'bronze', 'iron', 'silver', 'gold', 'promethium']; var OVEN_LEVELS = ['bronze', 'iron', 'silver', 'gold', 'promethium']; var WAND_LEVELS = ['wooden', 'oak', 'willow', 'maple', 'stardust']; var OIL_STORAGE_SIZES = [10e3, 50e3, 100e3, 300e3, 600e3, 2e6]; var RECIPE_MAX = { 'brewing': { 'braveryPotion': { max: 1 } , 'stardustCrystalPotion': { max: 1 } } , 'cooksBook': {} , 'crafting': { 'drills': { max: 10 } , 'crushers': { max: 10 } , 'giantDrills': { max: 10 } , 'excavators': { max: 10 } , 'oilPipe': { max: 1 } , 'pumpjacks': { max: 10 } , 'rowBoat': { max: 1 } , 'canoe': { max: 1 } , 'sailBoat': { max: 1 } , 'steamBoat': { max: 1 } // thanks aguyd , 'bonemealBin': { extraKeys: ['boundFilledBonemealBin'] , max: 1 } , 'oilFactory': { max: 1 } , 'brewingKit': { max: 1 } , 'rocket': { max: 1 } } , 'magic': {} }; var SMELTING_REQUIREMENTS = { 'glass': { sand: 1 , oil: 10 } , 'bronzeBar': { copper: 1 , tin: 1 , oil: 10 } , 'ironBar': { iron: 1 , oil: 100 } , 'silverBar': { silver: 1 , oil: 300 } , 'goldBar': { gold: 1 , oil: 1e3 } , 'promethiumBar': { promethium: 1 , charcoal: 1 } }; var PLANT_NAME = { '1': 'Dark Mushrooms' , '2': 'Red Mushrooms' , '3': 'Dotted Green Leafs' , '4': 'Green Leafs' , '5': 'Lime Leafs' , '6': 'Gold Leafs' , '7': 'Striped Gold Leafs' , '8': 'Crystal Leafs' , '9': 'Striped Crystal Leafs' , '10': 'Blewit Mushrooms' , '11': 'Snapegrass' , '12': 'Tree' , '13': 'Oak Tree' , '14': 'Wheat' , '15': 'Willow Tree' , '16': 'Grass' , '17': 'Maple Tree' , '18': 'Stardust Tree' , '19': 'Carrots' , '20': 'Tomatoes' , '21': 'Potatoes' , '22': 'Essence Tree' }; var SKILL_LIST = ['mining', 'crafting', 'woodcutting', 'farming', 'brewing', 'combat', 'fishing', 'cooking', 'magic']; var AREA_LIST = ['fields', 'forests', 'caves', 'volcano', 'northFields', 'hauntedMansion']; var AREA_NAMES = ['Fields', 'Forests', 'Caves', 'Volcano', 'Northern Fields', 'Haunted Mansion']; function getAreaName(areaId) { if (areaId === 33) { return 'Quest'; } else { return AREA_NAMES[areaId]; } } var MONSTER_NAMES = ['Chicken', 'Rat', 'Bee', 'Snake', 'Field Tree', 'Thief', 'Bear', 'Bat', 'Skeleton', 'Golem', 'Fire Bird', 'Healer', 'Lizard', 'Northern Tree', 'Ice Bird', 'Phantom', 'Ghost', 'Grim Reaper', 'Troll', 'Five Eyed', 'Stone Golem']; function getMonsterName(monsterId) { if (monsterId === 101) { return 'Ghostly Old Mage'; } else { return MONSTER_NAMES[monsterId]; } } var FISH_XP = { 'rawShrimp': 50 , 'rawSardine': 500 , 'rawSalmon': 700 , 'rawTuna': 3e3 , 'rawLobster': 5e3 , 'rawSwordfish': 5e3 , 'rawEel': 6e3 , 'rawShark': 12e3 , 'rawWhale': 20e3 , 'rawRainbowFish': 30e3 }; var BOAT_LIST = ['rowBoat', 'canoe', 'sailBoat', 'steamBoat']; var TRIP_DURATION = { 'rowBoat': 3 , 'canoe': 5 , 'sailBoat': 7 , 'steamBoat': 10 }; var MAX_ROCKET_KM = 384400; var format; (function (format) { var UNITS = [ { threshold: 10e3 , factor: 1e3 , token: 'k' } , { threshold: 1e6 , factor: 1e6 , token: 'M' } , { threshold: 1e9 , factor: 1e9 , token: 'B' } , { threshold: 1e12 , factor: 1e12 , token: 'T' } , { threshold: 1e15 , factor: 1e15 , token: 'Q' }]; var TIME_STEPS = [ { threshold: 1 , name: 'second' , short: 'sec' , padp: 0 } , { threshold: 60 , name: 'minute' , short: 'min' , padp: 0 } , { threshold: 3600 , name: 'hour' , short: 'h' , padp: 1 } , { threshold: 86400 , name: 'day' , short: 'd' , padp: 2 }]; function ensureNumber(num) { return (typeof num === 'number' ? num : Number(num)); } function number(num, shorten) { if (shorten === void 0) { shorten = false; } num = ensureNumber(num); if (shorten) { for (var i = UNITS.length - 1; i >= 0; i--) { var unit = UNITS[i]; if (num >= unit.threshold) { return number(Math.round(num / unit.factor)) + unit.token; } } } return num.toLocaleString('en'); } format.number = number; function numbersInText(text) { return text.replace(/\d(?:[\d',\.]*\d)?/g, function (numStr) { return number(numStr.replace(/\D/g, '')); }); } format.numbersInText = numbersInText; // use time format established in DHQoL (https://greasyfork.org/scripts/16041-dhqol) function timer(timer, shorten) { if (shorten === void 0) { shorten = true; } if (typeof timer === 'string') { timer = parseInt(timer, 10); } timer = Math.max(timer, 0); var days = Math.floor(timer / 86400); // 24 * 60 * 60 var hours = Math.floor((timer % 86400) / 3600); // 60 * 60 var minutes = Math.floor((timer % 3600) / 60); var seconds = timer % 60; return (shorten && days === 0 ? '' : days + 'd ') + (shorten && days === 0 && hours === 0 ? '' : zeroPadLeft(hours) + ':') + zeroPadLeft(minutes) + ':' + zeroPadLeft(seconds); } format.timer = timer; function time2NearestUnit(time, long) { if (long === void 0) { long = false; } var step = TIME_STEPS[0]; for (var i = TIME_STEPS.length - 1; i > 0; i--) { if (time >= TIME_STEPS[i].threshold) { step = TIME_STEPS[i]; break; } } var factor = Math.pow(10, step.padp); var num = Math.round(time / step.threshold * factor) / factor; var unit = long ? step.name + (num === 1 ? '' : 's') : step.short; return num + ' ' + unit; } format.time2NearestUnit = time2NearestUnit; function sec2Str(seconds) { seconds = Number(seconds); if (seconds < 0) { return seconds.toString(); } var s = seconds % 60; var m = Math.floor(seconds / 60) % 60; var h = Math.floor(seconds / 3600); var strs = []; if (h > 0) { strs.push(h + ' hour' + (h == 1 ? '' : 's')); } if (m > 0) { strs.push(m + ' minute' + (m == 1 ? '' : 's')); } if (s > 0) { strs.push(s + ' second' + (s == 1 ? '' : 's')); } if (strs.length > 1) { var glue = ' and '; for (var i = strs.length - 2; i >= 0; i--) { strs[i] = strs[i] + glue + strs[i + 1]; glue = ', '; } return strs[0]; } else { return strs[0] || ''; } } format.sec2Str = sec2Str; function min2Str(minutes) { return sec2Str(Number(minutes) * 60); } format.min2Str = min2Str; })(format || (format = {})); /** * general functions */ function getStyle(elId) { var id = elId != null ? 'style-' + elId : null; var styleElement = id != null ? document.getElementById(id) : null; if (styleElement == null) { styleElement = document.createElement('style'); if (id != null) { styleElement.id = id; } styleElement.type = 'text/css'; document.head.appendChild(styleElement); } return styleElement; } function addStyle(styleCode, elId) { var styleElement = getStyle(elId); styleElement.innerHTML += styleCode; } function zeroPadLeft(num) { return (num < 10 ? '0' : '') + num; } function capitalize(str) { return str[0].toUpperCase() + str.substr(1); } function key2Name(key, lowerCase) { if (lowerCase === void 0) { lowerCase = false; } var name = key.replace(/[A-Z]/g, function (c) { return ' ' + (lowerCase ? c.toLowerCase() : c); }); return lowerCase ? name : capitalize(name); } function pluralize(name) { return name.replace(/([^aeiou])y$/, '$1ie').replace(/s?$/, '') + 's'; } function split2Words(str, char) { if (char === void 0) { char = ' '; } return str.replace(/[A-Z]/g, char + '$&'); } function getBoundKey(key) { return 'bound' + capitalize(key); } function getTierKey(key, tierLevel) { return TIER_LEVELS[tierLevel] + capitalize(key); } function getWikiaKey(key) { return key2Name(key.replace(/^bound-?|^special-case-/i, '').replace(/\d+[km]?$/i, '')) .replace(/^\s/, '').replace(/[ -]/g, '_') .replace(/^(?:Empty|Sapphire|Emerald|Ruby|Diamond|Raw|Uncooked|Filled)_/, '') .replace(/^(?:Bronze|Iron|Silver|Gold|Promethium|Runite)_(?!Bar)/, '') .replace(/^Npc_/, 'Monster_') .replace(/_(?:Unlocked|Quest)$/, ''); } function getWikiaLink(key) { return 'http://diamondhuntonline.wikia.com/wiki/' + getWikiaKey(key); } function now() { return (new Date()).getTime(); } function ensureTooltip(id, target) { var tooltipId = 'tooltip-' + id; var tooltipEl = document.getElementById(tooltipId); if (!tooltipEl) { tooltipEl = document.createElement('div'); tooltipEl.id = tooltipId; tooltipEl.style.display = 'none'; var tooltipList = document.getElementById('tooltip-list'); tooltipList.appendChild(tooltipEl); } // ensure binded events to show the tooltip if (target.dataset.tooltipId == null) { target.dataset.tooltipId = tooltipId; win.$(target).bind( { mousemove: win.changeTooltipPosition , mouseenter: win.showTooltip , mouseleave: function (event) { var target = event.target; var parent = target.parentElement; // ensure tooltips inside an tooltip element is possible if (!!target.dataset.tooltipId && parent && !!parent.dataset.tooltipId) { win.showTooltip.call(parent, event); } else { win.hideTooltip(event); } } }); } return tooltipEl; } var timeStr2Sec = (function () { var unitFactors = { 'd': 24 * 60 * 60 , 'h': 60 * 60 , 'm': 60 , 's': 1 }; return function timeStr2Sec(str) { return str .replace(/(\d+)([hms])/g, function (wholeMatch, num, unit) { return parseInt(num) * (unitFactors[unit] || 1) + '+'; }) .split('+') .map(function (s) { return parseInt(s, 10); }) .filter(function (n) { return !isNaN(n); }) .reduce(function (p, c) { return p + c; }, 0); }; })(); function getGameValue(key) { return win[key]; } function getFurnaceLevel() { for (var i = FURNACE_LEVELS.length - 1; i >= 0; i--) { if (getGameValue(getBoundKey(FURNACE_LEVELS[i] + 'Furnace')) > 0) { return i; } } return -1; } function getFurnaceLevelName() { return FURNACE_LEVELS[getFurnaceLevel()] || ''; } function getPrice(item) { var price = win.getPrice(item); if (typeof price === 'number') { return price; } var match = price.match(/(\d+)([kM])/); if (!match) { return parseInt(price, 10); } var FACTORS = { 'k': 1e3 , 'M': 1e6 }; return parseInt(match[1], 10) * (FACTORS[match[2]] || 1); } function doGet(url) { return new Promise(function (resolve, reject) { var request = new XMLHttpRequest(); request.onreadystatechange = function (event) { if (request.readyState != XMLHttpRequest.DONE) { return; } if (request.status != 200) { return reject(event); } resolve(request.responseText); }; request.open('GET', url); request.send(); }); } function removeWhitespaceChildNodes(el) { for (var i = 0; i < el.childNodes.length; i++) { var child = el.childNodes.item(i); if (child.nodeType === Node.TEXT_NODE && /^\s*$/.test(child.textContent || '')) { el.removeChild(child); i--; } } } function debounce(func, wait, immediate) { var timeout; return function () { var _this = this; var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var callNow = immediate && !timeout; timeout && clearTimeout(timeout); timeout = setTimeout(function () { timeout = null; if (!immediate) { func.apply(_this, args); } }, wait); if (callNow) { func.apply(this, args); } }; } function passThis(fn) { return function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } return fn.apply(void 0, [this].concat(args)); }; } /** * persistence store */ var store; (function (store) { var oldPrefix = 'dh2-'; var storePrefix = 'dh2.'; function update(key, keepOldValue) { if (keepOldValue === void 0) { keepOldValue = true; } if (localStorage.hasOwnProperty(oldPrefix + key)) { if (keepOldValue) { localStorage.setItem(storePrefix + key, localStorage.getItem(oldPrefix + key)); } localStorage.removeItem(oldPrefix + key); } } var changeListener = new Map(); function changeDetected(key, oldValue, newValue) { if (changeListener.has(key)) { setTimeout(function () { changeListener.get(key).forEach(function (fn) { return fn(key, oldValue, newValue); }); }); } } function watchFn(fnName) { var _fn = localStorage[fnName]; localStorage[fnName] = function (key) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } var oldValue = localStorage.getItem(key); _fn.apply(localStorage, [key].concat(args)); var newValue = localStorage.getItem(key); if (oldValue !== newValue) { changeDetected(key, oldValue, newValue); } }; } watchFn('setItem'); watchFn('removeItem'); var _clear = localStorage.clear; localStorage.clear = function () { var oldValues = new Map(); for (var i = 0; i < localStorage.length; i++) { var key = localStorage.key(i); oldValues.set(key, localStorage.getItem(key)); } _clear(); for (var key in oldValues) { var newValue = localStorage.getItem(key); if (oldValues.get(key) !== newValue) { changeDetected(key, oldValues.get(key), newValue); } } }; function addChangeListener(key, fn) { if (!changeListener.has(key)) { changeListener.set(key, new Set()); } changeListener.get(key).add(fn); } store.addChangeListener = addChangeListener; function removeChangeListener(key, fn) { if (changeListener.has(key)) { changeListener.get(key).delete(fn); } } store.removeChangeListener = removeChangeListener; function get(key) { update(key); var value = localStorage.getItem(storePrefix + key); if (value != null) { try { return JSON.parse(value); } catch (e) {} } return value; } store.get = get; function has(key) { update(key); return localStorage.hasOwnProperty(storePrefix + key); } store.has = has; function remove(key) { update(key, false); localStorage.removeItem(storePrefix + key); } store.remove = remove; function set(key, value) { update(key, false); localStorage.setItem(storePrefix + key, JSON.stringify(value)); } store.set = set; })(store || (store = {})); var settings; (function (settings) { settings.name = 'settings'; var DIALOG_WIDTH = 450; var KEY; (function (KEY) { KEY[KEY["hideCraftingRecipes"] = 0] = "hideCraftingRecipes"; KEY[KEY["hideUselessItems"] = 1] = "hideUselessItems"; KEY[KEY["useNewChat"] = 2] = "useNewChat"; KEY[KEY["colorizeChat"] = 3] = "colorizeChat"; KEY[KEY["intelligentScrolling"] = 4] = "intelligentScrolling"; KEY[KEY["showTimestamps"] = 5] = "showTimestamps"; KEY[KEY["showIcons"] = 6] = "showIcons"; KEY[KEY["showTags"] = 7] = "showTags"; KEY[KEY["enableSpamDetection"] = 8] = "enableSpamDetection"; KEY[KEY["showNotifications"] = 9] = "showNotifications"; KEY[KEY["showEssencePopup"] = 10] = "showEssencePopup"; KEY[KEY["wikiaLinks"] = 11] = "wikiaLinks"; KEY[KEY["newXpAnimation"] = 12] = "newXpAnimation"; KEY[KEY["amountSymbol"] = 13] = "amountSymbol"; KEY[KEY["showTabTimer"] = 14] = "showTabTimer"; KEY[KEY["showLootTab"] = 15] = "showLootTab"; KEY[KEY["useEfficiencyStyle"] = 16] = "useEfficiencyStyle"; KEY[KEY["makeNumberInputs"] = 17] = "makeNumberInputs"; KEY[KEY["addKeepInput"] = 18] = "addKeepInput"; KEY[KEY["addMaxBtn"] = 19] = "addMaxBtn"; KEY[KEY["highlightUnplantableSeed"] = 20] = "highlightUnplantableSeed"; KEY[KEY["showSdChange"] = 21] = "showSdChange"; KEY[KEY["usePotionWarning"] = 22] = "usePotionWarning"; KEY[KEY["showCaptions"] = 23] = "showCaptions"; KEY[KEY["syncPriceHistory"] = 24] = "syncPriceHistory"; KEY[KEY["useNewToolbar"] = 25] = "useNewToolbar"; KEY[KEY["changeMachineDialog"] = 26] = "changeMachineDialog"; })(KEY = settings.KEY || (settings.KEY = {}));; var CFG = (_a = {} , _a[KEY.hideCraftingRecipes] = { name: 'Hide crafting recipes of finished items' , description: "Hides crafting recipes of:\n\t\t\t\t<ul style=\"margin: .5rem 0 0;\">\n\t\t\t\t\t<li>furnace, oil storage and oven recipes if they aren't better than the current level</li>\n\t\t\t\t\t<li>machines if the user has the maximum amount of this type (counts bound and unbound items)</li>\n\t\t\t\t\t<li>non-stackable items which the user already owns (counts bound and unbound items)</li>\n\t\t\t\t</ul>" , defaultValue: true } , _a[KEY.hideUselessItems] = { name: 'Hide useless items' , description: "Hides <em>unbound</em> items which may has been crafted accidentially and are of no use for the player:\n\t\t\t\t<ul style=\"margin: .5rem 0 0;\">\n\t\t\t\t\t<li>furnace, oil storage and oven recipes if they aren't better than the current level</li>\n\t\t\t\t\t<li>machines if the user has already bound the maximum amount of this type</li>\n\t\t\t\t\t<li>non-stackable items which the user has already bound</li>\n\t\t\t\t</ul>" , defaultValue: false } , _a[KEY.useNewChat] = { name: 'Use the new chat' , description: "Enables using the completely new chat with pm tabs, clickable links, clickable usernames to send a pm, intelligent scrolling and suggesting commands while typing" , defaultValue: true } , _a[KEY.colorizeChat] = { name: 'Colorize chat messages' , description: "Colorize chat messages according to a unique color for each user" , defaultValue: false , sub: { 'colorizer': { defaultValue: 0 , label: ['Equally Distributed', 'Random (light colors)', 'Random (dark colors)'] , options: ['equallyDistributed', 'random1', 'random2'] } } } , _a[KEY.intelligentScrolling] = { name: 'Intelligent scrolling' , description: "Autoscroll gets disabled when you scroll up and gets enabled again when you scroll all the way down to the bottom of the chat." , defaultValue: true } , _a[KEY.showTimestamps] = { name: 'Show timestamps' , description: "Enables showing timestamps in chat" , defaultValue: true } , _a[KEY.showIcons] = { name: 'Show user-icons' , description: "Enables showing icons (formerly sigils) for each user in chat" , defaultValue: true } , _a[KEY.showTags] = { name: 'Show user-tags' , description: "Enables showing tags (Dev, Mod, Contributor) and colors for messages in chat" , defaultValue: true } , _a[KEY.enableSpamDetection] = { name: 'Enable spam detection' , description: "Enables simple spam detection" , defaultValue: true } , _a[KEY.showNotifications] = { name: 'Show browser notifications' , description: "Shows browser notifications for enabled events (click the little gear for more options)" , defaultValue: true , sub: { 'showType': { defaultValue: 0 , label: ['only when window inactive', 'always'] , options: ['whenInactive', 'always'] } , 'smelting': { defaultValue: true , label: 'Smelting finishes' } , 'chopping': { defaultValue: true , label: 'A tree is fully grown' } , 'harvest': { defaultValue: true , label: 'A plant can be harvested' } , 'potionEffect': { defaultValue: true , label: 'A potion\'s effect ends' } , 'boatReturned': { defaultValue: true , label: 'A boat returns' } , 'heroReady': { defaultValue: true , label: 'The hero is fully recovered and ready to fight' } , 'itemsSold': { defaultValue: true , label: 'Items are sold on the market' } , 'pirate': { defaultValue: true , label: 'A pirate has found a treasure map' } , 'essence': { defaultValue: true , label: 'An essence was found' } , 'rocket': { defaultValue: true , label: 'The rocket has landed on the moon or earth' } , 'wind': { defaultValue: true , label: 'The wind for the sail boat has changed' } , 'perk': { defaultValue: true , label: 'A new perk is unlocked (achievement set completed)' } , 'pm': { defaultValue: true , label: 'A private messages (pm) arrives' } , 'mention': { defaultValue: true , label: 'The username is mentioned in chat' } , 'keyword': { defaultValue: true , label: 'A keyword is mentioned in chat' } , 'serverMsg': { defaultValue: true , label: 'Server messages (like <em>Server is restarting...</em>)' } } } , _a[KEY.showEssencePopup] = { name: 'Show essence popup' , description: "Shown a popup (like the ones when a diamond is found or the server is restarting) for finding an essence" , defaultValue: false } , _a[KEY.wikiaLinks] = { name: 'Show wikia links' , description: "Show wikia links for every item on hover (the little icon in the upper left corner)" , defaultValue: true } , _a[KEY.newXpAnimation] = { name: 'New XP-gain animation' , description: "Show gained xp on top skill bar instead on the position of the mouse" , defaultValue: true } , _a[KEY.amountSymbol] = { name: 'Show \u00D7 on items' , description: "Show a tiny \u00D7-symbol before amount numbers of items" , defaultValue: true } , _a[KEY.showTabTimer] = { name: 'Show tab timer and info' , description: "Show timer on tabs for trees, plants and hero" , defaultValue: true } , _a[KEY.showLootTab] = { name: 'Show sub tab for loot table' , description: "Show a sub tab for combat drop table in combat" , defaultValue: true } , _a[KEY.useEfficiencyStyle] = { name: 'Use space efficient style' , description: "Use a space efficient style with less blank space" , defaultValue: false } , _a[KEY.makeNumberInputs] = { name: 'Turn text inputs into number inputs' , description: "Number inputs allow you to change the amount via arrow buttons" , defaultValue: true } , _a[KEY.addKeepInput] = { name: 'Add keep input for selling to npc shop' , description: "A keep input allows you to set the amount of items you want to keep when selling" , defaultValue: true } , _a[KEY.addMaxBtn] = { name: 'Add max button for some crafting inputs' , description: "Add max button for crafting (e.g. vials), brewing potions and cooking food" , defaultValue: true } , _a[KEY.highlightUnplantableSeed] = { name: 'Show whether a seed can be planted' , description: "Fades the item box of a seed when it's not plantable" , defaultValue: true } , _a[KEY.showSdChange] = { name: 'Show stardust change' , description: "Shows the amount of stardust earned or spent in the last tick" , defaultValue: true } , _a[KEY.usePotionWarning] = { name: 'Use drink warning for active potions' , description: "Disable drink button for 3 seconds if the potion is already active" , defaultValue: true } , _a[KEY.showCaptions] = { name: 'Show item captions' , description: "Show item captions for some items instead of the number of owned items" , defaultValue: true } , _a[KEY.syncPriceHistory] = { name: 'Sync price history' , description: "Synchronize the local price history" , defaultValue: false , sub: { 'url': { defaultValue: '' , label: 'paste url here' } } } , _a[KEY.useNewToolbar] = { name: 'Use new toolbar' , description: "Use new reordered toolbar" , defaultValue: true , requiresReload: true } , _a[KEY.changeMachineDialog] = { name: 'Use slider for machine dialog' , description: "Change buttons in machine dialog into slider" , defaultValue: true , requiresReload: true } , _a); var SETTINGS_TABLE_ID = 'dh2-settings'; var SETTING_ID_PREFIX = 'dh2-setting-'; var settings2Init = Object.keys(CFG); /** * settings */ function toName(key, subKey) { var name = typeof key === 'string' ? key : KEY[key]; if (subKey !== undefined) { return name + '.' + subKey; } return name; } function getStoreKey(key, subKey) { return 'setting.' + toName(key, subKey); } var observedSettings = new Map(); var observedSubSettings = new Map(); function observe(key, fn) { var n = toName(key); if (!observedSettings.has(n)) { observedSettings.set(n, new Set()); } observedSettings.get(n).add(fn); } settings.observe = observe; function observeSub(key, subKey, fn) { var n = toName(key, subKey); if (!observedSubSettings.has(n)) { observedSubSettings.set(n, new Set()); } observedSubSettings.get(n).add(fn); } settings.observeSub = observeSub; function unobserve(key, fn) { var n = toName(key); if (!observedSettings.has(n)) { return false; } return observedSettings.get(n).delete(fn); } settings.unobserve = unobserve; function unobserveSub(key, subKey, fn) { var n = toName(key, subKey); if (!observedSubSettings.has(n)) { return false; } return observedSubSettings.get(n).delete(fn); } settings.unobserveSub = unobserveSub; var settingsProxies = new Map(); function get(key) { if (!CFG.hasOwnProperty(key)) { return false; } if (settingsProxies.has(key)) { var proxy = settingsProxies.get(key); return proxy.get(key); } var name = getStoreKey(key); return store.has(name) ? store.get(name) : CFG[key].defaultValue; } settings.get = get; function getSub(key, subKey) { if (!CFG.hasOwnProperty(key)) { return null; } var name = getStoreKey(key, subKey); var def = CFG[key].sub[subKey].defaultValue; if (store.has(name)) { var stored = store.get(name); if (def instanceof Array) { for (var i = 0; i < def.length; i++) { if (stored.indexOf(def[i]) === -1) { stored.push(def[i]); } } for (var i = 0; i < stored.length; i++) { if (def.indexOf(stored[i]) === -1) { stored.splice(i, 1); i--; } } } return stored; } else { return def; } } settings.getSub = getSub; function set(key, newValue) { if (!CFG.hasOwnProperty(key)) { return; } var oldValue = get(key); var n = toName(key); if (settingsProxies.has(key)) { var proxy = settingsProxies.get(key); proxy.set(key, oldValue, newValue); } else { store.set(getStoreKey(key), newValue); } if (oldValue !== newValue && observedSettings.has(n)) { observedSettings.get(n).forEach(function (fn) { return fn(key, oldValue, newValue); }); } } settings.set = set; function setSub(key, subKey, newValue) { if (!CFG.hasOwnProperty(key)) { return; } var oldValue = getSub(key, subKey); var n = toName(key, subKey); store.set(getStoreKey(key, subKey), newValue); if (oldValue !== newValue && observedSubSettings.has(n)) { observedSubSettings.get(n).forEach(function (fn) { return fn(key, subKey, oldValue, newValue); }); } } settings.setSub = setSub; function getSubCfg(key) { if (!CFG.hasOwnProperty(key)) { return; } return CFG[key].sub; } settings.getSubCfg = getSubCfg; function initSettingsStyle() { addStyle("\ntable.table-style1 tr:not([onclick])\n{\n\tcursor: initial;\n}\n#tab-container-profile h2.section-title\n{\n\tcolor: orange;\n\tline-height: 1.2rem;\n\tmargin-top: 2rem;\n}\n#tab-container-profile h2.section-title > a.version\n{\n\tcolor: orange;\n\tfont-size: 1.2rem;\n\ttext-decoration: none;\n}\n#tab-container-profile h2.section-title > a.version:hover\n{\n\tcolor: white;\n\ttext-decoration: underline;\n}\n#tab-container-profile h2.section-title > span.note\n{\n\tfont-size: 0.9rem;\n}\n#" + SETTINGS_TABLE_ID + " tr.reload td:first-child::after\n{\n\tcontent: '*';\n\tfont-weight: bold;\n\tmargin-left: 3px;\n}\n#" + SETTINGS_TABLE_ID + " tr.sub td\n{\n\tposition: relative;\n}\n#" + SETTINGS_TABLE_ID + " tr.sub td button:last-child\n{\n\tmargin: -1px;\n\tposition: absolute;\n\tright: 0;\n}\n\n.ui-dialog-content > h2:first-child\n{\n\tmargin-top: 0;\n}\n\n.settings-container\n{\n\tlist-style: none;\n\tmargin: 5px 30px;\n\tpadding: 0;\n}\n.ui-dialog-content .settings-container\n{\n\tmargin: 5px 0;\n}\n.settings-container > li.setting\n{\n\tbackground-color: silver;\n\tborder: 1px solid black;\n\tborder-left: 0;\n\tborder-right: 0;\n\tborder-top-width: 0;\n\tdisplay: flex;\n}\n.settings-container > li.setting:first-child\n{\n\tborder-top-width: 1px;\n}\n.ui-dialog-content .settings-container > li.setting,\n.ui-dialog-content .settings-container > li.setting:hover\n{\n\tbackground-color: transparent;\n\tborder: 0;\n\tmargin: .25rem 0;\n}\n.settings-container > li.setting,\n.settings-container > li.setting *\n{\n\tcursor: pointer;\n\t-webkit-user-select: none;\n\t-moz-user-select: none;\n\t-ms-user-select: none;\n\tuser-select: none;\n}\n.settings-container > li.setting:hover\n{\n\tbackground-color: gray;\n}\n.settings-container > li.setting > input[type=\"checkbox\"]\n{\n\tdisplay: none;\n}\n.settings-container > li.setting > label\n{\n\tdisplay: block;\n\tflex-grow: 1;\n\tpadding: .25rem .5rem;\n}\n.settings-container > li.setting > label.ui-checkboxradio-label\n{\n\ttext-align: left;\n}\n.settings-container > li.setting > label.ui-checkboxradio-label .ui-checkboxradio-icon-space\n{\n\tmargin-right: .25rem;\n}\n.settings-container > li.setting > input + label:not(.ui-checkboxradio-label)::before\n{\n\tbackground-image: url(images/icons/x.png);\n\tbackground-size: 20px;\n\tcontent: '';\n\tdisplay: inline-block;\n\theight: 20px;\n\tmargin: 0 .25rem;\n\twidth: 20px;\n\tvertical-align: middle;\n}\n.settings-container > li.setting > input:checked + label:not(.ui-checkboxradio-label)::before\n{\n\tbackground-image: url(images/icons/check.png);\n}\n.ui-dialog-content .settings-container > li.setting > label + button\n{\n\tmargin-left: -.2rem;\n\tz-index: 1;\n}\n.settings-container.sortable > li.setting > span.ui-icon.handle\n{\n\tfloat: left;\n\tmargin: 6px 10px;\n\tz-index: 10;\n}\n.settings-container > li.setting span.ui-selectmenu-button\n{\n\twidth: calc(100% - 2em - 2*3px + 2*.1em);\n}\n.settings-container > li.setting > button.ui-button\n{\n\twidth: 100%;\n}\n.ui-textfield\n{\n\tbackground: none;\n\tcolor: inherit;\n\tcursor: text;\n\tfont: inherit;\n\toutline: none;\n\ttext-align: inherit;\n}\n.ui-textfield.ui-state-active,\n.ui-widget-content .ui-textfield.ui-state-active,\n.ui-widget-header .ui-textfield.ui-state-active,\n.ui-button.ui-textfield:active,\n.ui-button.ui-textfield.ui-state-active:hover\n{\n\tbackground: transparent;\n\tborder: 1px solid #c5c5c5;\n\tcolor: #333333;\n\tfont-weight: normal;\n}\n.settings-container.list > li\n{\n\tborder: 1px solid #c5c5c5;\n\tborder-radius: 3px;\n\tdisplay: flex;\n\tmargin: 5px 0;\n}\n.settings-container.list > li > span.content\n{\n\tflex: 1 0 auto;\n\tline-height: 2rem;\n\tmargin: 0 5px 0 1rem;\n}\n.settings-container.list > li > button.ui-button\n{\n\tmargin: -1px;\n}\n.instruction\n{\n\tcursor: default;\n\t-webkit-user-select: none;\n\t-moz-user-select: none;\n\t-ms-user-select: none;\n\tuser-select: none;\n}\n.instruction code,\n.instruction a\n{\n\tcursor: initial;\n\t-webkit-user-select: text;\n\t-moz-user-select: text;\n\t-ms-user-select: text;\n\tuser-select: text;\n}\n.instruction code\n{\n\tbackground-color: lightgray;\n\tdisplay: inline-block;\n\tpadding: .25rem;\n}\n\t\t"); } function getSettingId(key, subKey) { var name = toName(key) + (subKey !== undefined ? '-' + subKey : ''); return SETTING_ID_PREFIX + split2Words(name, '-').toLowerCase(); } function initSettingTable() { function insertAfter(newChild, oldChild) { var parent = oldChild.parentElement; if (oldChild.nextElementSibling == null) { parent.appendChild(newChild); } else { parent.insertBefore(newChild, oldChild.nextElementSibling); } } function getCheckImageSrc(value) { return 'images/icons/' + (value ? 'check' : 'x') + '.png'; } var profileTable = document.getElementById('profile-toggleTable'); if (!profileTable) { return; } var settingsHeader = document.createElement('h2'); settingsHeader.className = 'section-title'; settingsHeader.innerHTML = "Userscript \"DH2 Fixed\" <a class=\"version\" href=\"https://greasyfork.org/scripts/27642-dh2-fixed\" target=\"_blank\">v" + version + "</a><br>\n\t\t\t<span class=\"note\" style=\"display: none;\">(* changes require reloading the tab)</span>"; var requiresReloadNote = settingsHeader.querySelector('.note'); insertAfter(settingsHeader, profileTable); var settingsTable = document.createElement('table'); settingsTable.id = SETTINGS_TABLE_ID; settingsTable.className = 'table-style1'; settingsTable.width = '40%'; settingsTable.innerHTML = "\n\t\t<tr style=\"background-color:grey;\">\n\t\t\t<th>Setting</th>\n\t\t\t<th>Enabled</th>\n\t\t</tr>\n\t\t"; function addRowClickListener(row, key, settingId) { row.addEventListener('click', function () { var newValue = !get(key); set(key, newValue); document.getElementById(settingId).src = getCheckImageSrc(newValue); }); } function addSubClickListener(btn, dialog) { btn.addEventListener('click', function (event) { initJQueryDialog(dialog); event.stopPropagation(); event.preventDefault(); }); } for (var _i = 0, settings2Init_1 = settings2Init; _i < settings2Init_1.length; _i++) { var k = settings2Init_1[_i]; // convert it into a KEY var key = parseInt(k, 10); var setting = CFG[key]; if (setting == null) { console.error('missing setting entry:', key, toName(key)); continue; } var settingId = getSettingId(key); var row = settingsTable.insertRow(-1); row.classList.add('setting'); if (setting.requiresReload) { row.classList.add('reload'); requiresReloadNote.style.display = ''; } row.setAttribute('onclick', ''); row.innerHTML = "\n\t\t\t<td>" + setting.name + "</td>\n\t\t\t<td><img src=\"" + getCheckImageSrc(get(key)) + "\" id=\"" + settingId + "\" class=\"image-icon-20\"></td>\n\t\t\t"; if (setting.sub) { row.classList.add('sub'); var subBtn = document.createElement('button'); subBtn.innerHTML = "<img src=\"images/icons/gearOff.gif\" class=\"image-icon-15\">"; row.cells.item(0).appendChild(subBtn); var dialog = createSubSettingDialog(key); addSubClickListener(subBtn, dialog); } var tooltipEl = ensureTooltip(settingId, row); tooltipEl.innerHTML = setting.description; if (setting.requiresReload) { tooltipEl.innerHTML += "<span style=\"color: hsla(20, 100%, 50%, 1); font-size: .9rem; display: block; margin-top: 0.5rem;\">You have to reload the browser tab to apply changes to this setting.</span>"; } addRowClickListener(row, key, settingId); } insertAfter(settingsTable, settingsHeader); } function initProxies() { var row = document.querySelector('tr[data-tooltip-id="tooltip-profile-removeCraftingFilter"]'); if (row) { var valueCache_1 = getGameValue('profileRemoveCraftingFilter') != 1; settingsProxies.set(KEY.hideCraftingRecipes , { get: function (key) { return getGameValue('profileRemoveCraftingFilter') != 1; } , set: function (key, oldValue, newValue) { if (valueCache_1 != newValue) { row.click(); valueCache_1 = newValue; } } }); observer.add('profileRemoveCraftingFilter', function () { set(KEY.hideCraftingRecipes, getGameValue('profileRemoveCraftingFilter') != 1); }); } } var subDialog; (function (subDialog) { function defaultHandler(key, dialog) { var setting = CFG[key]; var subSettings = setting.sub; var settingContainer = createSubSettingsContainer(key, subSettings); dialog.appendChild(settingContainer); } function colorizeChat(dialog) { defaultHandler(KEY.colorizeChat, dialog); } subDialog.colorizeChat = colorizeChat; function showNotifications(dialog) { dialog.appendChild(document.createTextNode('Show notifications\u2026')); defaultHandler(KEY.showNotifications, dialog); dialog.appendChild(document.createTextNode('Events for which notifications are shown:')); var ulNotifType = dialog.lastElementChild; var ulEvents = ulNotifType.cloneNode(false); while (ulNotifType.children.length > 1) { ulEvents.appendChild(ulNotifType.children.item(1)); } dialog.appendChild(ulEvents); } subDialog.showNotifications = showNotifications; function syncPriceHistory(dialog) { var setting = CFG[KEY.syncPriceHistory]; var subSettings = setting.sub; var instructionEl = document.createElement('div'); instructionEl.className = 'instruction'; instructionEl.innerHTML = "Go to <a href=\"http://myjson.com/\" target=\"_blank\">http://myjson.com/</a>, insert <code>{}</code> and press \"<em>Save</em>\". Then copy the URL of the created store (e.g. <code>http://myjson.com/ltk51</code>) and insert it into the following input:"; dialog.appendChild(instructionEl); var settingContainer = createSubSettingsContainer(KEY.syncPriceHistory, subSettings); dialog.appendChild(settingContainer); } subDialog.syncPriceHistory = syncPriceHistory; })(subDialog || (subDialog = {})); function createSubSettingDialog(key) { var settingId = getSettingId(key); var setting = CFG[key]; var dialog = document.createElement('div'); dialog.id = 'dialog-' + settingId; dialog.style.display = 'none'; dialog.innerHTML = "<h2>" + setting.name + "</h2>"; var name = toName(key); if (subDialog.hasOwnProperty(name)) { subDialog[name](dialog); } else { console.warn('missing setting handler for "%s"', name); var todoEl = document.createElement('span'); todoEl.textContent = 'TODO'; dialog.appendChild(todoEl); } document.body.appendChild(dialog); return dialog; } function createSubSettingsContainer(parentKey, subSettings) { var settingsContainer = document.createElement('ul'); settingsContainer.className = 'settings-container'; function addCheckbox(listEl, subKey, id, setting) { var checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.id = id; checkbox.name = id; checkbox.checked = getSub(parentKey, subKey); var label = document.createElement('label'); label.htmlFor = id; label.innerHTML = setting.label; checkbox.addEventListener('change', function () { return setSub(parentKey, subKey, checkbox.checked); }); listEl.appendChild(checkbox); listEl.appendChild(label); } function addSelectmenu(listEl, subKey, id, setting) { var select = document.createElement('select'); select.id = id; select.name = id; var options = setting.options; var selectedIndex = getSub(parentKey, subKey); for (var i = 0; i < options.length; i++) { var option = document.createElement('option'); option.value = options[i]; if (setting.label) { option.innerHTML = setting.label[i]; } else { option.innerHTML = key2Name(options[i]); } option.selected = i == selectedIndex; select.appendChild(option); } select.addEventListener('change', function () { return setSub(parentKey, subKey, select.selectedIndex); }); listEl.appendChild(select); } function addInput(listEl, subKey, id, setting) { var input = document.createElement('input'); input.type = 'text'; input.placeholder = setting.label || ''; input.value = getSub(parentKey, subKey); var onChange = function () { return setSub(parentKey, subKey, input.value); }; input.addEventListener('click', onChange); input.addEventListener('change', onChange); input.addEventListener('keyup', onChange); listEl.appendChild(input); } var keyList = Object.keys(subSettings); var orderIndex = keyList.findIndex(function (k) { return subSettings[k].defaultValue instanceof Array; }); var isSortable = orderIndex != -1; if (isSortable) { keyList = getSub(parentKey, keyList[orderIndex]); } for (var _i = 0, keyList_1 = keyList; _i < keyList_1.length; _i++) { var subKey = keyList_1[_i]; var settingId = getSettingId(parentKey, subKey); var setting = subSettings[subKey]; var listEl = document.createElement('li'); listEl.classList.add('setting'); if (isSortable) { listEl.dataset.subKey = subKey; var sortableIcon = document.createElement('span'); sortableIcon.className = 'ui-icon ui-icon-arrowthick-2-n-s handle'; listEl.appendChild(sortableIcon); } if (setting.options) { addSelectmenu(listEl, subKey, settingId, setting); } else if (typeof setting.defaultValue === 'boolean') { addCheckbox(listEl, subKey, settingId, setting); } else if (typeof setting.defaultValue === 'string') { addInput(listEl, subKey, settingId, setting); } settingsContainer.appendChild(listEl); } return settingsContainer; } function initJQueryDialog(dialog) { var $dialog = win.$(dialog); $dialog.dialog( { width: DIALOG_WIDTH + 'px' }); $dialog.find('input[type="checkbox"]').checkboxradio() .next().children(':first-child').removeClass('ui-state-hover'); $dialog.find('button:not(.sub)').button(); $dialog.find('input:text').button() .addClass('ui-textfield') .off('mouseenter').off('mousedown').off('keydown'); $dialog.find('select').selectmenu( { change: function (event, ui) { var changeEvent = document.createEvent('HTMLEvents'); changeEvent.initEvent('change', false, true); event.target.dispatchEvent(changeEvent); } }); $dialog.find('.sortable').sortable( { handle: '.handle' , update: function (event, ui) { var newOrder = []; var children = event.target.children; for (var i = 0; i < children.length; i++) { var child = children[i]; newOrder.push(child.dataset.subKey); } var updateEvent = new CustomEvent('sortupdate' , { detail: newOrder }); event.target.dispatchEvent(updateEvent); } }); return $dialog; } function createSettingsContainer(settingList) { var settingsContainer = document.createElement('ul'); settingsContainer.className = 'settings-container'; function addOpenDialogClickListener(el, dialog) { el.addEventListener('click', function (event) { initJQueryDialog(dialog); event.stopPropagation(); event.preventDefault(); }); } function addChangeListener(key, checkbox) { checkbox.addEventListener('change', function () { set(key, checkbox.checked); }); } for (var _i = 0, settingList_1 = settingList; _i < settingList_1.length; _i++) { var key = settingList_1[_i]; var settingId = getSettingId(key); var setting = CFG[key]; var index = settings2Init.indexOf(key.toString()); if (index != -1) { settings2Init.splice(index, 1); } var listEl = document.createElement('li'); listEl.classList.add('setting'); if (setting.requiresReload) { listEl.classList.add('reload'); } var checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.id = settingId; checkbox.checked = get(key); var label = document.createElement('label'); label.htmlFor = settingId; label.textContent = setting.name; addChangeListener(key, checkbox); listEl.appendChild(checkbox); listEl.appendChild(label); if (setting.sub) { var moreBtn = document.createElement('button'); moreBtn.className = 'sub'; moreBtn.innerHTML = "<img src=\"images/icons/gearOff.gif\" class=\"image-icon-20\" />"; listEl.appendChild(moreBtn); var dialog = createSubSettingDialog(key); addOpenDialogClickListener(moreBtn, dialog); } settingsContainer.appendChild(listEl); var tooltipEl = ensureTooltip(settingId, listEl); tooltipEl.innerHTML = setting.description; if (setting.requiresReload) { tooltipEl.innerHTML += "<span style=\"color: hsla(20, 100%, 50%, 1); font-size: .9rem; display: block; margin-top: 0.5rem;\">You have to reload the browser tab to apply changes to this setting.</span>"; } } return settingsContainer; } function initCraftingSettings() { var craftingItems = document.getElementById('tab-sub-container-crafting'); if (!craftingItems) { return; } var br = craftingItems.nextElementSibling; var after = br.nextElementSibling; var parent = after.parentElement; var settingList = [KEY.hideCraftingRecipes, KEY.hideUselessItems]; var settingsContainer = createSettingsContainer(settingList); parent.insertBefore(settingsContainer, after); } function initMuteDialog(settingsContainer) { // muted people dialog var dialog = document.createElement('div'); dialog.id = 'dialog-chat-muted-people'; dialog.style.display = 'none'; dialog.innerHTML = "<h2>Muted people</h2>"; var input = document.createElement('input'); input.type = 'text'; input.placeholder = 'username'; dialog.appendChild(input); var addBtn = document.createElement('button'); addBtn.textContent = '+'; dialog.appendChild(addBtn); var listEl = document.createElement('ul'); listEl.className = 'settings-container list'; var username2Item = {}; var username2Btn = {}; function removeListener(event) { var target = event.target; var username = target.dataset.username || ''; var index = win.mutedPeople.indexOf(username); if (index !== -1) { win.mutedPeople.splice(index, 1); } } function add2List(username) { var item = document.createElement('li'); item.innerHTML = "<span class=\"content\">" + username + "</span>"; var removeBtn = document.createElement('button'); removeBtn.dataset.username = username; removeBtn.textContent = '-'; win.$(removeBtn).button(); removeBtn.addEventListener('click', removeListener); username2Btn[username] = removeBtn; item.appendChild(removeBtn); username2Item[username] = item; listEl.appendChild(item); } var _push = win.mutedPeople.push; win.mutedPeople.push = function () { var items = []; for (var _i = 0; _i < arguments.length; _i++) { items[_i] = arguments[_i]; } items.forEach(function (username) { return add2List(username); }); return _push.call.apply(_push, [win.mutedPeople].concat(items)); }; var _splice = win.mutedPeople.splice; win.mutedPeople.splice = function (start, deleteCount) { var items = []; for (var _i = 2; _i < arguments.length; _i++) { items[_i - 2] = arguments[_i]; } for (var i = 0; i < deleteCount; i++) { var username = win.mutedPeople[start + i]; var item = username2Item[username]; delete username2Item[username]; listEl.removeChild(item); var btn = username2Btn[username]; delete username2Btn[username]; btn.removeEventListener('click', removeListener); } items.forEach(function (username) { return add2List(username); }); return _splice.call.apply(_splice, [win.mutedPeople, start, deleteCount].concat(items)); }; dialog.appendChild(listEl); addBtn.addEventListener('click', function () { win.mutedPeople.push(input.value); input.value = ''; }); document.body.appendChild(dialog); var listItem = document.createElement('li'); listItem.classList.add('setting'); var dialogBtn = document.createElement('button'); dialogBtn.innerHTML = "List of muted people"; dialogBtn.addEventListener('click', function () { initJQueryDialog(dialog); }); listItem.appendChild(dialogBtn); settingsContainer.appendChild(listItem); } function initKeywordDialog(settingsContainer) { // keyword dialog var dialog = document.createElement('div'); dialog.id = 'dialog-chat-keyword-list'; dialog.style.display = 'none'; dialog.innerHTML = "<h2>Keywords</h2>"; var input = document.createElement('input'); input.type = 'text'; input.placeholder = 'keyword'; dialog.appendChild(input); var addBtn = document.createElement('button'); addBtn.textContent = '+'; dialog.appendChild(addBtn); var listEl = document.createElement('ul'); listEl.className = 'settings-container list'; function add2List(keyword) { var item = document.createElement('li'); item.innerHTML = "<span class=\"content\">" + keyword + "</span>"; var removeBtn = document.createElement('button'); removeBtn.textContent = '-'; win.$(removeBtn).button(); var remove = function () { if (chat.removeKeyword(keyword)) { listEl.removeChild(item); removeBtn.removeEventListener('click', remove); } }; removeBtn.addEventListener('click', remove); item.appendChild(removeBtn); listEl.appendChild(item); } // add all keywords chat.keywordList.forEach(function (keyword) { return add2List(keyword); }); dialog.appendChild(listEl); addBtn.addEventListener('click', function () { var keyword = input.value; if (chat.addKeyword(keyword)) { add2List(keyword); input.value = ''; } }); document.body.appendChild(dialog); var listItem = document.createElement('li'); listItem.classList.add('setting'); var dialogBtn = document.createElement('button'); dialogBtn.innerHTML = "Manage list of keywords"; dialogBtn.addEventListener('click', function () { initJQueryDialog(dialog); }); listItem.appendChild(dialogBtn); settingsContainer.appendChild(listItem); } function initChatSettings() { var controlDiv = document.querySelector('#div-chat > div:first-child'); if (!controlDiv) { return; } var btn = document.createElement('button'); btn.textContent = 'Chat Settings'; controlDiv.appendChild(btn); var dialog = document.createElement('div'); dialog.id = 'dialog-chat-settings'; dialog.style.display = 'none'; dialog.innerHTML = "<h2>Chat Settings</h2>"; var settingList = [KEY.useNewChat, KEY.colorizeChat, KEY.intelligentScrolling, KEY.showTimestamps, KEY.showIcons, KEY.showTags, KEY.enableSpamDetection]; var settingsContainer = createSettingsContainer(settingList); initMuteDialog(settingsContainer); initKeywordDialog(settingsContainer); dialog.appendChild(settingsContainer); document.body.appendChild(dialog); btn.addEventListener('click', function () { initJQueryDialog(dialog); }); } function init() { initProxies(); initSettingsStyle(); initCraftingSettings(); initChatSettings(); initSettingTable(); } settings.init = init; var _a; })(settings || (settings = {})); /** * Code from https://github.com/davidmerfield/randomColor */ var colorGenerator; (function (colorGenerator) { // seed to get repeatable colors var seed = null; var COLOR_NOT_FOUND = { hueRange: [] , lowerBounds: [] , saturationRange: [] , brightnessRange: [] }; var COLOR_BOUNDS = { 'monochrome': { hueRange: [] , lowerBounds: [ [0, 0] , [100, 0] ] } , 'red': { hueRange: [-26, 18] , lowerBounds: [ [20, 100] , [30, 92] , [40, 89] , [50, 85] , [60, 78] , [70, 70] , [80, 60] , [90, 55] , [100, 50] ] } , 'orange': { hueRange: [19, 46] , lowerBounds: [ [20, 100] , [30, 93] , [40, 88] , [50, 86] , [60, 85] , [70, 70] , [100, 70] ] } , 'yellow': { hueRange: [47, 62] , lowerBounds: [ [25, 100] , [40, 94] , [50, 89] , [60, 86] , [70, 84] , [80, 82] , [90, 80] , [100, 75] ] } , 'green': { hueRange: [63, 178] , lowerBounds: [ [30, 100] , [40, 90] , [50, 85] , [60, 81] , [70, 74] , [80, 64] , [90, 50] , [100, 40] ] } , 'blue': { hueRange: [179, 257] , lowerBounds: [ [20, 100] , [30, 86] , [40, 80] , [50, 74] , [60, 60] , [70, 52] , [80, 44] , [90, 39] , [100, 35] ] } , 'purple': { hueRange: [258, 282] , lowerBounds: [ [20, 100] , [30, 87] , [40, 79] , [50, 70] , [60, 65] , [70, 59] , [80, 52] , [90, 45] , [100, 42] ] } , 'pink': { hueRange: [283, 334] , lowerBounds: [ [20, 100] , [30, 90] , [40, 86] , [60, 84] , [80, 80] , [90, 75] , [100, 73] ] } }; // shared color dictionary var colorDictionary = {}; function defineColor(name, hueRange, lowerBounds) { var _a = lowerBounds[0] , sMin = _a[0] , bMax = _a[1]; var _b = lowerBounds[lowerBounds.length - 1] , sMax = _b[0] , bMin = _b[1]; colorDictionary[name] = { hueRange: hueRange , lowerBounds: lowerBounds , saturationRange: [sMin, sMax] , brightnessRange: [bMin, bMax] }; } function loadColorBounds() { for (var name_1 in COLOR_BOUNDS) { defineColor(name_1, COLOR_BOUNDS[name_1].hueRange, COLOR_BOUNDS[name_1].lowerBounds); } } function randomWithin(min, max) { if (min === void 0) { min = 0; } if (max === void 0) { max = 0; } if (seed === null) { return Math.floor(min + Math.random() * (max + 1 - min)); } else { // seeded random algorithm from http://indiegamr.com/generate-repeatable-random-numbers-in-js/ seed = (seed * 9301 + 49297) % 233280; var rnd = seed / 233280.0; return Math.floor(min + rnd * (max - min)); } } function getColorInfo(hue) { // maps red colors to make picking hue easier if (hue >= 334 && hue <= 360) { hue -= 360; } for (var colorName in colorDictionary) { var color = colorDictionary[colorName]; if (color.hueRange.length > 0 && hue >= color.hueRange[0] && hue <= color.hueRange[1]) { return colorDictionary[colorName]; } } return COLOR_NOT_FOUND; } function getHueRange(colorInput) { var number = typeof colorInput === 'undefined' ? Number.NaN : colorInput; if (typeof number === 'string') { number = parseInt(number, 10); } if (colorInput && isNaN(number) && colorDictionary.hasOwnProperty(colorInput)) { var color = colorDictionary[colorInput]; if (color.hueRange.length > 0) { return color.hueRange; } } else if (!isNaN(number) && number < 360 && number > 0) { return [number, number]; } return [0, 360]; } function pickHue(options) { var hueRange = getHueRange(options.hue); var hue = randomWithin(hueRange[0], hueRange[1]); // instead of storing red as two seperate ranges, we group them, using negative numbers if (hue < 0) { return 360 + hue; } return hue; } function getSaturationRange(hue) { return getColorInfo(hue).saturationRange; } function pickSaturation(hue, options) { if (options.luminosity === 'random') { return randomWithin(0, 100); } if (options.hue === 'monochrome') { return 0; } var _a = getSaturationRange(hue) , sMin = _a[0] , sMax = _a[1]; switch (options.luminosity) { case 'bright': sMin = 55; break; case 'dark': sMin = sMax - 10; break; case 'light': sMax = 55; break; } return randomWithin(sMin, sMax); } function getMinimumBrightness(H, S) { var lowerBounds = getColorInfo(H).lowerBounds; for (var i = 0; i < lowerBounds.length - 1; i++) { var _a = lowerBounds[i] , s1 = _a[0] , v1 = _a[1]; var _b = lowerBounds[i + 1] , s2 = _b[0] , v2 = _b[1]; if (S >= s1 && S <= s2) { var m = (v2 - v1) / (s2 - s1); var b = v1 - m * s1; return m * S + b; } } return 0; } function pickBrightness(H, S, options) { var bMin = getMinimumBrightness(H, S); var bMax = 100; switch (options.luminosity) { case 'dark': bMax = bMin + 20; break; case 'light': bMin = (bMax + bMin) / 2; break; case 'random': bMin = 0; bMax = 100; break; } return randomWithin(bMin, bMax); } var HSVColor = (function () { function HSVColor(H, S, V) { this.H = H; this.S = S; this.V = V; } HSVColor.fromHSVArray = function (hsv) { return new HSVColor(hsv[0], hsv[1], hsv[2]); }; HSVColor.prototype.toHex = function () { var rgb = this.toRGB(); return '#' + this.componentToHex(rgb[0]) + this.componentToHex(rgb[1]) + this.componentToHex(rgb[2]); }; HSVColor.prototype.toHSL = function () { var h = this.H; var s = this.S / 100; var v = this.V / 100; var k = (2 - s) * v; return [ h , Math.round(s * v / (k < 1 ? k : 2 - k) * 10e3) / 100 , k / 2 * 100 ]; }; HSVColor.prototype.toHSLString = function (alpha) { var hsl = this.toHSL(); if (alpha !== undefined) { return "hsla(" + hsl[0] + ", " + hsl[1] + "%, " + hsl[2] + "%, " + alpha + ")"; } else { return "hsl(" + hsl[0] + ", " + hsl[1] + "%, " + hsl[2] + "%)"; } }; HSVColor.prototype.toRGB = function () { // this doesn't work for the values of 0 and 360 here's the hacky fix var h = Math.min(Math.max(this.H, 1), 359); // Rebase the h,s,v values h = h / 360; var s = this.S / 100; var v = this.V / 100; var h_i = Math.floor(h * 6); var f = h * 6 - h_i; var p = v * (1 - s); var q = v * (1 - f * s); var t = v * (1 - (1 - f) * s); var r = 256; var g = 256; var b = 256; switch (h_i) { case 0: r = v; g = t; b = p; break; case 1: r = q; g = v; b = p; break; case 2: r = p; g = v; b = t; break; case 3: r = p; g = q; b = v; break; case 4: r = t; g = p; b = v; break; case 5: r = v; g = p; b = q; break; } return [Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)]; }; HSVColor.prototype.toRGBString = function (alpha) { var rgb = this.toRGB(); if (alpha !== undefined) { return "rgba(" + rgb.join(', ') + ", " + alpha + ")"; } else { return "rgb(" + rgb.join(', ') + ")"; } }; HSVColor.prototype.componentToHex = function (c) { var hex = c.toString(16); return hex.length == 1 ? '0' + hex : hex; }; return HSVColor; }()); colorGenerator.HSVColor = HSVColor; function setFormat(hsv, options) { var color = HSVColor.fromHSVArray(hsv); switch (options.format) { case 'object': return color; case 'hsvArray': return hsv; case 'hslArray': return color.toHSL(); case 'hsl': return color.toHSLString(); case 'hsla': return color.toHSLString(options.alpha || Math.random()); case 'rgbArray': return color.toRGB(); case 'rgb': return color.toRGBString(); case 'rgba': return color.toRGBString(options.alpha || Math.random()); case 'hex': default: return color.toHex(); } } function generateColor(options) { // pick a hue (H) var H = pickHue(options); // use H to determine saturation (S) var S = pickSaturation(H, options); // use S and H to determine brightness (B) var B = pickBrightness(H, S, options); // return the HSB color in the desired format return setFormat([H, S, B], options); } function getRandom(options) { options = options || {}; seed = options.seed == null ? null : options.seed; // check if we need to generate multiple colors if (options.count !== null && options.count !== undefined) { var colors = []; while (options.count > colors.length) { // Since we're generating multiple colors, the seed has to be incrememented. // Otherwise we'd just generate the same color each time... if (seed !== null) { seed += 1; } colors.push(generateColor(options)); } return colors; } return generateColor(options); } colorGenerator.getRandom = getRandom; var ColorInterval = (function () { function ColorInterval(start, end) { this.start = start; this.end = end; this.left = null; this.right = null; this.value = null; } ColorInterval.prototype.getNextValue = function () { if (this.value == null) { this.value = (this.start + this.end) / 2; return this.value; } if (this.left == null) { this.left = new ColorInterval(this.start, this.value); return this.left.getNextValue(); } if (this.right == null) { this.right = new ColorInterval(this.value, this.end); return this.right.getNextValue(); } if (this.left.getHeight() <= this.right.getHeight()) { return this.left.getNextValue(); } else { return this.right.getNextValue(); } }; ColorInterval.prototype.getHeight = function () { return 1 + (this.left == null ? 0 : this.left.getHeight()) + (this.right == null ? 0 : this.right.getHeight()); }; return ColorInterval; }()); colorGenerator.ColorInterval = ColorInterval; var defaultRootInterval = new ColorInterval(0, 360); function getEquallyDistributed(rootInterval) { if (rootInterval === void 0) { rootInterval = defaultRootInterval; } return 'hsl(' + rootInterval.getNextValue() + ', 100%, 80%)'; } colorGenerator.getEquallyDistributed = getEquallyDistributed; var Color = (function () { function Color(r, g, b) { this.r = r; this.g = g; this.b = b; } Color.fromHex = function (hex) { return new Color(parseInt(hex.substr(1, 2), 16), parseInt(hex.substr(3, 2), 16), parseInt(hex.substr(5, 2), 16)); }; Color.fromRgb = function (rgb) { var match = rgb.match(this.rgbRegex); return new Color(parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3], 10)); }; Color.fromString = function (str) { if (this.hexRegex.test(str)) { return this.fromHex(str); } else if (this.rgbRegex.test(str)) { return this.fromRgb(str); } else { throw new Error('Unexpected color format: ' + str); } }; Color.prototype.toString = function (hex) { if (hex === void 0) { hex = true; } return '#' + this.toHex(this.r) + this.toHex(this.g) + this.toHex(this.b); }; Color.prototype.toHex = function (x) { var xStr = x.toString(16); return (xStr.length == 1 ? '0' : '') + xStr; }; Color.hexRegex = /^#(?:[0-9a-f]{3}){1,2}$/i; Color.rgbRegex = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i; return Color; }()); function ratioColor(color1, color2, ratio) { var color = new Color(Math.ceil(color1.r * (1 - ratio) + color2.r * ratio), Math.ceil(color1.g * (1 - ratio) + color2.g * ratio), Math.ceil(color1.b * (1 - ratio) + color2.b * ratio)); return color.toString(); } function getColorTransition(value, colorStrings) { var smallerValue = -1; var biggerValue = Number.MAX_SAFE_INTEGER; var colors = {}; for (var v in colorStrings) { var vNum = Number(v); if (vNum === value) { return colorStrings[v]; } else if (vNum < value) { smallerValue = Math.max(smallerValue, vNum); } else { biggerValue = Math.min(biggerValue, vNum); } colors[v] = Color.fromString(colorStrings[v]); } if (smallerValue === -1) { return colorStrings[biggerValue]; } if (biggerValue === Number.MAX_SAFE_INTEGER) { return colorStrings[smallerValue]; } var ratio = (value - smallerValue) / (biggerValue - smallerValue); return ratioColor(colors[smallerValue], colors[biggerValue], ratio); } colorGenerator.getColorTransition = getColorTransition; // populate the color dictionary loadColorBounds(); })(colorGenerator || (colorGenerator = {})); /** * provides icons */ var icons; (function (icons) { icons.CHART_LINE = 'M16,11.78L20.24,4.45L21.97,5.45L16.74,14.5L10.23,10.75L5.46,19H22V21H2V3H4V17.54L9.5,8L16,11.78Z'; icons.WIKIA = '<defs><linearGradient id="a" x1="0%" x2="63.85%" y1="100%" y2="32.54%"><stop stop-color="#94D11F" offset="0%"/><stop stop-color="#09D3BF" offset="100%"/></linearGradient></defs><path fill="url(#a)" fill-rule="evenodd" d="M10.18 16.8c0 .2-.05.46-.26.67l-.8.7-7.38-6.95v-2.7l8.1 7.62c.12.12.33.36.33.66zm11.2-8.1v2.53l-9.15 8.86a.67.67 0 0 1-.5.2.73.73 0 0 1-.5-.2l-.85-.77 11-10.62zm-6.97 4.5l-2.53 2.43-8.04-7.67a2 2 0 0 1 0-2.9l2.53-2.43 8.04 7.67c.84.8.84 2.1 0 2.9zm-1.5-6.68L15.56 4c.4-.4.94-.6 1.52-.6.57 0 1.1.2 1.52.6l2.72 2.6-4.16 3.98-1.52-1.45-2.73-2.6zm10.18-.4l-6-5.8L17 .2l-.14.12-5.22 5.03L6.96.87l-.6-.48-.12-.1-.1.1-6.1 5.7-.04.06v5.76l.05.05 11.4 10.87.12.1.12-.1 11.37-10.87.05-.05V6.17l-.05-.05z"/>'; function getSvgAsUrl(svg) { return "url('data:image/svg+xml;base64," + btoa(svg) + "')"; } icons.getSvgAsUrl = getSvgAsUrl; function wrapCodeWithSvg(code, viewBox, width, height) { return "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"" + width + "\" height=\"" + height + "\" viewBox=\"" + viewBox + "\">" + code + "</svg>"; } icons.wrapCodeWithSvg = wrapCodeWithSvg; function getMd(pathDots, color, width, height) { if (color === void 0) { color = 'black'; } if (width === void 0) { width = '30'; } if (height === void 0) { height = '30'; } return getSvgAsUrl(wrapCodeWithSvg("<path fill=\"" + color + "\" d=\"" + pathDots + "\" />", '0 0 24 24', width, height)); } icons.getMd = getMd; })(icons || (icons = {})); /** * notifications */ var notifications; (function (notifications) { notifications.name = 'notifications'; function event(title, options) { if ((!options || options.whenActive !== true) && !document.hidden && document.hasFocus() && settings.getSub(settings.KEY.showNotifications, 'showType') !== 1) { return; } if (!settings.get(settings.KEY.showNotifications)) { // notifications disabled: return stub notification return Promise.resolve( { close: function () {} }); } if (!("Notification" in win)) { return Promise.reject('Your browser does not support notifications.'); } return Notification.requestPermission() .then(function (permission) { if (permission === 'granted') { var n_1 = new Notification(title, options); n_1.onclick = function (event) { if (options && options.autoFocus !== false) { win.focus(); } if (options && options.autoClose !== false) { n_1.close(); } if (options && options.onclick) { options.onclick(n_1, event); } }; return Promise.resolve(n_1); } else { return Promise.reject('Notification permission denied'); } }); } notifications.event = event; function requestPermission() { if (settings.get(settings.KEY.showNotifications)) { Notification.requestPermission(); } } function init() { requestPermission(); settings.observe(settings.KEY.showNotifications, function () { return requestPermission(); }); } notifications.init = init; })(notifications || (notifications = {})); /** * process commands */ var commands; (function (commands) { var XP_GAIN_KEY = 'xpGain'; var MAX_XP_GAIN_HISTORY_LENGTH = 100; var IMAGE2SKILL = { // mining = #cc0000 'icons/pickaxe': 'mining' // crafting = #cc0000 , 'icons/anvil': 'crafting' // woodcutting = cyan , 'icons/woodcutting': 'woodcutting' // farming = green , 'icons/watering-can': 'farming' // brewing = #800080 , 'vialOfWater': 'brewing' , 'largeVialOfWater': 'brewing' , 'hugeVialOfWater': 'brewing' // combat = lime , 'icons/combat': 'combat' // magic = blue , 'icons/wizardhat': 'magic' // fishing = blue , 'tuna': 'fishing' // cooking = yellow , 'icons/cooking': 'cooking' }; var xpGainHistory = store.has(XP_GAIN_KEY) ? store.get(XP_GAIN_KEY) : {}; addStyle("\n.scroller.xp\n{\n\tfont-size: 18pt;\n\tposition: absolute;\n\ttext-align: center;\n}\n\t"); function minutes2String(data) { return data.replace(/Your account has been running for: (\d+) minutes./, function (wholeMatch, minutes) { return 'Your account has been running for ' + format.min2Str(minutes) + '.'; }); } var LOOT_MSG_PREFIX = 'SHOW_LOOT_DIAG='; function processLoot(data) { if (!/^SM=Your boat found nothing\.$|^SHOW_LOOT_DIAG=/.test(data)) { return false; } var loot = { type: 'loot' , title: '' , itemList: [] }; if (data.startsWith('SM=')) { loot.title = 'Boat'; loot.emptyText = 'Your boat found nothing.'; } else if (data.startsWith(LOOT_MSG_PREFIX)) { var split = data.substr(LOOT_MSG_PREFIX.length).split('~'); loot.title = split[0]; for (var i = 1; i < split.length; i += 2) { loot.itemList.push( { icon: split[i] , text: split[i + 1] }); } } log.add(loot); return true; } var XP_GAIN_REGEX = /^ST=([^~]+)\.png~([^~]+)~\+(\d+)\s*xp(.*)$/; var animationQueue = {}; function queueXpAnimation(skill, cell, color, xpAmount, extraXp) { if (!settings.get(settings.KEY.newXpAnimation)) { return; } animationQueue[skill] = animationQueue[skill] || []; animationQueue[skill].push( { cell: cell , color: color , xpAmount: xpAmount , extraXp: extraXp }); if (animationQueue[skill].length === 1) { nextAnimation(skill); } } function nextAnimation(skill) { var entry = animationQueue[skill][0]; if (!entry || !settings.get(settings.KEY.newXpAnimation)) { return; } var cell = entry.cell , color = entry.color , xpAmount = entry.xpAmount , extraXp = entry.extraXp; var rect = cell.getBoundingClientRect(); var extraXpStr = extraXp > 0 ? " (+" + extraXp + ")" : ''; var $el = win.$("<div class=\"scroller xp\" style=\"color: " + color + "; left: " + (rect.left + 50) + "px; top: " + (document.body.scrollTop + rect.top) + "px; width: " + (rect.width - 2 * 20 - 50) + "px;\">+" + format.number(xpAmount) + extraXpStr + "</div>") .appendTo('body'); // ensure the existence of $el, so the complete-function can be called instantly if the window is hidden $el .animate( { top: '-=15px' } , { duration: 1500 , easing: 'easeOutQuad' , complete: function () { animationQueue[skill].shift(); nextAnimation(skill); } }) .fadeOut( { duration: 2500 , queue: false , complete: function () { return $el.remove(); } }); } function processXpGain(data) { var match = data.match(XP_GAIN_REGEX); if (!match) { return false; } var icon = match[1]; var skill = IMAGE2SKILL[icon] || ''; var color = match[2]; var xpAmount = Number(match[3]); var extra = match[4]; var cell = document.getElementById('top-bar-level-td-' + skill); if (!cell) { console.debug('match (no cell found):', match); return false; } var entry = { time: now() , amount: xpAmount }; if (match[4]) { entry.extra = match[4]; } if (skill == 'fishing') { log.processFishingXpChange(xpAmount); } var extraXp = 0; if (extra && settings.get(settings.KEY.newXpAnimation)) { var extraMatch = extra.match(/^\s*\(<img[^>]+src=(['"])images\/([^']+)\.png\1[^>]+>\s*(.+)\)$/); var extraXpMatch = extra.match(/^\s*\(\+(\d+)\s*xp\)\s*$/); if (extraMatch) { var icon_1 = extraMatch[2]; var text = extraMatch[3]; if (icon_1 == 'brewingKit') { text = '+' + text; } win.scrollText(icon_1, color, text); } else if (extraXpMatch) { extraXp = Number(extraXpMatch[1]); } else { win.scrollText('none', color, extra); } } // save the xp event var list = xpGainHistory[skill] || []; list.push(entry); xpGainHistory[skill] = list.slice(-MAX_XP_GAIN_HISTORY_LENGTH); store.set(XP_GAIN_KEY, xpGainHistory); if (settings.get(settings.KEY.newXpAnimation)) { queueXpAnimation(skill, cell, color, xpAmount, extraXp); } return true; } function processLevelUp(data) { if (!data.startsWith('LVL_UP=')) { return false; } var skill = data.substr('LVL_UP='.length); var xp = getGameValue(skill + 'Xp'); var oldLvl = win.getLevel(xp); log.add( { type: 'lvlup' , skill: skill , newLevel: oldLvl + 1 }); return true; } function processCombat(data) { var match = data.match(/^STHS=([^~]+)~([^~]+)~([^~]+)~img-(.+)~(melee|heal)$/); if (!match) { return false; } // keep track of different battles and add the data to the current battle var number = match[3]; if (!/\D/.test(number)) { number = Number(number); } log.add( { type: 'combat' , what: match[5] , who: match[4] , text: number }); return true; } function processEnergy(data) { var match = data.match(/^ST=steak\.png~orange~\+([\d',]+)$/); if (!match) { return false; } log.add( { type: 'energy' , energy: Number(match[1].replace(/\D/g, '')) }); return true; } function processHeat(data) { var match = data.match(/^ST=icons\/fire\.png~red~\+([\d',]+)$/); if (!match) { return false; } log.add( { type: 'heat' , heat: Number(match[1].replace(/\D/g, '')) }); return true; } function processMarket(data) { if (data === 'ST=icons/shop.png~orange~Item Purchased') { log.add( { type: 'market' }); return true; } var match = data.match(/^ST=coins\.png~yellow~\+([\d',]+)$/); if (!match) { return false; } var coins = Number(match[1].replace(/\D/g, '')); log.add( { type: 'market' , coins: coins }); return true; } function processBonemeal(data) { var match = data.match(/^ST=filledBonemealBin\.png~white~\+([\d',]+)$/); if (!match) { return false; } var bonemeal = Number(match[1].replace(/\D/g, '')); log.add( { type: 'bonemeal' , bonemeal: bonemeal }); return true; } function processCrafting(data) { if (data === 'ST=none~#806600~Item Crafted') { log.add( { type: 'crafting' }); return true; } return false; } function processStardust(data) { var match = data.match(/^ST=(?:icons\/)?stardust\.png~yellow~\+([\d',]+)$/); if (!match) { return false; } var stardust = Number(match[1].replace(/\D/g, '')); log.add( { type: 'stardust' , stardust: stardust }); return true; } var RUNNING_ACCOUNT_STR = 'Your account has been running for:'; function formatData(data) { if (data.startsWith('STHS=') || data.startsWith('STE=') || data.startsWith('SM=') || data.startsWith('ST=') || data.startsWith('SHOW_LOOT_DIAG=')) { if (data.indexOf(RUNNING_ACCOUNT_STR) != -1) { data = minutes2String(data); } data = format.numbersInText(data); } return data; } commands.formatData = formatData; function process(data) { // prepare for logging events in an activity log if (processLoot(data)) { return; } else if (processXpGain(data)) { // return undefined to let the original function be called return settings.get(settings.KEY.newXpAnimation) ? null : void 0; } else if (processLevelUp(data) || processCombat(data) || processEnergy(data) || processHeat(data) || processMarket(data) || processBonemeal(data) || processCrafting(data) || processStardust(data)) { return; } else if (data.startsWith('SM=')) { log.add( { data: minutes2String(data.replace(/^[^=]+=/, '')) }); } else if (data.startsWith('STHS=') || data.startsWith('STE=') || data.startsWith('ST=')) {} // notifications for this kind of message: "SM=An update has been scheduled for today." if (data.startsWith('SM=')) { if (settings.getSub(settings.KEY.showNotifications, 'serverMsg')) { var msg = data.substr(3) .replace(/<br\s*\/?>/g, '\n') .replace(/<img src='images\/(.+?)\.png'.+?\/?> (\d+)/g, function (wholeMatch, key, amount) { return format.number(amount) + ' ' + split2Words(key) + ', '; }) .replace(/<.+?>/g, '') .replace(/(\s)\1+/g, '$1') .replace(/, $/, ''); notifications.event('Message from server' , { body: minutes2String(msg) }); } } return; } commands.process = process; })(commands || (commands = {})); /** * log activities and stuff */ var log; (function (log) { log.name = 'log'; var LOG_KEY = 'activityLog'; var MAX_LOG_SIZE = 100; var logList = store.has(LOG_KEY) ? store.get(LOG_KEY) : []; var currentCombat = null; var currentCombatEl = null; var LOG_FILTER = { 'combat': { title: 'Combat' , img: 'images/icons/combat.png' } , 'loot': { title: 'Loot' , img: 'http://www.clker.com/cliparts/U/a/v/n/h/w/bag-hi.png' } , 'fish': { title: 'Caught fish' , img: 'images/tuna.png' } , 'skill': { title: 'Skill advance' , img: 'images/icons/skills.png' } , 'other': { title: 'All other' , label: 'Other' } }; var logEl; function isFightStarted() { return win.fightMonsterId !== 0; } function saveLog() { store.set(LOG_KEY, logList); } function createLi(entry) { var entryEl = document.createElement('li'); entryEl.dataset.time = (new Date(entry.time || 0)).toLocaleString(); entryEl.dataset.type = entry.type; return entryEl; } function appendLi(entryEl) { var filterEl = logEl.firstElementChild; var next = filterEl && filterEl.nextElementSibling; if (next) { logEl.insertBefore(entryEl, next); } else { logEl.appendChild(entryEl); } logEl.classList.remove('empty'); } function setGenericEntry(entry, init) { var el = createLi(entry);; el.innerHTML = typeof entry.data === 'string' ? format.numbersInText(entry.data) : JSON.stringify(entry.data); appendLi(el); } function setLootEntry(entry, init) { var el = createLi(entry); var header = document.createElement('h1'); header.className = 'container-title'; header.textContent = entry.title; el.appendChild(header); var itemContainer = document.createElement('span'); if (entry.itemList.length === 0) { itemContainer.innerHTML = "<span class=\"dialogue-loot\">" + entry.emptyText + "</span>"; } else { var update = false; for (var _i = 0, _a = entry.itemList; _i < _a.length; _i++) { var item = _a[_i]; if (item.hasOwnProperty('key')) { item.icon = item.key; delete item.key; update = true; } if (item.hasOwnProperty('amount')) { item.text = (item.amount || Number.NaN).toString(); delete item.amount; update = true; } var itemEl = document.createElement('span'); itemEl.className = 'dialogue-loot'; itemEl.innerHTML = "<img src=\"" + item.icon + "\" class=\"image-icon-50\"> " + format.numbersInText(item.text); itemContainer.appendChild(itemEl); itemContainer.appendChild(document.createTextNode(' ')); } if (update) { saveLog(); } } el.appendChild(itemContainer); var valueContainer = document.createElement('div'); valueContainer.className = 'total-value'; valueContainer.appendChild(document.createTextNode('Total value: ')); var totalValue = document.createElement('span'); totalValue.style.cursor = 'pointer'; totalValue.textContent = 'Click to calculate'; valueContainer.appendChild(totalValue); totalValue.addEventListener('click', function () { var items = {}; for (var _i = 0, _a = entry.itemList; _i < _a.length; _i++) { var item = _a[_i]; if (item.text.indexOf('xp') === -1) { var key = item.icon.replace(/^.+\/([^\/]+)\.png$/, '$1'); var num = Number(item.text.replace(/\D/g, '')); items[key] = (items[key] || 0) + num; } } market.calcMarketValue(items) .then(function (sum) { totalValue.innerHTML = "<img class=\"image-icon-20\" src=\"images/coins.png\"> " + format.number(sum[0]) + " - <img class=\"image-icon-20\" src=\"images/coins.png\"> " + format.number(sum[1]); }); }); el.appendChild(valueContainer); appendLi(el); } function setFishEntry(entry, init) { var el = createLi(entry); el.innerHTML = "You caught a " + key2Name(entry.fish, true) + "."; appendLi(el); } function setEnergyEntry(entry, init) { var el = createLi(entry); el.innerHTML = "Your hero gained " + format.number(entry.energy) + " energy."; appendLi(el); } function setHeatEntry(entry, init) { var el = createLi(entry); el.innerHTML = "You added " + format.number(entry.heat) + " heat to your oven."; appendLi(el); } function setLevelUpEntry(entry, init) { var el = createLi(entry); el.innerHTML = "You advanced your " + entry.skill + " skill to level " + entry.newLevel + "."; appendLi(el); } function getCombatInfo(data, initHp, scaleX, width) { var points = []; var startHp = -1; var hp = initHp; for (var tick in data) { hp = data[tick]; if (startHp === -1) { startHp = hp; } points.push((scaleX * Number(tick)) + ' ' + hp); } if (points.length === 0) { points.push('0 ' + initHp); } points.push(width + ' ' + hp, width + ' 0', '0 0'); return { points: points , startHp: startHp === -1 ? initHp : startHp , endHp: hp }; } function getHTMLFromCombatInfo(info, name) { return "<div class=\"combat-log-graph\">\n\t\t\t<span>" + name + " (" + info.startHp + " Hp to " + info.endHp + " Hp):</span><br>\n\t\t\t<svg style=\"height: " + info.startHp + "px;\"><polygon points=\"" + info.points.join(',') + "\"></polygon></svg>\n\t\t</div>"; } function setCombatEntry(entry, init) { var created = init || currentCombatEl == null; if (init || currentCombatEl == null) { currentCombatEl = createLi(entry); } var HTML = ''; // support old log format if (!entry.hasOwnProperty('ticks')) { var info = { hero: { heal: 0 , melee: 0 } , monster: { heal: 0 , melee: 0 } }; for (var i = 0; i < entry.parts.length; i++) { var part = entry.parts[i]; info[part.who][part.type] += part.number; } HTML = "<div>Hero: <span style=\"color: green;\">+" + info.hero.heal + "</span> <span style=\"color: red;\">-" + info.hero.melee + "</span></div>\n\t\t\t<div>Monster: <span style=\"color: green;\">+" + info.monster.heal + "</span> <span style=\"color: red;\">-" + info.monster.melee + "</span></div>"; } else { var currentTick = Math.max(entry.ticks, 0); var width = logEl.scrollWidth - 4 * 12.8 - 2; var scaleX = currentTick === 0 ? 0 : width / currentTick; var hero = getCombatInfo(entry.hero, win.heroHp, scaleX, width); var monster = getCombatInfo(entry.monster, win.fightMonsterHp, scaleX, width); // TODO: who won? HTML = "The fight took " + format.sec2Str(currentTick) + ".\n\t\t\t" + getHTMLFromCombatInfo(hero, 'Hero') + "\n\t\t\t" + getHTMLFromCombatInfo(monster, 'Monster') + "\n\t\t\t"; } // map monster name and area name from monster id (the ids are starting at 1) var isShiny = entry.monsterId > 1e3; var mId = entry.monsterId - (isShiny ? 1001 : 1); var monsterName = (isShiny ? 'Shiny ' : '') + (getMonsterName(mId) || '(' + (mId % 3 + 1) + ')'); var areaId = Math.floor(mId / 3); var areaName = getAreaName(areaId) || '(' + (areaId + 1) + ')'; currentCombatEl.innerHTML = "<h2>Combat against " + monsterName + " in " + areaName + "</h2>\n\t\t" + HTML; if (created) { appendLi(currentCombatEl); } if (!isFightStarted()) { currentCombatEl = null; } } function setMarketEntry(entry, init) { var el = createLi(entry); if (entry.coins) { el.innerHTML = "You collected " + format.number(entry.coins) + " from market."; } else { el.innerHTML = "You purchased an item on market."; } appendLi(el); } function setBonemealEntry(entry, init) { var el = createLi(entry); el.innerHTML = "You added " + format.number(entry.bonemeal) + " bonemeal to your bonemeal bin."; appendLi(el); } function setCraftingEntry(entry, init) { var el = createLi(entry); el.innerHTML = "You crafted an item."; appendLi(el); } function setStardustEntry(entry, init) { var el = createLi(entry); el.innerHTML = "You got " + format.number(entry.stardust) + " stardust."; appendLi(el); } var entryType2Fn = { 'loot': setLootEntry , 'fish': setFishEntry , 'energy': setEnergyEntry , 'heat': setHeatEntry , 'lvlup': setLevelUpEntry , 'combat': setCombatEntry , 'market': setMarketEntry , 'bonemeal': setBonemealEntry , 'crafting': setCraftingEntry , 'stardust': setStardustEntry }; function updateLog(entry, init) { if (init === void 0) { init = false; } if (!logEl) { return; } if (entry.type && entryType2Fn.hasOwnProperty(entry.type)) { entryType2Fn[entry.type](entry, init); } else { setGenericEntry(entry, init); } } function add2Log(entry) { logList.push(entry); logList = logList.slice(-MAX_LOG_SIZE); saveLog(); } // use the last stored combat, compare monster id and health state to check whether this combat might be interrupted last time (hero health != 0 && monster health != 0) and continue logging to that fight function findCurrentCombat() { for (var i = logList.length - 1; i >= 0; i--) { if (logList[i].type == 'combat') { var entry = logList[i]; if (entry.monsterId == win.fightMonsterId && entry.hero[entry.ticks] !== 0 && entry.hero[entry.ticks] !== 0) { return entry; } break; } } return null; } function add(entry) { if (!entry.time) { entry.time = now(); } if (entry.type == 'combat') { currentCombat = currentCombat || findCurrentCombat(); if (!currentCombat) { return; } // skip entries without further information if (typeof entry.text !== 'number' || entry.text === 0) { return; } var hp = entry.who == 'hero' ? win.heroHp : win.fightMonsterHp; // the hp values are updated after this event, so I have to calculate the new value by myself hp += (entry.what == 'heal' ? 1 : -1) * entry.text; currentCombat[entry.who][currentCombat.ticks] = hp; saveLog(); updateLog(currentCombat); } else { add2Log(entry); updateLog(entry); } } log.add = add; function addLogEl() { addStyle("\n#show-activity-log\n{\n\tdisplay: none;\n}\nbody\n{\n\toverflow-y: scroll;\n}\n#activity-log-label\n{\n\tcolor: pink;\n\tcursor: pointer;\n\t-webkit-user-select: none;\n\t-moz-user-select: none;\n\t-ms-user-select: none;\n\tuser-select: none;\n}\n#activity-log-overlay\n{\n\tbackground-color: transparent;\n\tcolor: transparent;\n\tpointer-events: none;\n\tposition: fixed;\n\tbottom: 0;\n\tleft: 0;\n\ttop: 0;\n\tright: 0;\n\ttransition: background-color .3s ease-out;\n\tz-index: 1000;\n}\n#show-activity-log:checked ~ #activity-log-overlay\n{\n\tbackground-color: rgba(0, 0, 0, 0.4);\n\tpointer-events: all;\n}\n#activity-log\n{\n\tbackground-color: white;\n\tcolor: black;\n\tlist-style: none;\n\tmargin: 0;\n\toverflow-y: scroll;\n\tpadding: .4rem .8rem;\n\tposition: fixed;\n\ttop: 0;\n\tright: 0;\n\tbottom: 0;\n\ttransform: translateX(100%);\n\ttransition: transform .3s ease-out;\n\tmin-width: 15rem;\n\twidth: 40%;\n\tmax-width: 30rem;\n\tz-index: 1000;\n}\n#show-activity-log:checked ~ #activity-log\n{\n\ttransform: translateX(0%);\n}\n#activity-log::before\n{\n\tcontent: 'Activity Log';\n\tdisplay: block;\n\tfont-size: 1rem;\n\tfont-weight: bold;\n\tmargin-bottom: 0.8rem;\n}\n#activity-log.empty::after\n{\n\tcontent: 'Activities will be listed here.';\n}\n#activity-log li:not(.filter)\n{\n\tborder: 1px solid gray;\n\tborder-radius: .2rem;\n\tdisplay: none;\n\tmargin: .2rem 0;\n\tpadding: .4rem .8rem;\n}\n#activity-log li:not(.filter)::before\n{\n\tcolor: gray;\n\tcontent: attr(data-time);\n\tdisplay: block;\n\tfont-size: 0.8rem;\n\tmargin: -4px 0 4px -4px;\n}\n.combat-log-graph > svg\n{\n\ttransform: scaleY(-1);\n\twidth: 100%;\n}\n.combat-log-graph > svg polygon\n{\n\tfill: green;\n\tstroke: black;\n\tstroke-width: 1px;\n}\n#activity-log.combat > li[data-type=\"combat\"]\n{\n\tdisplay: block;\n}\n#activity-log.loot > li[data-type=\"loot\"]\n{\n\tdisplay: block;\n}\n#activity-log.fish > li[data-type=\"fish\"]\n{\n\tdisplay: block;\n}\n#activity-log.lvlup > li[data-type=\"lvlup\"]\n{\n\tdisplay: block;\n}\n#activity-log.other > li[data-type=\"energy\"],\n#activity-log.other > li[data-type=\"heat\"],\n#activity-log.other > li[data-type=\"market\"],\n#activity-log.other > li[data-type=\"bonemeal\"],\n#activity-log.other > li[data-type=\"crafting\"],\n#activity-log.other > li[data-type=\"stardust\"],\n#activity-log.other > li[data-type=\"undefined\"]\n{\n\tdisplay: block;\n}\n\t\t"); // add new tab "Activity Log" var checkboxId = 'show-activity-log'; var activityLogLabel = document.createElement('label'); activityLogLabel.id = 'activity-log-label'; activityLogLabel.htmlFor = checkboxId; activityLogLabel.textContent = 'Activity Log'; newTopbar.addTabEntry(activityLogLabel); var checkbox = document.createElement('input'); checkbox.id = checkboxId; checkbox.type = 'checkbox'; checkbox.style.display = 'none'; document.body.insertBefore(checkbox, document.body.firstChild); var label = document.createElement('label'); label.id = 'activity-log-overlay'; label.htmlFor = checkboxId; document.body.appendChild(label); logEl = document.createElement('ul'); logEl.id = 'activity-log'; var classList = []; var html = ''; for (var key in LOG_FILTER) { // TODO: load saved filter var checked = true; classList.push(key); html += "<label for=\"log-filter-" + key + "\" title=\"" + LOG_FILTER[key].title + "\">\n\t\t\t\t" + (LOG_FILTER[key].img ? "<img class=\"image-icon-20\" src=\"" + LOG_FILTER[key].img + "\">" : LOG_FILTER[key].label) + "\n\t\t\t</label>\n\t\t\t<input type=\"checkbox\" id=\"log-filter-" + key + "\" " + (checked ? 'checked' : '') + ">"; } logEl.className = 'empty ' + classList.join(' '); logEl.innerHTML = "<li class=\"filter\">\n\t\t\t" + html + "\n\t\t</li>"; document.body.appendChild(logEl); var $checkboxes = win.$('li.filter > input[id^="log-filter-"]'); $checkboxes.checkboxradio( { icon: false }); $checkboxes.change(function (event) { var id = event.target.id; var key = id.replace('log-filter-', ''); var checked = document.getElementById(id).checked; logEl.classList[checked ? 'add' : 'remove'](key); // TODO: save current state }); // add all stored elements logList.forEach(function (e) { return updateLog(e, true); }); } function observeCombat() { observer.add('fightMonsterId', function (key, oldValue, newValue) { if (isFightStarted()) { currentCombat = { type: 'combat' , time: now() , monsterId: newValue , ticks: -5 , hero: {} , monster: {} }; add2Log(currentCombat); updateLog(currentCombat); } else { if (currentCombat) { currentCombat.ticks--; saveLog(); } currentCombat = null; currentCombatEl = null; } }); observer.addTick(function () { if (currentCombat !== null) { currentCombat.ticks++; if (currentCombat.ticks === 0) { currentCombat.hero[0] = win.heroHp; currentCombat.monster[0] = win.fightMonsterHp; } updateLog(currentCombat); } }); } var possiblyCaughtFish; var lastFishingXpChange = 0; function fishObserver(key, oldValue, newValue) { if (oldValue < newValue && lastFishingXpChange >= now() - 5e3) { var idx = possiblyCaughtFish.indexOf(key); if (idx !== -1) { add( { type: 'fish' , fish: key }); possiblyCaughtFish = []; lastFishingXpChange = 0; } } } function processFishingXpChange(xp) { lastFishingXpChange = now(); possiblyCaughtFish = []; for (var fish in FISH_XP) { if (FISH_XP[fish] == xp) { possiblyCaughtFish.push(fish); } } } log.processFishingXpChange = processFishingXpChange; function observeFishing() { for (var fish in FISH_XP) { observer.add(fish, fishObserver); } } function init() { addLogEl(); observeCombat(); observeFishing(); } log.init = init; })(log || (log = {})); /** * game events */ var gameEvents; (function (gameEvents) { gameEvents.name = 'gameEvents'; // min time difference between two notifications with the same title (10 seconds) var MIN_TIME_DIFFERENCE = 10; gameEvents.enabled = { smelting: true , chopping: true , harvest: true , boat: true , battle: true , brewing: true , market: true , map: true , essence: true , rocket: true , wind: true , perk: true }; var lastTimestamp = new Map(); function notifyTabClickable(title, body, icon, tabKey, whenActive) { if (whenActive === void 0) { whenActive = false; } var now = (new Date).getTime(); var timeDiff = now - (lastTimestamp.get(title) || 0); if (timeDiff < MIN_TIME_DIFFERENCE * 1e3) { return; } var promise = notifications.event(title , { body: body , icon: 'images/' + icon , whenActive: whenActive , onclick: function () { var tabNames = tabKey.split('.'); win.openTab(tabNames[0]); if (tabNames.length > 1) { win.openSubTab(tabNames[1]); } } }); if (promise) { lastTimestamp.set(title, now); } } function observeTimer(k, fn) { observer.add(k, function (key, oldValue, newValue) { if (oldValue > 0 && newValue == 0) { fn(key, oldValue, newValue); } }); } function smelting() { observeTimer('smeltingPercD', function (key, oldValue, newValue) { if (!gameEvents.enabled.smelting || !settings.getSub(settings.KEY.showNotifications, 'smelting')) { return; } notifyTabClickable('Hot topic', 'Your smelting has finished.', getFurnaceLevelName() + 'Furnace.png', 'crafting'); }); } function chopping() { observer.add([ 'treeStage1' , 'treeStage2' , 'treeStage3' , 'treeStage4' , 'treeStage5' , 'treeStage6' ], function (key, oldValue, newValue) { if (!gameEvents.enabled.chopping || !settings.getSub(settings.KEY.showNotifications, 'chopping')) { return; } if (newValue == 4) { notifyTabClickable('Wood you be mine?', 'One or more of your trees are fully grown and can be chopped.', 'icons/woodcutting.png', 'woodcutting'); } }); } function harvest() { observer.add([ 'farmingPatchStage1' , 'farmingPatchStage2' , 'farmingPatchStage3' , 'farmingPatchStage4' , 'farmingPatchStage5' , 'farmingPatchStage6' ], function (key, oldValue, newValue) { if (!gameEvents.enabled.harvest || !settings.getSub(settings.KEY.showNotifications, 'harvest')) { return; } if (newValue == 4) { notifyTabClickable('Green thumb', 'One or more of your crops is ready for harvest.', 'icons/watering-can.png', 'farming'); } else if (newValue > 4) { notifyTabClickable('I didn\'t plant this', 'One or more of your crops died.', 'icons/watering-can.png', 'farming'); } }); } function boat() { var timerKeys = BOAT_LIST.map(function (boatKey) { return boatKey + 'Timer'; }); observeTimer(timerKeys, function (key, oldValue, newValue) { if (!gameEvents.enabled.boat || !settings.getSub(settings.KEY.showNotifications, 'boatReturned')) { return; } var boatKey = key.replace(/Timer$/, ''); notifyTabClickable('Fishy business', 'Your ' + split2Words(boatKey).toLowerCase() + ' returned from its trip.', boatKey + '.png', 'combat'); }); } function battle() { observeTimer('combatGlobalCooldown', function (key, oldValue, newValue) { if (!gameEvents.enabled.battle || !settings.getSub(settings.KEY.showNotifications, 'heroReady')) { return; } notifyTabClickable('Ready to work', 'Your hero is eager to fight.', 'icons/combat.png', 'combat'); }); } function brewing() { observeTimer([ 'barPotionTimer' , 'seedPotionTimer' , 'stardustPotionTimer' , 'superStardustPotionTimer' ], function (key, oldValue, newValue) { if (!gameEvents.enabled.brewing || !settings.getSub(settings.KEY.showNotifications, 'potionEffect')) { return; } var potionKey = key.replace(/Timer$/, ''); if (getGameValue(potionKey) > 0) { notifyTabClickable('Cheers!', 'You can drink another ' + split2Words(potionKey) + '.', key.replace(/Timer$/, '') + '.png', 'brewing'); } }); } function market() { var _refreshMarketSlot = win.refreshMarketSlot; var lastCollectText = 0; win.refreshMarketSlot = function (offerId, itemKey, amount, price, collectText, slotId, timeLeft) { var diff = collectText - lastCollectText; lastCollectText = collectText; if (gameEvents.enabled.market && settings.getSub(settings.KEY.showNotifications, 'itemsSold') && collectText > 0) { var soldAmount = diff / price; var amountText = ['one (1)', 'two (2)', 'three (3)'][soldAmount - 1] || format.number(soldAmount); var itemName = split2Words(itemKey).toLowerCase(); if (soldAmount > 1) { itemName = pluralize(itemName); } var textTemplate = function (itemText) { return "You've sold " + itemText + " to the market."; }; if (amount > 0) { notifyTabClickable('Ka-ching', textTemplate(amountText + ' ' + itemName), 'icons/shop.png', 'playermarket'); } else { notifyTabClickable('Sold out', textTemplate((soldAmount === 1 ? 'your' : 'all') + ' ' + amountText + ' ' + itemName), 'icons/shop.png', 'playermarket'); } } _refreshMarketSlot(offerId, itemKey, amount, price, collectText, slotId, timeLeft); }; } function gameValues() { observer.add('treasureMap', function (key, oldValue, newValue) { if (gameEvents.enabled.map && settings.getSub(settings.KEY.showNotifications, 'pirate') && oldValue < newValue) { notifyTabClickable('Arrrr!', 'Your pirate found a treasure map.', 'treasureMap.png', 'items'); } }); observer.add('essence', function (key, oldValue, newValue) { if (oldValue < newValue) { var diff = newValue - oldValue; var num = ['an', 'two', 'three'][diff - 1] || diff; var text = 'You found ' + num + ' essence' + (diff > 1 ? 's' : '') + '.'; if (gameEvents.enabled.essence && settings.get(settings.KEY.showEssencePopup)) { win.confirmDialogue(400, text, 'Close', '', ''); } if (gameEvents.enabled.essence && settings.getSub(settings.KEY.showNotifications, 'essence')) { notifyTabClickable('Essence of Life', text, 'essence.png', 'combat.spells'); } } }); observer.add('rocketMoonId', function (key, oldValue, newValue) { if (gameEvents.enabled.rocket && settings.getSub(settings.KEY.showNotifications, 'rocket')) { if (newValue > 0) { notifyTabClickable('One small step for a man...', 'Your rocket landed on the moon.', 'rocket.png', 'mining'); } else if (oldValue < 0 && newValue === 0) { notifyTabClickable('Back home', 'Your rocket returned to earth.', 'rocket.png', 'mining'); } } }); var WIND_DESCRIPTION = [ 'The sea is sleeping like a baby' , 'There is a slight breeze' , 'A normal day on the sea' , 'There is a storm coming' , 'The sea is raging' ]; var WIND_CATEGORY = ['none', 'low', 'medium', 'high', 'very high']; var _setSailBoatWind = win.setSailBoatWind; var oldValue = -1; win.setSailBoatWind = function (windLevel) { _setSailBoatWind(windLevel); var newValue = win.sailBoatWindGlobal; if (oldValue !== -1 && oldValue !== newValue && win.boundSailBoat > 0 && gameEvents.enabled.wind && settings.getSub(settings.KEY.showNotifications, 'wind')) { var windText = (WIND_DESCRIPTION[win.sailBoatWindGlobal] || 'The wind is turning') + ' (' + (WIND_CATEGORY[win.sailBoatWindGlobal] || 'level ' + win.sailBoatWindGlobal) + ' wind).'; notifyTabClickable('Wind of change', windText, 'sailBoat.png', 'combat'); } oldValue = newValue; }; // trigger getting the wind level once at page load // so the script can distinguish between getting the wind initially and an actual wind change win.processTab('combat'); // achievements (e.g. achBrewingEasyCompleted) var achRegex = /^ach([A-Z][a-z]+)([A-Z][a-z]+)Completed$/; function checkAchievement(key, oldValue, newValue) { if (gameEvents.enabled.perk && settings.getSub(settings.KEY.showNotifications, 'perk') && oldValue < newValue) { var match = key.match(/^ach([A-Z][a-z]+)([A-Z][a-z]+)Completed$/); var skillName = match[1].toLowerCase(); var difficulty = match[2].toLowerCase(); notifyTabClickable('New perk unlocked', 'You completed the ' + difficulty + ' ' + skillName + ' achievement set.', 'achievementBook.png', 'achievements'); } } for (var _i = 0, _a = win.jsItemArray; _i < _a.length; _i++) { var key = _a[_i]; if (achRegex.test(key)) { observer.add(key, checkAchievement); } } var stardustEl = document.querySelector('span[data-item-display="stardust"]'); var parent = stardustEl && stardustEl.parentElement; if (stardustEl && parent) { addStyle("\n#dh2qol-stardustMonitor\n{\n\tdisplay: none !important;\n}\n#stardust-change\n{\n\tcolor: grey;\n\tdisplay: inline-block;\n\tmargin-left: .25rem;\n\ttext-align: left;\n\twidth: 2.5rem;\n}\n#stardust-change.hide\n{\n\tvisibility: hidden;\n}\n\t\t\t"); var changeEl_1 = document.createElement('span'); changeEl_1.className = 'hide'; changeEl_1.id = 'stardust-change'; parent.appendChild(changeEl_1); var HIDE_AFTER_TICKS_1 = 5; var ticksSinceSdChange_1 = HIDE_AFTER_TICKS_1; var sdDiff_1 = 0; observer.add('stardust', function (key, oldValue, newValue) { sdDiff_1 = Math.max(newValue - oldValue, 0); if (sdDiff_1 > 0) { ticksSinceSdChange_1 = 0; } }); observer.addTick(function () { var show = settings.get(settings.KEY.showSdChange) && ticksSinceSdChange_1 < HIDE_AFTER_TICKS_1; changeEl_1.classList[show ? 'remove' : 'add']('hide'); ticksSinceSdChange_1++; var diff = ticksSinceSdChange_1 > 1 ? 0 : sdDiff_1; var sign = diff > 0 ? '+' : PLUS_MINUS_SIGN; changeEl_1.textContent = '(' + sign + format.number(diff) + ')'; }); } } function init() { smelting(); chopping(); harvest(); boat(); battle(); brewing(); market(); gameValues(); } gameEvents.init = init; })(gameEvents || (gameEvents = {})); /** * hide crafting recipes of lower tiers or of maxed machines */ var crafting; (function (crafting) { crafting.name = 'crafting'; /** * hide crafted recipes */ function setRecipeVisibility(key, visible) { var recipeRow = document.getElementById('crafting-' + key); if (recipeRow) { recipeRow.style.display = (!settings.get(settings.KEY.hideCraftingRecipes) || visible) ? '' : 'none'; } } function hideLeveledRecipes(max, getKey, init) { if (init === void 0) { init = false; } var keys2Observe = []; var maxLevel = 0; for (var i = max - 1; i >= 0; i--) { var level = i + 1; var key = getKey(i); var boundKey = getBoundKey(key); keys2Observe.push(key); keys2Observe.push(boundKey); if (getGameValue(key) > 0 || getGameValue(boundKey) > 0) { maxLevel = Math.max(maxLevel, level); } setRecipeVisibility(key, level > maxLevel); } if (init) { observer.add(keys2Observe, function () { return hideLeveledRecipes(max, getKey, false); }); } } function hideToolRecipe(key, init) { if (init === void 0) { init = false; } var emptyKey = getTierKey(key, 0); var keys2Observe = [emptyKey]; var hasTool = getGameValue(emptyKey) > 0; for (var i = 0; i < TIER_LEVELS.length; i++) { var boundKey = getBoundKey(getTierKey(key, i)); hasTool = hasTool || getGameValue(boundKey) > 0; keys2Observe.push(boundKey); } setRecipeVisibility(emptyKey, !hasTool); if (init) { observer.add(keys2Observe, function () { return hideToolRecipe(key, false); }); } } function hideRecipe(key, init) { if (init === void 0) { init = false; } var info = RECIPE_MAX.crafting[key]; var maxValue = typeof info.max === 'function' ? info.max() : info.max; var boundKey = getBoundKey(key); var unbound = getGameValue(key); var bound = getGameValue(boundKey); var extra = (info.extraKeys || []).map(function (k) { return getGameValue(k); }).reduce(function (p, c) { return p + c; }, 0); setRecipeVisibility(key, maxValue - (bound + unbound + extra) > 0); if (init) { observer.add([key, boundKey], function () { return hideRecipe(key, false); }); } } /** * hide useless items */ function setItemVisibility(key, visible) { var itemBox = document.getElementById('item-box-' + key); if (itemBox) { itemBox.style.display = getGameValue(key) > 0 && (!settings.get(settings.KEY.hideUselessItems) || visible) ? '' : 'none'; } } function hideLeveledItems(max, getKey, init) { if (init === void 0) { init = false; } var keys2Observe = []; var maxLevel = 0; for (var i = max - 1; i >= 0; i--) { var level = i + 1; var key = getKey(i); var boundKey = getBoundKey(key); keys2Observe.push(key); keys2Observe.push(boundKey); if (getGameValue(boundKey) > 0) { maxLevel = Math.max(maxLevel, level); } setItemVisibility(key, level > maxLevel); } if (init) { observer.add(keys2Observe, function () { return hideLeveledItems(max, getKey, false); }); } } function hideItem(key, hideInfo, init) { if (init === void 0) { init = false; } var maxValue = typeof hideInfo.max === 'function' ? hideInfo.max() : hideInfo.max; var boundKey = getBoundKey(key); var bound = getGameValue(boundKey); var extra = (hideInfo.extraKeys || []).map(function (k) { return getGameValue(k); }).reduce(function (p, c) { return p + c; }, 0); setItemVisibility(key, (bound + extra) < maxValue); if (init) { observer.add([key, boundKey], function () { return hideItem(key, hideInfo, false); }); } } function init() { function processRecipes(init) { if (init === void 0) { init = false; } // furnace hideLeveledRecipes(FURNACE_LEVELS.length, function (i) { return FURNACE_LEVELS[i] + 'Furnace'; }, init); // oil storage hideLeveledRecipes(OIL_STORAGE_SIZES.length, function (i) { return 'oilStorage' + (i + 1); }, init); // oven recipes hideLeveledRecipes(OVEN_LEVELS.length, function (i) { return OVEN_LEVELS[i] + 'Oven'; }, init); // tools for (var _i = 0, TIER_ITEMS_1 = TIER_ITEMS; _i < TIER_ITEMS_1.length; _i++) { var tool = TIER_ITEMS_1[_i]; hideToolRecipe(tool, init); } // other stuff for (var key in RECIPE_MAX.crafting) { hideRecipe(key, init); } if (init) { settings.observe(settings.KEY.hideCraftingRecipes, function () { return processRecipes(false); }); } } processRecipes(true); var _processCraftingTab = win.processCraftingTab; win.processCraftingTab = function () { var reinit = !!win.refreshLoadCraftingTable; _processCraftingTab(); if (reinit) { processRecipes(false); } }; function processItems(init) { if (init === void 0) { init = false; } // furnace hideLeveledItems(FURNACE_LEVELS.length, function (i) { return FURNACE_LEVELS[i] + 'Furnace'; }, init); // oil storage hideLeveledItems(OIL_STORAGE_SIZES.length, function (i) { return 'oilStorage' + (i + 1); }, init); // oven recipes hideLeveledItems(OVEN_LEVELS.length, function (i) { return OVEN_LEVELS[i] + 'Oven'; }, init); // other stuff for (var key in RECIPE_MAX.crafting) { hideItem(key, RECIPE_MAX.crafting[key], init); } if (init) { settings.observe(settings.KEY.hideUselessItems, function () { return processItems(false); }); } } processItems(true); } crafting.init = init; })(crafting || (crafting = {})); /** * improve item boxes */ var itemBoxes; (function (itemBoxes) { itemBoxes.name = 'itemBoxes'; function hideNumberInItemBox(key, setVisibility) { if (setVisibility === void 0) { setVisibility = false; } var itemBox = document.getElementById('item-box-' + key); if (!itemBox) { return; } var numberElement = itemBox.querySelector('span[data-item-display]'); if (!numberElement) { return; } numberElement.classList.add('number-caption'); if (setVisibility) { numberElement.classList.remove('hide'); numberElement.classList.add('hidden'); } else { numberElement.classList.remove('hidden'); numberElement.classList.add('hide'); } } function addSpan2ItemBox(key, replace, setVisibility) { if (replace === void 0) { replace = true; } if (setVisibility === void 0) { setVisibility = false; } if (replace) { hideNumberInItemBox(key, setVisibility); } var itemBox = document.getElementById('item-box-' + key); if (!itemBox) { return; } var span = document.createElement('span'); span.className = 'caption'; itemBox.appendChild(span); return span; } function addCaptionStyle() { var CLASS_NAME = 'show-captions'; addStyle("\nbody:not(." + CLASS_NAME + ") span.caption\n{\n\tdisplay: none;\n}\nbody." + CLASS_NAME + " span.number-caption.hidden\n{\n\tvisibility: hidden;\n}\nbody." + CLASS_NAME + " span.number-caption.hide\n{\n\tdisplay: none;\n}\n\t\t"); function updateBodyClass() { var show = settings.get(settings.KEY.showCaptions); document.body.classList[show ? 'add' : 'remove'](CLASS_NAME); } updateBodyClass(); settings.observe(settings.KEY.showCaptions, function () { return updateBodyClass(); }); } function setOilPerSecond(span, oil) { span.innerHTML = "+ " + format.number(oil) + " L/s <img src=\"images/oil.png\" class=\"image-icon-20\">"; } // show capacity of furnace function addFurnaceCaption() { for (var i = 0; i < FURNACE_LEVELS.length; i++) { var key = FURNACE_LEVELS[i] + 'Furnace'; var boundKey = getBoundKey(key); var capacitySpan = addSpan2ItemBox(boundKey); if (capacitySpan) { capacitySpan.classList.add('capacity'); capacitySpan.textContent = 'Capacity: ' + format.number(win.getFurnaceCapacity(boundKey), true); } } // charcoal foundry var foundryCapacitySpan = addSpan2ItemBox('charcoalFoundry'); if (foundryCapacitySpan) { foundryCapacitySpan.classList.add('capacity'); foundryCapacitySpan.textContent = 'Capacity: 100'; } } // show oil cap of oil storage function addOilStorageCaption() { for (var i = 0; i < OIL_STORAGE_SIZES.length; i++) { var key = 'oilStorage' + (i + 1); var capSpan = addSpan2ItemBox(getBoundKey(key)); if (capSpan) { capSpan.classList.add('oil-cap'); capSpan.textContent = 'Oil cap: ' + format.number(OIL_STORAGE_SIZES[i], true); } } } var oilPipeOrbKey = 'boundBlueOilPipeOrb'; function setOilPipeCaption(span) { setOilPerSecond(span, 50 + win.achMiningEasyCompleted * 50 + getGameValue(oilPipeOrbKey) * 100); } // show oil per second function addOilCaption() { addStyle("\n#item-box-handheldOilPump,\n#item-box-boundOilPipe,\n#item-box-boundPumpjacks,\n#item-box-boundOilFactory\n{\n\tposition: relative;\n}\nspan.caption.oil\n{\n\tfont-size: .9rem;\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n}\nspan.caption.oil img[src=\"images/oil.png\"]\n{\n\t-webkit-filter: drop-shadow(0px 0px 5px rgb(255,255,255));\n\tfilter: url(#drop-shadow);\n\t-ms-filter: \"progid:DXImageTransform.Microsoft.Dropshadow(OffX=0, OffY=0, Color='#FFF')\";\n\tfilter: \"progid:DXImageTransform.Microsoft.Dropshadow(OffX=0, OffY=0, Color='#FFF')\";\n}\n\t\t"); var tpl = document.createElement('templateWrapper'); tpl.innerHTML = "\n<svg height=\"0\" xmlns=\"http://www.w3.org/2000/svg\">\n <filter id=\"drop-shadow\">\n <feGaussianBlur in=\"SourceAlpha\" stdDeviation=\"1\"></feGaussianBlur>\n <feOffset dx=\"0\" dy=\"0\" result=\"offsetblur\"></feOffset>\n <feFlood flood-color=\"rgba(255,255,255,1)\"></feFlood>\n <feComposite in2=\"offsetblur\" operator=\"in\"></feComposite>\n <feMerge>\n\n <feMergeNode></feMergeNode><feMergeNode in=\"SourceGraphic\"></feMergeNode>\n </feMerge>\n </filter>\n</svg>\n\t\t"; var shadowDrop = tpl.firstElementChild; document.body.appendChild(shadowDrop); var handheldOilSpan = addSpan2ItemBox('handheldOilPump', true, true); if (handheldOilSpan) { handheldOilSpan.classList.add('oil'); setOilPerSecond(handheldOilSpan, 1 * win.miner); observer.add('miner', function () { return setOilPerSecond(handheldOilSpan, 1 * win.miner); }); } var oilPipeSpan = addSpan2ItemBox('boundOilPipe', true, true); if (oilPipeSpan) { oilPipeSpan.classList.add('oil'); setOilPipeCaption(oilPipeSpan); observer.add(oilPipeOrbKey, function () { return setOilPipeCaption(oilPipeSpan); }); } // add pump jack oil display var pumpjackSpan = addSpan2ItemBox('boundPumpjacks', false); if (pumpjackSpan) { pumpjackSpan.classList.add('oil'); var setCaption_1 = function () { return setOilPerSecond(pumpjackSpan, win.boundPumpjacks * 10); }; setCaption_1(); observer.add('boundPumpjacks', function () { return setCaption_1(); }); } // add number of workers as caption to oil factory var workerSpan = addSpan2ItemBox('boundOilFactory'); if (workerSpan) { var setCaption_2 = function () { return workerSpan.textContent = 'Workers: ' + format.number(win.oilFactoryCheapWorkers, true); }; setCaption_2(); observer.add('oilFactoryCheapWorkers', function () { return setCaption_2(); }); } var factoryOilSpan = addSpan2ItemBox('boundOilFactory'); if (factoryOilSpan) { factoryOilSpan.classList.add('oil'); var setCaption_3 = function () { return setOilPerSecond(factoryOilSpan, win.oilFactoryCheapWorkers); }; setCaption_3(); observer.add('oilFactoryCheapWorkers', function () { return setCaption_3(); }); } } function addWandCaption() { for (var i = 0; i < WAND_LEVELS.length; i++) { var level = WAND_LEVELS[i]; var key = level + 'Wand'; var wandSpan = addSpan2ItemBox(key); if (wandSpan) { wandSpan.textContent = capitalize(level) + ' Wand'; } } } function addVariousCaptions() { var key2Name = { 'achievementBook': 'Achievements' , 'emptyAnvil': 'Anvil' , 'tap': 'Tree Tap' , 'farmer': 'Farmer' , 'gardener': 'Gardener' , 'planter': 'Planter' , 'boundBrewingKit': 'Brewing Kit' , 'cooksBook': 'Cooks Book' , 'cooksPage': 'Cooks Page' , 'combatDropTable': 'Loot Table' , 'magicBook': 'Spell Book' }; for (var key in key2Name) { var span = addSpan2ItemBox(key); if (span) { span.textContent = key2Name[key]; } } } // show current tier function addTierCaption() { addStyle("\nspan.item-box > span.orb::before\n{\n\tbackground-color: aqua;\n\tborder: 1px solid silver;\n\tborder-radius: 100%;\n\tcontent: '';\n\tdisplay: inline-block;\n\tmargin-left: -5px;\n\tmargin-right: 5px;\n\twidth: 10px;\n\theight: 10px;\n}\n\t\t"); function addOrbObserver(key, spanList) { var boundOrbKey = getBoundKey('Blue' + capitalize(key) + 'Orb'); function checkOrb() { var classAction = getGameValue(boundOrbKey) > 0 ? 'add' : 'remove'; for (var _i = 0, spanList_1 = spanList; _i < spanList_1.length; _i++) { var span = spanList_1[_i]; span.classList[classAction]('orb'); } } checkOrb(); observer.add(boundOrbKey, function () { return checkOrb(); }); } var remainingOrbItems = ORB_ITEMS; for (var _i = 0, TIER_ITEMS_2 = TIER_ITEMS; _i < TIER_ITEMS_2.length; _i++) { var tierItem = TIER_ITEMS_2[_i]; var isBindable = TIER_ITEMS_NOT_BINDABLE.indexOf(tierItem) === -1; var spanList = []; for (var i = 0; i < TIER_LEVELS.length; i++) { var key = getTierKey(tierItem, i); var toolKey = isBindable ? getBoundKey(key) : key; var tierSpan = addSpan2ItemBox(toolKey); if (tierSpan) { tierSpan.classList.add('tier'); tierSpan.textContent = TIER_NAMES[i]; spanList.push(tierSpan); } } var orbIndex = remainingOrbItems.indexOf(tierItem); if (orbIndex !== -1) { addOrbObserver(tierItem, spanList); remainingOrbItems.splice(orbIndex, 1); } } for (var _a = 0, remainingOrbItems_1 = remainingOrbItems; _a < remainingOrbItems_1.length; _a++) { var itemKey = remainingOrbItems_1[_a]; var captionSpan = document.querySelector('#item-box-' + getBoundKey(itemKey) + ' > span:last-of-type'); if (!captionSpan) { continue; } addOrbObserver(itemKey, [captionSpan]); } } var boatTimerKeys = BOAT_LIST.map(function (boatKey) { return boatKey + 'Timer'; }); function checkBoat(span, timerKey, init) { if (init === void 0) { init = false; } var isInTransit = getGameValue(timerKey) > 0; var otherInTransit = boatTimerKeys.some(function (k) { return k != timerKey && getGameValue(k) > 0; }); span.textContent = isInTransit ? 'In transit' : 'Ready'; span.style.visibility = otherInTransit ? 'hidden' : ''; var parent = span.parentElement; parent.style.opacity = otherInTransit ? '.5' : ''; if (init) { observer.add(boatTimerKeys, function () { return checkBoat(span, timerKey, false); }); } } // show boat progress function addBoatCaption() { addStyle("\n#item-box-boundSailBoat.item-box > span[data-item-display] + span + span\n{\n\tdisplay: none;\n}\n\t\t"); for (var i = 0; i < BOAT_LIST.length; i++) { var span = addSpan2ItemBox(getBoundKey(BOAT_LIST[i])); if (span) { checkBoat(span, boatTimerKeys[i], true); } } } // show bonemeal function addBonemealCaption() { var noBonemealSpan = addSpan2ItemBox('boundBonemealBin'); if (!noBonemealSpan) { return; } noBonemealSpan.textContent = 'Bonemeal: 0'; var bonemealSpan = addSpan2ItemBox('boundFilledBonemealBin'); if (!bonemealSpan) { return; } bonemealSpan.dataset.itemDisplay = 'bonemeal'; bonemealSpan.textContent = format.number(win.bonemeal); var captionSpan = document.createElement('span'); captionSpan.className = 'caption'; captionSpan.textContent = 'Bonemeal: '; bonemealSpan.parentElement.insertBefore(captionSpan, bonemealSpan); } function warningBeforeSellingGems() { var _sellNPCItemDialogue = win.sellNPCItemDialogue; win.sellNPCItemDialogue = function (item, amount) { if (item == 'sapphire' || item == 'emerald' || item == 'ruby' || item == 'diamond' || item == 'bloodDiamond') { var itemName = key2Name(amount == 1 ? item : item.replace(/y$/, 'ie') + 's', true); if (amount == 0 || !win.confirm('Gems are precious and rare. Please consider carefully:\nDo you really want to sell ' + amount + ' ' + itemName + '?')) { return; } } else if (item == 'logs' || item == 'oakLogs' || item == 'willowLogs' || item == 'mapleLogs' || item == 'stardustLogs' || item == 'ancientLogs') { var itemName = key2Name(amount == 1 ? item.replace(/s$/, '') : item, true); if (amount == 0 || !win.confirm('Logs are time consuming to collect. Please consider carefully:\nDo you really want to sell ' + amount + ' ' + itemName + '?')) { return; } } _sellNPCItemDialogue(item, amount); }; } function addWikiaLinks() { var WIKIA_CLASS = 'wikia-links'; addStyle("\n." + WIKIA_CLASS + " .item-box\n{\n\tposition: relative;\n}\n.item-box > .wikia-link\n{\n\tbackground-color: black;\n\tbackground-image: " + icons.getSvgAsUrl(icons.wrapCodeWithSvg(icons.WIKIA, '-2 -2 26 27', 30, 30)) + ";\n\tbackground-repeat: no-repeat;\n\tdisplay: none;\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 30px;\n\theight: 30px;\n}\n." + WIKIA_CLASS + " .item-box:hover > .wikia-link\n{\n\tdisplay: block;\n}\n\t\t"); function setWikiaLinksVisibility(init) { if (init === void 0) { init = false; } var show = settings.get(settings.KEY.wikiaLinks); document.body.classList[show ? 'add' : 'remove'](WIKIA_CLASS); if (init) { settings.observe(settings.KEY.wikiaLinks, function () { return setWikiaLinksVisibility(); }); } } setWikiaLinksVisibility(true); var boxes = document.getElementsByClassName('item-box'); function disableClickPropagation(el) { el.addEventListener('click', function (event) { event.stopPropagation(); }); } for (var i = 0; i < boxes.length; i++) { var box = boxes.item(i); var key = box.id.replace(/^item-box-/, ''); var linkArea = document.createElement('a'); linkArea.className = 'wikia-link'; linkArea.href = getWikiaLink(key); linkArea.target = '_blank'; disableClickPropagation(linkArea); box.appendChild(linkArea); var tooltipEl = ensureTooltip('wikiLink', linkArea); if (tooltipEl.innerHTML === '') { tooltipEl.innerHTML = "Click to open the wikia page about this item."; } } } function init() { addCaptionStyle(); addFurnaceCaption(); addOilStorageCaption(); addOilCaption(); addWandCaption(); addVariousCaptions(); addTierCaption(); addBoatCaption(); addBonemealCaption(); warningBeforeSellingGems(); addWikiaLinks(); } itemBoxes.init = init; })(itemBoxes || (itemBoxes = {})); /** * add new chat */ var chat; (function (chat) { chat.name = 'chat'; // min time difference between repeated messages to not be considered as spam var MIN_DIFF_REPEATED_MSG = 5e3; var KEYWORD_LIST_KEY = 'keywordList'; chat.keywordList = store.has(KEYWORD_LIST_KEY) ? store.get(KEYWORD_LIST_KEY) : []; var CHAT_HISTORY_KEY = 'chatHistory'; var MAX_CHAT_HISTORY_LENGTH = 100; var PM_HISTORY_KEY = 'pmHistory'; var MAX_PM_HISTORY_LENGTH = 50; var Type; (function (Type) { Type[Type["reload"] = -1] = "reload"; Type[Type["normal"] = 0] = "normal"; Type[Type["pmReceived"] = 1] = "pmReceived"; Type[Type["pmSent"] = 2] = "pmSent"; Type[Type["serverMsg"] = 3] = "serverMsg"; })(Type || (Type = {}));; var Tag; (function (Tag) { Tag[Tag["none"] = 0] = "none"; Tag[Tag["donor"] = 1] = "donor"; Tag[Tag["contributor"] = 2] = "contributor"; Tag[Tag["mod"] = 3] = "mod"; Tag[Tag["dev"] = 4] = "dev"; Tag[Tag["server"] = 5] = "server"; })(Tag || (Tag = {}));; /** * The chunk hiding starts with at least 10 chunks. * So there are at least * (chunkHidingMinChunks-1) * msgChunkSize + 1 = 9 * 100 + 1 = 901 * messages before the chunk hiding mechanism starts. */ var CHUNK_HIDING_MIN_CHUNKS = 10; var MSG_CHUNK_SIZE = 100; var RELOADED_CHAT_DATA = { timestamp: 0 , username: '' , userlevel: 0 , icon: 0 , tag: 0 , type: Type.reload , msg: '[...]' }; var CHAT_BOX_ID = 'div-chat'; var DEFAULT_CHAT_DIV_ID = 'div-chat-area'; var GENERAL_CHAT_DIV_ID = 'div-chat-general'; var PM_CHAT_TAB_PREFIX = 'tab-chat-pm-'; var PM_CHAT_DIV_PREFIX = 'div-chat-pm-'; var CHAT_TABS_ID = 'chat-tabs'; var CHAT_INPUT_ID = 'chat-input-text'; var CHAT_CLASS = 'div-chat-area'; var COLORIZE_CLASS = 'colorize'; var SpecialTab; (function (SpecialTab) { SpecialTab[SpecialTab["default"] = 0] = "default"; SpecialTab[SpecialTab["general"] = 1] = "general"; SpecialTab[SpecialTab["filler"] = 2] = "filler"; })(SpecialTab || (SpecialTab = {}));; var CHAT_SPECIAL_TAB_ID = (_a = {} , _a[SpecialTab.default] = 'tab-chat-default' , _a[SpecialTab.general] = 'tab-chat-general' , _a[SpecialTab.filler] = 'tab-chat-filler' , _a); var CONTEXTMENU_ID = 'player-contextmenu'; var CHAT_ICONS = [ { key: '' , title: '' } , { key: 'halloween2015' , title: 'Halloween Gamer (2015)' } , { key: 'christmas2015' , title: 'Chirstmas Gamer (2015)' } , { key: 'easter2016' , title: 'Easter Gamer (2016)' } , { key: 'halloween2016' , title: 'Halloween Gamer (2016)' } , { key: 'christmas2016' , title: 'Chirstmas Gamer (2016)' } , { key: 'dh1Max' , title: 'DH1 Pro' } , { key: 'hardcore' , title: 'Hardcore Player' } , { key: 'quest' , title: 'Questmaster' } , { key: 'maxMining' , title: 'Mastery in mining' } , { key: 'maxCrafting' , title: 'Mastery in crafting' } , { key: 'maxWC' , title: 'Mastery in woodcutting' } , { key: 'maxFarming' , title: 'Mastery in farming' } , { key: 'maxBrewing' , title: 'Mastery in brewing' } , { key: 'maxCombat' , title: 'Mastery in combat' } , { key: 'maxMagic' , title: 'Mastery in magic' } , { key: 'maxFishing' , title: 'Mastery in fishing' } , { key: 'maxCooking' , title: 'Mastery in cooking' } , { key: 'maxLevel' , title: 'Mastery of all skills' } , { key: 'birdcage' , title: 'Stole a birdcage' } , { key: 'achievement' , title: 'Achievement Hunter' }]; var getUnknownChatIcon = function (icon) { return { key: 'unknown' , title: '' , img: '<img src="images/chat-icons/' + icon + '.png" class="image-icon-20" />' }; }; var CHAT_TAGS = [ null , { key: 'donor' , name: '' } , { key: 'contributor' , name: 'Contributor' } , { key: 'mod' , name: 'Moderator' } , { key: 'dev' , name: 'Dev' } , { key: 'yell' , name: 'Server Message' } ]; var LOCALE = 'en-US'; var LOCALE_OPTIONS = { hour12: false , year: 'numeric' , month: 'long' , day: 'numeric' , hour: '2-digit' , minute: '2-digit' , second: '2-digit' }; // game commands var COMMANDS = [ 'pm' , 'mute' , 'clear' , 'ipmute' ]; var CLEAR_CMD = 'clear'; var TUTORIAL_CMD = 'tutorial'; // load chat history var chatHistory = store.get(CHAT_HISTORY_KEY) || []; var pmHistory = store.get(PM_HISTORY_KEY) || []; // store chat colors for each user var user2Color; var usedColors; // reserve color for special messages (e.g. server messages): white var reservedColors = ['#ffffff']; // message chunks var msgChunkMap = new Map(); // for adding elements at startup var chatboxFragments = new Map(); var chatInitialized = false; // find index of last message which is not a pm var isLastMsgNotReload = false; for (var i = chatHistory.length - 1; i >= 0; i--) { if (!isDataPM(chatHistory[i])) { isLastMsgNotReload = chatHistory[i].type != Type.reload; break; } } // insert a placeholder for a reloaded chat if (isLastMsgNotReload) { RELOADED_CHAT_DATA.timestamp = (new Date()).getTime(); chatHistory.push(RELOADED_CHAT_DATA); } function isMuted(user) { return user !== win.username && win.mutedPeople.some(function (name) { return user.indexOf(name) > -1; }); } function isSpam(data) { // allow all own messages, messages from contributors, mods, devs and all server messages if (data.username === win.username || data.tag != Tag.none) { return false; } /** * get last message of current user */ var historyIndex = chatHistory.indexOf(data); if (historyIndex == -1) { historyIndex = chatHistory.length; } var lastData = null; for (var i = historyIndex - 1; i >= 0 && (lastData === null); i--) { var dataBefore = chatHistory[i]; if (dataBefore.username === data.username) { lastData = dataBefore; } } /** * compare message and don't allow the same message twice */ if (lastData && lastData.msg === data.msg && (data.timestamp - lastData.timestamp) < MIN_DIFF_REPEATED_MSG) { return true; } return false; } function saveKeywordList() { store.set(KEYWORD_LIST_KEY, chat.keywordList); } function addKeyword(keyword) { if (keyword !== '' && chat.keywordList.indexOf(keyword) === -1) { chat.keywordList.push(keyword); saveKeywordList(); return true; } return false; } chat.addKeyword = addKeyword; function removeKeyword(keyword) { var index = chat.keywordList.indexOf(keyword); if (index !== -1) { chat.keywordList.splice(index, 1); saveKeywordList(); return true; } return false; } chat.removeKeyword = removeKeyword; function handleScrolling(chatbox) { if (win.isAutoScrolling) { setTimeout(function () { return chatbox.scrollTop = chatbox.scrollHeight; }); } } // for chat messages which arrive before DOMContentLoaded and can not be displayed since the DOM isn't ready function processChatData(username, iconString, tagString, msg, isPM) { var tag = parseInt(tagString, 10); var userlevel = 0; var type = Type.normal; if (isPM == 1) { var match = msg.match(/^\s*\[(PM from|Sent to) ([A-Za-z0-9_ ]+)\]: (.+?)\s*$/) || ['', '', username, msg]; type = match[1] == 'Sent to' ? Type.pmSent : Type.pmReceived; username = match[2]; if (username !== 'sexy_squid') { username = username.replace(/_/g, ' '); } msg = match[3]; } else if (tag == Tag.server) { type = Type.serverMsg; } else { var match = msg.match(/^\s*\((\d+)\): (.+?)\s*$/); if (match) { userlevel = parseInt(match[1], 10); msg = match[2]; } else { userlevel = win.getGlobalLevel(); } } // unlinkify when using DH2QoL to store the plain message if (win.addToChatBox.toString().includes('linkify(arguments[3])')) { msg = msg.replace(/<a href='([^']+)' target='_blank'>\1<\/a>/ig, '$1'); } if (type == Type.pmSent) { // turn some critical characters into HTML entities msg = msg.replace(/[<>]/g, function (char) { return '&#' + char.charCodeAt(0) + ';'; }); } return { timestamp: now() , username: username , userlevel: userlevel , icon: parseInt(iconString, 10) , tag: tag , type: type , msg: msg }; } function saveChatHistory() { store.set(CHAT_HISTORY_KEY, chatHistory); } function savePmHistory() { store.set(PM_HISTORY_KEY, pmHistory); } function add2ChatHistory(data) { if (data.type === Type.pmReceived || data.type === Type.pmSent) { pmHistory.push(data); pmHistory = pmHistory.slice(-MAX_PM_HISTORY_LENGTH); savePmHistory(); } else { chatHistory.push(data); chatHistory = chatHistory.slice(-MAX_CHAT_HISTORY_LENGTH); saveChatHistory(); } } function username2Id(username) { return username.replace(/ /g, '_'); } function setNewCounter(tab, num, force) { if (force === void 0) { force = false; } var panel = getChatPanel(tab.dataset.username || ''); if (force || !tab.classList.contains('selected') || !win.isAutoScrolling && panel.scrollHeight > panel.scrollTop + panel.offsetHeight) { tab.dataset.new = num.toString(); } } function incrementNewCounter(tab) { setNewCounter(tab, parseInt(tab.dataset.new || '0', 10) + 1); } function getChatTab(username, specialTab) { var id = (specialTab != null) ? CHAT_SPECIAL_TAB_ID[specialTab] : PM_CHAT_TAB_PREFIX + username2Id(username); var tab = document.getElementById(id); if (!tab) { tab = document.createElement('div'); tab.className = 'chat-tab'; if (specialTab != null) { tab.classList.add(SpecialTab[specialTab]); } tab.id = id; tab.dataset.username = username; setNewCounter(tab, 0, true); if (username.length > 2) { tab.textContent = username; // thanks /u/Spino-Prime for pointing out this was missing var closeSpan = document.createElement('span'); closeSpan.className = 'close'; tab.appendChild(closeSpan); } var chatTabs = document.getElementById(CHAT_TABS_ID); var filler = chatTabs.querySelector('.filler'); if (filler) { chatTabs.insertBefore(tab, filler); } else { chatTabs.appendChild(tab); } } return tab; } function getChatPanel(username) { var id = username == '' ? GENERAL_CHAT_DIV_ID : PM_CHAT_DIV_PREFIX + username2Id(username); var panel = document.getElementById(id); if (!panel) { panel = document.createElement('div'); panel.setAttribute('disabled', 'disabled'); panel.id = id; panel.className = CHAT_CLASS; var defaultChat = document.getElementById(DEFAULT_CHAT_DIV_ID); var height = defaultChat.style.height; panel.style.height = height; var chatDiv = defaultChat.parentElement; chatDiv.insertBefore(panel, defaultChat); } return panel; } function changeChatTab(oldTab, newTab) { if (oldTab) { oldTab.classList.remove('selected'); var oldChatPanel = void 0; if (oldTab.classList.contains('default')) { oldChatPanel = document.getElementById(DEFAULT_CHAT_DIV_ID); } else { oldChatPanel = getChatPanel(oldTab.dataset.username || ''); } oldChatPanel.classList.remove('selected'); } newTab.classList.add('selected'); setNewCounter(newTab, 0, true); var newChatPanel; if (newTab.classList.contains('default')) { newChatPanel = document.getElementById(DEFAULT_CHAT_DIV_ID); } else { newChatPanel = getChatPanel(newTab.dataset.username || ''); } newChatPanel.classList.add('selected'); var toUsername = newTab.dataset.username; var newTextPlaceholder = toUsername == '' ? win.username + ':' : 'PM to ' + toUsername + ':'; document.getElementById(CHAT_INPUT_ID).placeholder = newTextPlaceholder; handleScrolling(newChatPanel); } function clearChat(username) { if (username === '') { // clean server chat chatHistory = []; saveChatHistory(); } else { // delete pms stored for that user for (var i = 0; i < pmHistory.length; i++) { var data = pmHistory[i]; if (data.username == username) { pmHistory.splice(i, 1); i--; } } savePmHistory(); } // clear pm-chat panel var panel = getChatPanel(username); while (panel.children.length > 0) { panel.removeChild(panel.children[0]); } msgChunkMap.delete(username); return panel; } function closeChatTab(username) { // clear pm-chat panel and remove message-history clearChat(username); // remove pm-tab (and change tab if necessary) var selectedTab = getSelectedTab(); var tab2Close = getChatTab(username, null); if (selectedTab.dataset.username == username) { var generalTab = getChatTab('', SpecialTab.general); changeChatTab(tab2Close, generalTab); } var tabContainer = tab2Close.parentElement; tabContainer.removeChild(tab2Close); } function isDataPM(data) { return data.type === Type.pmSent || data.type === Type.pmReceived; } function colorizeMsg(username) { if (username == '') { return null; } if (!user2Color.has(username)) { var color = void 0; do { var colorizer = settings.getSub(settings.KEY.colorizeChat, 'colorizer'); if (colorizer == 1) { color = colorGenerator.getRandom( { luminosity: 'light' }); } else if (colorizer == 2) { color = colorGenerator.getRandom( { luminosity: 'dark' }); } else { color = colorGenerator.getEquallyDistributed(); } } while (usedColors.has(color)); user2Color.set(username, color); usedColors.add(color); addStyle("\n#" + CHAT_BOX_ID + "." + COLORIZE_CLASS + " .chat-msg[data-username=\"" + username + "\"]\n{\n\tbackground-color: " + color + ";\n}\n\t\t\t", 'name-color'); } return user2Color.get(username); } function createMessageSegment(data) { var isThisPm = isDataPM(data); var msgUsername = data.type === Type.pmSent ? win.username : data.username; var history = isThisPm ? pmHistory : chatHistory; var historyIndex = history.indexOf(data); var isSameUser = null; var isSameTime = null; for (var i = historyIndex - 1; i >= 0 && (isSameUser === null || isSameTime === null); i--) { var dataBefore = history[i]; if (isThisPm === isDataPM(dataBefore)) { if (isSameUser === null) { var beforeUsername = dataBefore.type == Type.pmSent ? win.username : dataBefore.username; isSameUser = beforeUsername === msgUsername; } if (dataBefore.type != Type.reload) { isSameTime = Math.floor(data.timestamp / 1000 / 60) - Math.floor(dataBefore.timestamp / 1000 / 60) === 0; } } } var d = new Date(data.timestamp); var hour = (d.getHours() < 10 ? '0' : '') + d.getHours(); var minute = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes(); var icon = CHAT_ICONS[data.icon] || getUnknownChatIcon(data.icon); var tag = CHAT_TAGS[data.tag] || { key: '' , name: '' }; var formattedMsg = data.msg .replace(/<a href='(.+?)' target='_blank'>\1<\/a>/g, '$1') .replace(/(https?:\/\/[^\s"<>]+)/g, '<a target="_blank" href="$1">$1</a>'); colorizeMsg(msgUsername); var msgTitle = data.type == Type.reload ? 'Chat loaded on ' + d.toLocaleString(LOCALE, LOCALE_OPTIONS) : ''; var user = data.type === Type.serverMsg ? 'Server Message' : msgUsername; var levelAppendix = data.type == Type.normal ? ' (' + data.userlevel + ')' : ''; var userTitle = data.tag != Tag.server ? tag.name : ''; return "<span class=\"chat-msg\" data-type=\"" + data.type + "\" data-tag=\"" + tag.key + "\" data-username=\"" + msgUsername + "\">" + ("<span\n\t\t\t\tclass=\"timestamp\"\n\t\t\t\tdata-timestamp=\"" + data.timestamp + "\"\n\t\t\t\tdata-same-time=\"" + isSameTime + "\">" + hour + ":" + minute + "</span>") + ("<span class=\"user\" data-name=\"" + msgUsername + "\" data-same-user=\"" + isSameUser + "\">") + ("<span class=\"icon " + icon.key + "\" title=\"" + icon.title + "\"></span>") + ("<span class=\"name chat-tag-" + tag.key + "\" title=\"" + userTitle + "\">" + user + levelAppendix + ":</span>") + "</span>" + ("<span class=\"msg\" title=\"" + msgTitle + "\">" + formattedMsg + "</span>") + "</span>"; } function add2Chat(data) { if (!chatInitialized) { return; } var isThisPm = isDataPM(data); // don't mute pms (you can just ignore pm-tab if you like) if (!isThisPm && isMuted(data.username)) { return; } var userKey = isThisPm ? data.username : ''; if (isThisPm) { win.lastPMUser = data.username; } // username is 3-12 characters long var chatbox = getChatPanel(userKey); var msgChunk = msgChunkMap.get(userKey); if (!msgChunk || msgChunk.children.length >= MSG_CHUNK_SIZE) { msgChunk = document.createElement('div'); msgChunk.className = 'msg-chunk'; msgChunkMap.set(userKey, msgChunk); if (chatboxFragments != null) { if (!chatboxFragments.has(userKey)) { chatboxFragments.set(userKey, document.createDocumentFragment()); } chatboxFragments.get(userKey).appendChild(msgChunk); } else { chatbox.appendChild(msgChunk); } } var tmp = document.createElement('templateWrapper'); tmp.innerHTML = createMessageSegment(data); msgChunk.appendChild(tmp.children[0]); handleScrolling(chatbox); // add delay because handleScrolling is will set scrollTop delayed setTimeout(function () { var chatTab = getChatTab(userKey, isThisPm ? null : SpecialTab.general); incrementNewCounter(chatTab); }); } function applyChatStyle() { addStyle("\ndiv.div-chat-area\n{\n\tpadding-left: 0;\n}\nspan.chat-msg\n{\n\tdisplay: flex;\n\tmin-height: 21px;\n\tpadding: 1px 0;\n\tpadding-left: 5px;\n}\n#" + CHAT_BOX_ID + ":not(." + COLORIZE_CLASS + ") span.chat-msg:nth-child(2n)\n{\n\tbackground-color: hsla(0, 0%, 90%, 1);\n}\n.chat-msg[data-type=\"" + Type.reload + "\"]\n{\n\tfont-size: 0.8rem;\n\tline-height: 1.2rem;\n}\n.chat-msg .timestamp\n{\n\tdisplay: none;\n}\n#" + CHAT_BOX_ID + ".showTimestamps .chat-msg:not([data-type=\"" + Type.reload + "\"]) .timestamp\n{\n\tcolor: hsla(0, 0%, 50%, 1);\n\tdisplay: inline-block;\n\tfont-size: .9rem;\n\tmargin: 0;\n\tmargin-right: 5px;\n\tposition: relative;\n\twidth: 2.5rem;\n}\n.chat-msg .timestamp[data-same-time=\"true\"]\n{\n\tcolor: hsla(0, 0%, 50%, .1);\n}\n.chat-msg:not([data-type=\"" + Type.reload + "\"]) .timestamp:hover::after\n{\n\tbackground-color: hsla(0, 0%, 12%, 1);\n\tborder-radius: .2rem;\n\tcontent: attr(data-fulltime);\n\tcolor: hsla(0, 0%, 100%, 1);\n\tline-height: 1.35rem;\n\tpadding: .4rem .8rem;\n\tpointer-events: none;\n\tposition: absolute;\n\tleft: 2.5rem;\n\ttop: -0.4rem;\n\ttext-align: center;\n\twhite-space: nowrap;\n}\n\n#" + CHAT_BOX_ID + ".showTags .chat-msg[data-type=\"" + Type.pmReceived + "\"] { color: purple; }\n#" + CHAT_BOX_ID + ".showTags .chat-msg[data-type=\"" + Type.pmSent + "\"] { color: purple; }\n#" + CHAT_BOX_ID + ".showTags .chat-msg[data-type=\"" + Type.serverMsg + "\"] { color: blue; }\n#" + CHAT_BOX_ID + ".showTags .chat-msg[data-tag=\"contributor\"] { color: green; }\n#" + CHAT_BOX_ID + ".showTags .chat-msg[data-tag=\"mod\"] { color: #669999; }\n#" + CHAT_BOX_ID + ".showTags .chat-msg[data-tag=\"dev\"] { color: #666600; }\n.chat-msg:not([data-type=\"" + Type.reload + "\"]) .user\n{\n\tflex: 0 0 132px;\n\tmargin-right: 5px;\n\twhite-space: nowrap;\n}\n#" + GENERAL_CHAT_DIV_ID + " .chat-msg:not([data-type=\"" + Type.reload + "\"]) .user\n{\n\tflex-basis: 182px;\n}\n#" + CHAT_BOX_ID + ".showIcons #" + GENERAL_CHAT_DIV_ID + " .chat-msg:not([data-type=\"" + Type.reload + "\"]) .user\n{\n\tpadding-left: 22px;\n}\n.chat-msg .user[data-same-user=\"true\"]:not([data-name=\"\"])\n{\n\tcursor: default;\n\topacity: 0;\n}\n\n.chat-msg .user .icon\n{\n\tdisplay: none;\n}\n#" + CHAT_BOX_ID + ".showIcons .chat-msg .user .icon\n{\n\tdisplay: inline-block;\n\tmargin-left: -22px;\n}\n.chat-msg .user .icon.unknown > img,\n.chat-msg .user .icon:not(.unknown)::before\n{\n\tbackground-size: 20px 20px;\n\tcontent: '';\n\tdisplay: inline-block;\n\tmargin-right: 2px;\n\twidth: 20px;\n\theight: 20px;\n\tvertical-align: middle;\n}\n.chat-msg .user .icon.halloween2015::before\t{ background-image: url('images/chat-icons/1.png'); }\n.chat-msg .user .icon.christmas2015::before\t{ background-image: url('images/chat-icons/2.png'); }\n.chat-msg .user .icon.easter2016::before\t{ background-image: url('images/chat-icons/3.png'); }\n.chat-msg .user .icon.halloween2016::before\t{ background-image: url('images/chat-icons/4.png'); }\n.chat-msg .user .icon.christmas2016::before\t{ background-image: url('images/chat-icons/5.png'); }\n.chat-msg .user .icon.dh1Max::before\t\t{ background-image: url('images/chat-icons/6.png'); }\n.chat-msg .user .icon.hardcore::before\t\t{ background-image: url('images/chat-icons/7.png'); }\n.chat-msg .user .icon.quest::before\t\t\t{ background-image: url('images/chat-icons/8.png'); }\n.chat-msg .user .icon.maxMining::before\t\t{ background-image: url('images/chat-icons/9.png'); }\n.chat-msg .user .icon.maxCrafting::before\t{ background-image: url('images/chat-icons/10.png'); }\n.chat-msg .user .icon.maxWC::before\t\t\t{ background-image: url('images/chat-icons/11.png'); }\n.chat-msg .user .icon.maxFarming::before\t{ background-image: url('images/chat-icons/12.png'); }\n.chat-msg .user .icon.maxBrewing::before\t{ background-image: url('images/chat-icons/13.png'); }\n.chat-msg .user .icon.maxCombat::before\t\t{ background-image: url('images/chat-icons/14.png'); }\n.chat-msg .user .icon.maxMagic::before\t\t{ background-image: url('images/chat-icons/15.png'); }\n.chat-msg .user .icon.maxFishing::before\t{ background-image: url('images/chat-icons/16.png'); }\n.chat-msg .user .icon.maxCooking::before\t{ background-image: url('images/chat-icons/17.png'); }\n.chat-msg .user .icon.maxLevel::before\t\t{ background-image: url('images/chat-icons/18.png'); }\n.chat-msg .user .icon.birdcage::before\t\t{ background-image: url('images/chat-icons/19.png'); }\n.chat-msg .user .icon.achievement::before\t{ background-image: url('images/chat-icons/20.png'); }\n\n.chat-msg .user:not([data-same-user=\"true\"]) .name\n{\n\tcolor: rgba(0, 0, 0, 0.7);\n\tcursor: pointer;\n}\n.chat-msg .user .name.chat-tag-donor::before\n{\n\tbackground-image: url('images/chat-icons/donor.png');\n\tbackground-size: 20px 20px;\n\tcontent: '';\n\tdisplay: inline-block;\n\theight: 20px;\n\twidth: 20px;\n\tvertical-align: middle;\n}\n.chat-msg .user .name.chat-tag-yell\n{\n\tcursor: default;\n}\n#" + CHAT_BOX_ID + ".showTags .chat-msg .user .name.chat-tag-contributor,\n#" + CHAT_BOX_ID + ".showTags .chat-msg .user .name.chat-tag-mod,\n#" + CHAT_BOX_ID + ".showTags .chat-msg .user .name.chat-tag-dev,\n#" + CHAT_BOX_ID + ".showTags .chat-msg .user .name.chat-tag-yell\n{\n\tcolor: white;\n\tdisplay: inline-block;\n\tfont-size: 10pt;\n\tmargin-bottom: -1px;\n\tmargin-top: -1px;\n\tpadding-bottom: 2px;\n\ttext-align: center;\n\t/* 2px border, 10 padding */\n\twidth: calc(100% - 2*1px - 2*5px);\n}\n#" + CHAT_BOX_ID + ":not(.showTags) .chat-msg .user .name.chat-tag-contributor,\n#" + CHAT_BOX_ID + ":not(.showTags) .chat-msg .user .name.chat-tag-mod,\n#" + CHAT_BOX_ID + ":not(.showTags) .chat-msg .user .name.chat-tag-dev,\n#" + CHAT_BOX_ID + ":not(.showTags) .chat-msg .user .name.chat-tag-yell\n{\n\tbackground: initial;\n\tborder: inherit;\n\tfont-family: inherit;\n\tfont-size: inherit;\n\tpadding: initial;\n}\n\n.chat-msg[data-type=\"" + Type.reload + "\"] .user > *,\n.chat-msg[data-type=\"" + Type.pmReceived + "\"] .user > .icon,\n.chat-msg[data-type=\"" + Type.pmSent + "\"] .user > .icon\n{\n\tdisplay: none;\n}\n\n.chat-msg .msg\n{\n\tmin-width: 0;\n\toverflow: hidden;\n\tword-wrap: break-word;\n}\n\n#" + CHAT_BOX_ID + " ." + CHAT_CLASS + "\n{\n\twidth: calc(100% - 5px);\n\theight: 130px;\n\tdisplay: none;\n}\n#" + CHAT_BOX_ID + " ." + CHAT_CLASS + ".selected\n{\n\tdisplay: block;\n}\n#" + CHAT_TABS_ID + "\n{\n\tdisplay: flex;\n\tmargin: 10px -5px -6px;\n\tflex-wrap: wrap;\n}\n#" + CHAT_TABS_ID + " .chat-tab\n{\n\tbackground-color: gray;\n\tborder-top: 1px solid black;\n\tborder-right: 1px solid black;\n\tcursor: pointer;\n\tdisplay: inline-block;\n\tfont-weight: normal;\n\tpadding: 0.3rem .6rem;\n\tposition: relative;\n}\n#" + CHAT_TABS_ID + " .chat-tab.selected\n{\n\tbackground-color: transparent;\n\tborder-top-color: transparent;\n}\n#" + CHAT_TABS_ID + " .chat-tab.default\n{\n\tdisplay: none;\n}\n#" + CHAT_TABS_ID + " .chat-tab.filler\n{\n\tbackground-color: hsla(0, 0%, 90%, 1);\n\tborder-right: 0;\n\tbox-shadow: inset 5px 5px 5px -5px rgba(0, 0, 0, 0.5);\n\tcolor: transparent;\n\tcursor: default;\n\tflex-grow: 1;\n}\n#" + CHAT_TABS_ID + " .chat-tab::after\n{\n\tcolor: white;\n\tcontent: '(' attr(data-new) ')';\n\tfont-size: .9rem;\n\tfont-weight: bold;\n\tmargin-left: .4rem;\n}\n#" + CHAT_TABS_ID + " .chat-tab.selected::after\n{\n\tcolor: gray;\n}\n#" + CHAT_TABS_ID + " .chat-tab[data-new=\"0\"]::after\n{\n\tcolor: inherit;\n\tfont-weight: normal;\n}\n#" + CHAT_TABS_ID + " .chat-tab:not(.general).selected::after,\n#" + CHAT_TABS_ID + " .chat-tab:not(.general):hover::after\n{\n\tvisibility: hidden;\n}\n#" + CHAT_TABS_ID + " .chat-tab:not(.general).selected .close::after,\n#" + CHAT_TABS_ID + " .chat-tab:not(.general):hover .close::after\n{\n\tcontent: '\u00D7';\n\tfont-size: 1.5rem;\n\tposition: absolute;\n\ttop: 0;\n\tright: .6rem;\n\tbottom: 0;\n}\n\n#" + CONTEXTMENU_ID + "\n{\n\tbox-shadow: rgba(0, 0, 0, 0.8) 4px 4px 4px -2px;\n\tposition: fixed;\n}\n#" + CONTEXTMENU_ID + " .ui-widget-header\n{\n\tcursor: default;\n\tpadding: .25rem;\n}\n\t\t"); } function initColorizer(init) { if (init === void 0) { init = false; } var usernameList = user2Color && Array.from(user2Color.keys()) || []; user2Color = new Map(); usedColors = new Set(); for (var _i = 0, reservedColors_1 = reservedColors; _i < reservedColors_1.length; _i++) { var color = reservedColors_1[_i]; usedColors.add(color); } var colorStyle = getStyle('name-color'); colorStyle.innerHTML = ''; for (var _a = 0, usernameList_1 = usernameList; _a < usernameList_1.length; _a++) { var username = usernameList_1[_a]; colorizeMsg(username); } if (init) { settings.observeSub(settings.KEY.colorizeChat, 'colorizer', function () { return initColorizer(); }); } } function addIntelligentScrolling() { // add checkbox instead of button for toggling auto scrolling var btn = document.querySelector('input[value="Toggle Autoscroll"]'); var btnParent = btn.parentElement; var checkboxId = 'chat-toggle-autoscroll'; // create checkbox var toggleCheckbox = document.createElement('input'); toggleCheckbox.type = 'checkbox'; toggleCheckbox.id = checkboxId; toggleCheckbox.checked = true; // create label var toggleLabel = document.createElement('label'); toggleLabel.htmlFor = checkboxId; toggleLabel.textContent = 'Autoscroll'; btnParent.insertBefore(toggleCheckbox, btn); btnParent.insertBefore(toggleLabel, btn); btn.style.display = 'none'; var chatArea = document.getElementById(GENERAL_CHAT_DIV_ID); var showScrollTextTimeout = null; function setAutoScrolling(value, full) { if (full === void 0) { full = false; } if (win.isAutoScrolling != value) { toggleCheckbox.checked = value; win.isAutoScrolling = value; var icon_2 = 'none'; var color_1 = value ? 'lime' : 'red'; var text_1 = (value ? 'En' : 'Dis') + 'abled' + (full ? ' Autoscroll' : ''); if (full) { if (showScrollTextTimeout) { win.clearTimeout(showScrollTextTimeout); } showScrollTextTimeout = win.setTimeout(function () { return win.scrollText(icon_2, color_1, text_1); }, 300); } else { win.scrollText(icon_2, color_1, text_1); } setNewCounter(getSelectedTab(), 0, true); return true; } return false; } toggleCheckbox.addEventListener('change', function () { setAutoScrolling(this.checked); if (this.checked && settings.get(settings.KEY.intelligentScrolling)) { chatArea.scrollTop = chatArea.scrollHeight - chatArea.clientHeight; } }); var placeholderTemplate = document.createElement('div'); placeholderTemplate.className = 'placeholder'; var childStore = new WeakMap(); function scrollHugeChat() { // # of children var chunkNum = chatArea.children.length; // start chunk hiding at a specific amount of chunks if (chunkNum < CHUNK_HIDING_MIN_CHUNKS) { return; } var visibleTop = chatArea.scrollTop; var visibleBottom = visibleTop + chatArea.clientHeight; var referenceTop = visibleTop - win.innerHeight; var referenceBottom = visibleBottom + win.innerHeight; var top = 0; // never hide the last element since its size may change at any time when a new message gets appended for (var i = 0; i < chunkNum - 1; i++) { var child = chatArea.children[i]; var height = child.clientHeight; var bottom = top + height; var isVisible = top >= referenceTop && top <= referenceBottom || bottom >= referenceTop && bottom <= referenceBottom || top < referenceTop && bottom > referenceBottom; var isPlaceholder = child.classList.contains('placeholder'); if (!isVisible && !isPlaceholder) { var newPlaceholder = placeholderTemplate.cloneNode(false); newPlaceholder.style.height = height + 'px'; chatArea.replaceChild(newPlaceholder, child); childStore.set(newPlaceholder, child); } else if (isVisible && isPlaceholder) { var oldChild = childStore.get(child); chatArea.replaceChild(oldChild, child); childStore.delete(child); } top = bottom; } } var delayedScrollStart = null; var delayedScrollTimeout = null; // does not consider pm tabs; may be changed in a future version? chatArea.addEventListener('scroll', function () { if (settings.get(settings.KEY.intelligentScrolling)) { var scrolled2Bottom = (chatArea.scrollTop + chatArea.clientHeight) >= chatArea.scrollHeight - 1; setAutoScrolling(scrolled2Bottom, true); } var n = now(); if (delayedScrollStart == null) { delayedScrollStart = n; } if (delayedScrollStart + 300 > n) { if (delayedScrollTimeout) { win.clearTimeout(delayedScrollTimeout); } delayedScrollTimeout = win.setTimeout(function () { delayedScrollStart = null; delayedScrollTimeout = null; scrollHugeChat(); }, 50); } }); } function getSelectedTab() { return document.querySelector('#' + CHAT_TABS_ID + ' .chat-tab.selected'); } function getSelectedTabUsername() { var selectedTab = getSelectedTab(); return selectedTab.dataset.username || ''; } function clickChatTab(newTab) { var oldTab = getSelectedTab(); if (newTab == oldTab) { return; } changeChatTab(oldTab, newTab); } function clickCloseChatTab(tab) { var username = tab.dataset.username || ''; var chatPanel = getChatPanel(username); if (chatPanel.children.length === 0 || confirm("Do you want to close the pm tab of \"" + username + "\"?")) { closeChatTab(username); } } function checkSetting(init) { if (init === void 0) { init = false; } var enabled = settings.get(settings.KEY.useNewChat); // dis-/enable chat tabs var chatTabs = document.getElementById(CHAT_TABS_ID); chatTabs.style.display = enabled ? '' : 'none'; // dis-/enable checkbox for intelligent scrolling var intelScrollId = 'chat-toggle-intelligent-scroll'; var input = document.getElementById(intelScrollId); if (input) { input.style.display = enabled ? '' : 'none'; } var label = document.querySelector('label[for="' + intelScrollId + '"]'); if (label) { label.style.display = enabled ? '' : 'none'; } // virtually click on a tab var defaultTab = getChatTab('', SpecialTab.default); var generalTab = getChatTab('', SpecialTab.general); clickChatTab(enabled ? generalTab : defaultTab); if (init) { settings.observe(settings.KEY.useNewChat, function () { return checkSetting(false); }); } } function addChatTabs() { var chatBoxArea = document.getElementById(CHAT_BOX_ID); var chatTabs = document.createElement('div'); chatTabs.id = CHAT_TABS_ID; chatTabs.addEventListener('click', function (event) { var newTab = event.target; if (newTab.classList.contains('close')) { return clickCloseChatTab(newTab.parentElement); } if (!newTab.classList.contains('chat-tab') || newTab.classList.contains('filler')) { return; } clickChatTab(newTab); }); chatBoxArea.appendChild(chatTabs); // default tab (for disabled new chat) getChatTab('', SpecialTab.default); // general server chat var generalTab = getChatTab('', SpecialTab.general); generalTab.textContent = 'Server'; getChatPanel(''); getChatTab('', SpecialTab.filler); var _sendChat = win.sendChat; win.sendChat = function (inputEl) { var msg = inputEl.value; var selectedTab = document.querySelector('.chat-tab.selected'); if (selectedTab.dataset.username != '' && msg[0] != '/') { inputEl.value = '/pm ' + (selectedTab.dataset.username || '').replace(/ /g, '_') + ' ' + msg; } _sendChat(inputEl); }; } function switch2PmTab(username) { var newTab = getChatTab(username, null); clickChatTab(newTab); } function notifyPm(data) { notifications.event('Message from "' + data.username + '"' , { body: data.msg , onclick: function () { return switch2PmTab(data.username); } , whenActive: getSelectedTab().dataset.username != data.username }); } function checkMentionAndKeywords(data) { var lowerMsg = data.msg.toLowerCase(); var usernameRegex = new RegExp('\\b' + win.username + '\\b', 'i'); if (settings.getSub(settings.KEY.showNotifications, 'mention') && usernameRegex.test(lowerMsg)) // if (lowerMsg.indexOf(win.username) > -1) { notifications.event('You\'ve been mentioned' , { body: data.msg }); } var match = []; for (var _i = 0, keywordList_1 = chat.keywordList; _i < keywordList_1.length; _i++) { var keyword = keywordList_1[_i]; var regex = new RegExp('\\b' + keyword + '\\b', 'i'); if (regex.test(lowerMsg)) // if (lowerMsg.indexOf(keyword) > -1) { match.push(keyword); } } if (settings.getSub(settings.KEY.showNotifications, 'keyword') && match.length > 0) { notifications.event('Keyword: "' + match.join('", "') + '"' , { body: data.msg }); } } var addToChatBox_ = null; function newAddToChatBox(username, icon, tag, msg, isPM) { var data = processChatData(username, icon, tag, msg, isPM); var isThisSpam = false; if (isDataPM(data)) { if (data.type == Type.pmSent) { switch2PmTab(data.username); } else { notifyPm(data); } } else { isThisSpam = settings.get(settings.KEY.enableSpamDetection) && isSpam(data); if (!isThisSpam && data.username != win.username) { // check mentioning and keywords only for non-pms and only for messages from other players checkMentionAndKeywords(data); } } if (isThisSpam) { console.info('detected spam:', data); } else { add2ChatHistory(data); add2Chat(data); } var fn = addToChatBox_ == null ? win.addToChatBox : addToChatBox_; fn(username, icon, tag, msg, isPM); } chat.newAddToChatBox = newAddToChatBox; function openPmTab(username) { if (username == win.username || username == '') { return; } var userTab = getChatTab(username, null); clickChatTab(userTab); var input = document.getElementById(CHAT_INPUT_ID); input.focus(); } function newChat() { addChatTabs(); applyChatStyle(); initColorizer(true); addToChatBox_ = win.addToChatBox; win.addToChatBox = newAddToChatBox; chatInitialized = true; var chatbox = document.getElementById(CHAT_BOX_ID); chatbox.addEventListener('click', function (event) { var target = event.target; var userEl = target && target.parentElement; if (!target || !userEl || !target.classList.contains('name') || !userEl.classList.contains('user')) { return; } if (userEl.dataset.sameUser != 'true') { openPmTab(userEl.dataset.name || ''); } }); chatbox.addEventListener('mouseover', function (event) { var target = event.target; if (!target.classList.contains('timestamp') || !target.dataset.timestamp) { return; } var timestamp = parseInt(target.dataset.timestamp || '0', 10); target.dataset.fulltime = (new Date(timestamp)).toLocaleDateString(LOCALE, LOCALE_OPTIONS); target.dataset.timestamp = ''; }); // add context menu var contextmenu = document.createElement('ul'); contextmenu.id = CONTEXTMENU_ID; contextmenu.style.display = 'none'; contextmenu.innerHTML = "<li class=\"name ui-widget-header\"><div></div></li>\n\t\t<li class=\"open-pm\"><div>Open pm tab</div></li>\n\t\t<li class=\"stats\"><div>Open stats</div></li>\n\t\t<li class=\"mute\"><div>Mute</div></li>\n\t\t<li class=\"unmute\"><div>Unmute</div></li>"; document.body.appendChild(contextmenu); win.$(contextmenu).menu( { items: '> :not(.ui-widget-header)' }); var nameListEl = contextmenu.querySelector('.name'); var nameDivEl = nameListEl.firstElementChild; var muteEl = contextmenu.querySelector('.mute'); var unmuteEl = contextmenu.querySelector('.unmute'); chatbox.addEventListener('contextmenu', function (event) { var target = event.target; var userEl = target && target.parentElement; if (!userEl || !userEl.classList.contains('user')) { return; } var username = userEl.dataset.name; // ignore clicks on server messages or other special messages if (!username || userEl.dataset.sameUser == 'true') { return; } contextmenu.style.left = event.clientX + 'px'; contextmenu.style.top = event.clientY + 'px'; contextmenu.style.display = ''; contextmenu.dataset.username = username; nameDivEl.textContent = username; var isMuted = win.mutedPeople.indexOf(username) !== -1; muteEl.style.display = isMuted ? 'none' : ''; unmuteEl.style.display = isMuted ? '' : 'none'; event.stopPropagation(); event.preventDefault(); }); // add click listener for context menu and stop propagation contextmenu.addEventListener('click', function (event) { var target = event.target; event.stopPropagation(); while (target && target.id != CONTEXTMENU_ID && target.tagName != 'LI') { target = target.parentElement; } if (!target || target.id == CONTEXTMENU_ID) { return; } var username = contextmenu.dataset.username || ''; if (target.classList.contains('open-pm')) { openPmTab(username); } else if (target.classList.contains('stats')) { win.lookup(username); } else if (target.classList.contains('mute')) { if (username == '') { return; } win.mutedPeople.push(username); win.scrollText('none', 'lime', '<em>' + username + '</em> muted'); } else if (target.classList.contains('unmute')) { if (username == '') { return; } var index = win.mutedPeople.indexOf(username); if (index !== -1) { win.mutedPeople.splice(index, 1); } win.scrollText('none', 'red', '<em>' + username + '</em> unmuted'); } else { return; } contextmenu.style.display = 'none'; }); // add click listener to hide context menu document.addEventListener('click', function (event) { if (contextmenu.style.display != 'none') { contextmenu.style.display = 'none'; } }); win.addEventListener('contextmenu', function (event) { if (contextmenu.style.display != 'none') { contextmenu.style.display = 'none'; } }); // handle settings var showSettings = [settings.KEY.showTimestamps, settings.KEY.showIcons, settings.KEY.showTags]; function setShowSetting(key) { var enabled = settings.get(key); chatbox.classList[enabled ? 'add' : 'remove'](settings.KEY[key]); } for (var _i = 0, showSettings_1 = showSettings; _i < showSettings_1.length; _i++) { var key = showSettings_1[_i]; setShowSetting(key); settings.observe(key, function (k) { return setShowSetting(k); }); } } function addCommandSuggester() { var input = document.getElementById(CHAT_INPUT_ID); input.addEventListener('keyup', function (event) { if (event.key == 'Backspace' || event.key == 'Delete' || event.key == 'Enter' || event.key == 'Tab' || input.selectionStart != input.selectionEnd || input.selectionStart != input.value.length || !input.value.startsWith('/')) { return; } var value = input.value.substr(1); for (var _i = 0, COMMANDS_1 = COMMANDS; _i < COMMANDS_1.length; _i++) { var cmd = COMMANDS_1[_i]; if (cmd.startsWith(value)) { input.value = '/' + cmd; input.selectionStart = 1 + value.length; input.selectionEnd = input.value.length; break; } } }); } function addOwnCommands() { COMMANDS.push(TUTORIAL_CMD); function processOwnCommands(value) { if (!value.startsWith('/')) { return value; } var msgPrefix = '/'; var msg = value.substr(1); if (msg.startsWith('pm')) { var split = msg.split(' '); msgPrefix = '/' + split.slice(0, 2).join(' ') + ' '; msg = split.slice(2).join(' '); } if (msg.startsWith(CLEAR_CMD)) { // clear current chat (pm chat, or general chat) var username = getSelectedTabUsername(); clearChat(username); } else if (msg.startsWith(TUTORIAL_CMD)) { // thanks aguyd (https://greasyfork.org/forum/profile/aguyd) for the idea var name_2 = msg.substr(TUTORIAL_CMD.length).trim(); msgPrefix = ''; msg = 'https://www.reddit.com/r/DiamondHunt/comments/5vrufh/diamond_hunt_2_starter_faq/'; if (name_2.length != 0) { // maybe add '@' before the name? msg = name_2 + ', ' + msg; } } return msgPrefix + msg; } var _sendChat = win.sendChat; win.sendChat = function (inputEl) { inputEl.value = processOwnCommands(inputEl.value); _sendChat(inputEl); }; } function checkColorize(init) { if (init === void 0) { init = false; } var chatDiv = document.getElementById(CHAT_BOX_ID); chatDiv.classList[settings.get(settings.KEY.colorizeChat) ? 'add' : 'remove'](COLORIZE_CLASS); if (init) { settings.observe(settings.KEY.colorizeChat, function () { return checkColorize(false); }); } } function init() { newChat(); addIntelligentScrolling(); addCommandSuggester(); addOwnCommands(); checkColorize(true); checkSetting(true); var _enlargeChat = win.enlargeChat; var chatBoxArea = document.getElementById(CHAT_BOX_ID); function setChatBoxHeight(height) { var defaultChat = document.getElementById(DEFAULT_CHAT_DIV_ID); defaultChat.style.height = height; var generalChat = document.getElementById(GENERAL_CHAT_DIV_ID); generalChat.style.height = height; var chatDivs = chatBoxArea.querySelectorAll('div[id^="' + PM_CHAT_DIV_PREFIX + '"]'); for (var i = 0; i < chatDivs.length; i++) { chatDivs[i].style.height = height; } } win.enlargeChat = function (enlargeB) { _enlargeChat(enlargeB); var defaultChatDiv = document.getElementById(DEFAULT_CHAT_DIV_ID); var height = defaultChatDiv.style.height; store.set('chat.height', height); setChatBoxHeight(height); handleScrolling(defaultChatDiv); }; setChatBoxHeight(store.get('chat.height')); // add history to chat // TEMP >>> // move pm entries to pm history var changed = false; for (var i = 0; i < chatHistory.length; i++) { var data = chatHistory[i]; if (isDataPM(data)) { chatHistory.splice(i, 1); i--; pmHistory.push(data); changed = true; } } if (changed) { saveChatHistory(); savePmHistory(); } // TEMP <<< chatHistory.forEach(function (d) { return add2Chat(d); }); pmHistory.forEach(function (d) { return add2Chat(d); }); if (chatboxFragments) { chatboxFragments.forEach(function (fragment, key) { var chatbox = getChatPanel(key); chatbox.appendChild(fragment); }); chatboxFragments = null; } // reset the new counter for all tabs var tabs = document.querySelectorAll('.chat-tab'); for (var i = 0; i < tabs.length; i++) { setNewCounter(tabs[i], 0, true); } } chat.init = init; var _a; })(chat || (chat = {})); /** * hopefully only temporary fixes */ var temporaryFixes; (function (temporaryFixes) { temporaryFixes.name = 'temporaryFixes'; // update spells being clickable in combat function setSpellsClickable() { var spellbox = document.getElementById('fight-spellboox'); if (spellbox) { for (var i = 0; i < spellbox.children.length; i++) { var child = spellbox.children.item(i); if (!win.isInCombat() && child.hasAttribute('onclick')) { child.dataset.onclick = child.getAttribute('onclick') || ''; child.removeAttribute('onclick'); } else if (win.isInCombat() && !!child.dataset.onclick) { child.setAttribute('onclick', child.dataset.onclick || ''); child.dataset.onclick = ''; } } } } // warn before unloading/reloading the tab if combat is in progress function combatWarnOnUnload() { if (!win.isInCombat()) { win.onbeforeunload = null; } else { if (win.onbeforeunload == null) { win.onbeforeunload = function () { return 'You are in a fight!'; }; } } } function fixCombatCountdown() { var el = document.getElementById('combat-countdown'); if (!el) { return; } if (win.isInCombat()) { el.style.display = ''; var visible = win.combatCommenceTimer != 0; el.style.visibility = visible ? '' : 'hidden'; } } // fix exhaustion timer and updating brewing and cooking recipes function fixExhaustionTimer() { if (document.getElementById('tab-container-combat').style.display != 'none') { win.combatNotFightingTick(); } } function fixClientGameLoop() { var _clientGameLoop = win.clientGameLoop; win.clientGameLoop = function () { _clientGameLoop(); setSpellsClickable(); combatWarnOnUnload(); fixCombatCountdown(); fixExhaustionTimer(); }; } // fix elements of scrollText (e.g. when joining the game and receiving xp at that moment) function fixScroller() { var textEls = document.querySelectorAll('div.scroller'); for (var i = 0; i < textEls.length; i++) { var scroller = textEls[i]; if (scroller.style.position != 'absolute') { scroller.style.display = 'none'; } } } // fix style of tooltips function fixTooltipStyle() { addStyle("\nbody > div.tooltip > h2:first-child\n{\n\tmargin-top: 0;\n\tfont-size: 20pt;\n\tfont-weight: normal;\n}\n\t\t"); } // fix buiulding magic table dynamically function fixRefreshingMagicRecipes() { // define missing properties for checking the needed materials win.enchantStargemPotionMagic = 0; win.changeWeatherMagic = 0; win.refreshLoadMagicTable = true; var _processMagicTab = win.processMagicTab; win.processMagicTab = function () { var _refreshLoadCraftingTable = win.refreshLoadCraftingTable; win.refreshLoadCraftingTable = win.refreshLoadMagicTable; _processMagicTab(); win.refreshLoadCraftingTable = _refreshLoadCraftingTable; if (win.magicPage3 == 1) { win.showMateriesNeededAndLevelLabelsMagic('enchantStargemPotion'); win.showMateriesNeededAndLevelLabelsMagic('beam'); win.showMateriesNeededAndLevelLabelsMagic('changeWeather'); } }; } function moveItemBox(itemKey, targetElId, color1, color2) { var itemBox = document.getElementById('item-box-' + itemKey); var targetContainer = document.getElementById(targetElId); targetContainer.appendChild(itemBox); // remove event listeners before binding the tooltip to it var $itemBox = win.$(itemBox); $itemBox.off('mouseover').off('mouseleave'); itemBox.title = ''; // bind tooltip to item box ensureTooltip('ingredient-secondary', itemBox); // change color itemBox.style.background = 'linear-gradient(' + color1 + ', ' + color2 + ')'; $itemBox .mouseover(function () { itemBox.style.background = 'none'; itemBox.style.backgroundColor = color2; }) .mouseleave(function () { itemBox.style.background = 'linear-gradient(' + color1 + ', ' + color2 + ')'; }); } // move the strange leaf to brewing tab (thanks lasse_brus for this idea) function moveStrangeLeafs() { moveItemBox('strangeLeaf', 'tab-sub-container-brewing', '#800080', '#990099'); moveItemBox('strangerLeaf', 'tab-sub-container-brewing', '#800080', '#990099'); } // fix height of map item function fixTreasureMap() { var mapBox = document.getElementById('item-box-treasureMap'); var numSpan = mapBox.lastElementChild; numSpan.style.display = ''; numSpan.style.visibility = 'hidden'; } // fix wobbling tree places on hover (in wood cutting) function fixWoodcutting() { addStyle("\nimg.woodcutting-tree-img\n{\n\tborder: 1px solid transparent;\n}\n\t\t"); } // fix wobbling quest rows on hover (in quest book) function fixQuestBook() { addStyle("\n#table-quest-list tr\n{\n\tborder: 1px solid transparent;\n}\n\t\t"); } function fixScrollImages() { function fixIcon(icon) { return icon + (icon != 'none' && !/\..{3,4}$/.test(icon) ? '.png' : ''); } var _scrollTextHitSplat = win.scrollTextHitSplat; win.scrollTextHitSplat = function (icon, color, text, elId, cbType) { _scrollTextHitSplat(fixIcon(icon), color, text, elId, cbType); }; var _scrollText = win.scrollText; win.scrollText = function (icon, color, text) { _scrollText(fixIcon(icon), color, text); }; } function fixQuest8BraveryRecipe() { observer.add([ 'quest8' , 'braveryPotion' ], function () { var show = win.quest8 > 0 && win.braveryPotion == 0; var recipe = document.getElementById('brewing-braveryPotion'); if (recipe) { recipe.style.display = show ? '' : 'none'; } }); } function fixHitText() { win.scrollTextHitSplat = function (icon, color, text, elId, cbType) { var imgTag = icon != 'none' ? "<img src=\"images/" + icon + "\" class=\"image-icon-50\" />" : ''; var elementChosen = document.getElementById(elId); if (!elementChosen) { return; } var rect = elementChosen.getBoundingClientRect(); var xCoord = (rect.left + rect.right) / 2; var yCoord = (rect.bottom + rect.top) / 2; var extraStyle = ''; if (cbType == 'melee') { extraStyle = 'border: 1px solid red; background-color: #4d0000;'; } else if (cbType == 'heal') { extraStyle = 'border: 1px solid green; background-color: lime;'; } var $elementToAppend = win.$("<div class=\"scroller\" style=\"" + extraStyle + " color: " + color + "; position: fixed;\">" + imgTag + text + "</div>").appendTo('body'); if (xCoord == 0 && yCoord == 0) { var tab = document.getElementById('tab-container-bar-combat'); var tabRect = tab.getBoundingClientRect(); var boxRect = $elementToAppend.get(0).getBoundingClientRect(); xCoord = elId == 'img-hero' ? (tabRect.left - boxRect.width) : tabRect.right; yCoord = tabRect.top; } $elementToAppend .css( { left: xCoord , top: yCoord }) .animate( { top: '-=50px' }, function () { return $elementToAppend.fadeOut(1000, function () { return $elementToAppend.remove(); }); }); }; } function fixBoatTooltips() { var boatBox = document.getElementById('item-box-boundRowBoat'); var boatTooltip = boatBox && document.getElementById(boatBox.dataset.tooltipId || ''); var tooltipParent = boatTooltip && boatTooltip.parentElement; if (!boatBox || !boatTooltip || !tooltipParent) { return; } function setTripDuration(durationEl, boatKey) { var durationStr = TRIP_DURATION.hasOwnProperty(boatKey) ? TRIP_DURATION[boatKey].toString(10) : '?'; durationEl.innerHTML = "<strong>Trip duration:</strong> " + durationStr + " hours"; } boatTooltip.id = boatBox.dataset.tooltipId = 'tooltip-boundRowBoat'; boatTooltip.appendChild(document.createElement('br')); var boatDuration = document.createElement('span'); boatDuration.className = 'trip-duration'; setTripDuration(boatDuration, 'rowBoat'); boatTooltip.appendChild(boatDuration); for (var _i = 0, BOAT_LIST_1 = BOAT_LIST; _i < BOAT_LIST_1.length; _i++) { var boatKey = BOAT_LIST_1[_i]; var boundKey = getBoundKey(boatKey); var itemBox = document.getElementById('item-box-' + boundKey); if (!itemBox) { continue; } var tooltip = document.getElementById('tooltip-' + boundKey); if (!tooltip) { tooltip = boatTooltip.cloneNode(true); tooltip.id = 'tooltip-' + boundKey; var header = tooltip.firstElementChild; header.textContent = capitalize(split2Words(boatKey)); tooltipParent.appendChild(tooltip); itemBox.dataset.tooltipId = 'tooltip-' + boundKey; } var durationEl = tooltip.getElementsByClassName('trip-duration').item(0); if (durationEl) { setTripDuration(durationEl, boatKey); } } } function fixAlignments() { addStyle("\nspan.item-box[id^=\"item-box-\"] > img:not(.image-icon-100),\nspan.item-box[id^=\"item-box-\"] > span > img\n{\n\tmargin-top: -2px;\n}\n\n#tab-container-crafting .settings-container\n{\n\tmargin: 5px 30px;\n}\n#table-crafting-recipe,\n#table-brewing-recipe,\n#table-magic-recipe\n{\n\twidth: calc(100% - 2*20px - 2*10px);\n}\n#tab-sub-container-magic-items\n{\n\tmargin: 5px 0px;\n}\n#table-magic-recipe\n{\n\twidth: calc(100% - 2*10px);\n}\n\n#tab-container-farming\n{\n\tpadding: 0 20px;\n}\n#tab-sub-container-farming\n{\n\tmargin: 5px 0;\n\tmargin-bottom: -10px;\n}\ndiv.farming-patch,\ndiv.farming-patch-locked\n{\n\tmargin: 10px;\n}\nimg.farming-patch-img\n{\n\twidth: 349px;\n\theight: 400px;\n}\n/* fix position of some plant images */\nimg.farming-patch-img[src$=\"/3_1.png\"]\n{\n\theight: 398px;\n\tmargin-top: -2px;\n\tmargin-bottom: 4px;\n}\nimg.farming-patch-img[src$=\"/3_2.png\"]\n{\n\theight: 399px;\n\tmargin-top: -1px;\n\tmargin-bottom: 2px;\n\tmargin-left: 2px;\n\tmargin-right: -2px;\n}\nimg.farming-patch-img[src$=\"/3_4.png\"]\n{\n\tmargin-top: 1px;\n\tmargin-bottom: -1px;\n\tmargin-left: -2px;\n\tmargin-right: 2px;\n}\n\n#combat-table-area\n{\n\tborder-spacing: 0;\n}\n#combat-table-area > tbody > tr > td\n{\n\tvertical-align: top;\n}\ndiv#hero-area.hero,\ndiv#monster-area.monster\n{\n\tmargin-left: 20px;\n\tmargin-right: 20px;\n\tmargin-top: 10px;\n}\ntable.table-hero-stats,\ndiv.hp-bar,\n#hero-area div.fight-spellbook\n{\n\tmargin-left: 0;\n}\ndiv.hp-bar\n{\n\tmin-width: calc(100% - 2px);\n}\n#hero-area div.fight-spellbook\n{\n\tmargin: 0 -3px;\n}\n#hero-area span.fight-spell\n{\n\tmargin-bottom: 0;\n\tmargin-top: 0;\n}\n#hero-area > div:last-child,\n.imageMonster\n{\n\theight: 556px !important;\n\tmargin-top: -50px;\n}\n#monster-area div.hp-bar\n{\n\tmargin-top: 66px;\n\tmargin-bottom: 74px;\n}\n#monster-area > br:first-child,\n#monster-area table.table-hero-stats + br\n{\n\tdisplay: none;\n}\n.imageMonster\n{\n\talign-items: flex-end;\n\tdisplay: flex;\n\tposition: relative;\n}\n#combat-table-area[style$=\"auto;\"]\n{\n\tborder-color: transparent;\n}\n#img-monster\n{\n\tposition: absolute;\n}\n#img-monster[src$=\"/1.png\"]\n{\n\theight: 250px;\n}\n#img-monster[src$=\"/2.png\"]\n{\n\ttransform: translateY(30px);\n}\n#img-monster[src$=\"/3.png\"]\n{\n\theight: 180px;\n\ttransform: translateY(-350px);\n}\n#img-monster[src$=\"/4.png\"]\n{\n\theight: 180px;\n}\n#img-monster[src$=\"/5.png\"]\n{\n\theight: 700px;\n\ttransform: translateY(130px);\n}\n#img-monster[src$=\"/7.png\"]\n{\n\theight: 450px;\n\ttransform: translateY(30px);\n}\n#img-monster[src$=\"/8.png\"]\n{\n\theight: 280px;\n\ttransform: translateY(-260px);\n}\n#img-monster[src$=\"/9.png\"]\n{\n\theight: 450px;\n\ttransform: translateY(-10px);\n}\n#img-monster[src$=\"/11.png\"],\n#img-monster[src$=\"/15.png\"]\n{\n\ttransform: translateY(-180px);\n}\n#img-monster[src$=\"/14.png\"]\n{\n\theight: 500px;\n\tmargin-left: -50px;\n\tmargin-right: -50px;\n}\n#img-monster[src$=\"/100.png\"]\n{\n\theight: 300px;\n}\n#img-monster[src$=\"/101.png\"]\n{\n\ttransform: translateY(-10px);\n}\n#tab-sub-container-combat > .large-button > .image-icon-50\n{\n\theight: 70px;\n\tmargin-top: -10px;\n\twidth: 70px;\n}\n#combat-table-area span.large-button,\n#combat-table-area span.medium-button\n{\n\tmargin: 10px;\n}\n#combat-table-area span.large-button\n{\n\tfont-size: 3rem;\n}\n#combat-table-area span.medium-button + br + br\n{\n\tdisplay: none;\n}\n\t\t"); } function addHeroStatTooltips() { var table = document.querySelector('#hero-area table.table-hero-stats'); if (!table) { return; } var statRow = table.rows.item(0); var attackCell = statRow.cells.item(0); attackCell.title = 'Attack Damage'; win.$(attackCell).tooltip(); var accuracyCell = statRow.cells.item(1); accuracyCell.title = 'Attack Accuracy'; win.$(accuracyCell).tooltip(); var speedCell = statRow.cells.item(2); speedCell.title = 'Attack Speed'; win.$(speedCell).tooltip(); var defenseCell = statRow.cells.item(3); defenseCell.title = 'Defense'; win.$(defenseCell).tooltip(); } function unifyTooltips() { function getLastNonEmptyChild(parent) { for (var i = parent.childNodes.length - 1; i >= 0; i--) { var child = parent.childNodes.item(i); if (child.nodeType === Node.TEXT_NODE && (child.textContent || '').trim() !== '') { return null; } else if (child.nodeType === Node.ELEMENT_NODE) { return child; } } return null; } // clean unnecessary br-tags in tooltips var tooltips = document.querySelectorAll('#tooltip-list > div[id^="tooltip-"]'); for (var i = 0; i < tooltips.length; i++) { var tooltip = tooltips[i]; var lneChild = void 0; while ((lneChild = getLastNonEmptyChild(tooltip)) && lneChild.tagName == 'BR') { tooltip.removeChild(lneChild); } } function getTooltip(item) { return document.getElementById('tooltip-' + item); } var boldify = [ 'oilBarrel' , 'boundEmptyPickaxe' , 'boundEmptyShovel' , 'boundRocket' , 'ashes' , 'iceBones' ]; var lastDotRegex = /\.\s*$/; for (var _i = 0, boldify_1 = boldify; _i < boldify_1.length; _i++) { var item = boldify_1[_i]; var tooltip = getTooltip(item); if (!tooltip) { continue; } var textNode = tooltip.lastChild; while (textNode && (textNode.nodeType != Node.TEXT_NODE || (textNode.textContent || '').trim() === '')) { if (textNode.nodeName === 'SPAN') { textNode = textNode.lastChild; } else { textNode = textNode.previousSibling; } } if (!textNode) { continue; } var text = textNode.textContent || ''; var split = text.split(/\.(?=\s*\S+)/); var clickText = split[split.length - 1]; textNode.textContent = text.replace(clickText, ''); if (split.length > 1) { tooltip.appendChild(document.createElement('br')); tooltip.appendChild(document.createElement('br')); } var boldText = document.createElement('b'); boldText.textContent = clickText; tooltip.appendChild(boldText); } function prepareTooltip(item, editText, createOnMissing) { if (createOnMissing === void 0) { createOnMissing = false; } var tooltip = getTooltip(item); if (!tooltip) { return; } // try to find the b-node: var bNode = getLastNonEmptyChild(tooltip); if (bNode && bNode.tagName === 'SPAN') { bNode = getLastNonEmptyChild(bNode); } if (!bNode || bNode.tagName !== 'B') { if (!createOnMissing) { bNode = null; } else { tooltip.appendChild(document.createElement('br')); tooltip.appendChild(document.createElement('br')); bNode = document.createElement('b'); tooltip.appendChild(bNode); } } if (bNode) { bNode.textContent = editText(bNode); } } // remove dots for (var i = 0; i < tooltips.length; i++) { var item = tooltips.item(i).id.replace(/^tooltip-/, ''); prepareTooltip(item, function (bNode) { var text = bNode.textContent || ''; if (/Click to /.test(text)) { return text.replace(lastDotRegex, ''); } return text; }); } // add click texts function setText(item, text) { prepareTooltip(item, function () { return text; }, true); } for (var _a = 0, FURNACE_LEVELS_1 = FURNACE_LEVELS; _a < FURNACE_LEVELS_1.length; _a++) { var furnaceLevel = FURNACE_LEVELS_1[_a]; var furnaceItem = getBoundKey(furnaceLevel + 'Furnace'); setText(furnaceItem, 'Click to operate'); var ovenItem = getBoundKey(furnaceLevel + 'Oven'); setText(ovenItem, 'Click to operate'); } // fix tooltip of quests-book var questBookTooltip = getTooltip('quests-book'); if (questBookTooltip) { var childNodes = questBookTooltip.childNodes; for (var i = 0; i < childNodes.length; i++) { var node = childNodes[i]; if (node.nodeType === Node.TEXT_NODE && (node.textContent || '').indexOf('Click to see a list of quests.') > -1) { var next = node.nextSibling; if (next) { questBookTooltip.removeChild(next); } questBookTooltip.removeChild(node); } } } // fix tooltip of axe var axeTooltip = getTooltip('boundEmptyAxe'); if (axeTooltip) { axeTooltip.insertBefore(document.createElement('br'), axeTooltip.lastElementChild); } var texts = { 'quests-book': 'Click to see the list of quests' , 'achievementBook': 'Click to see the list of achievements' , 'boundEmptyChisel': 'Click to use' , 'rake': 'Click to upgrade your rake' , 'boundBoat': 'Click to send boat' }; for (var item in texts) { setText(item, texts[item]); } for (var _b = 0, BOAT_LIST_2 = BOAT_LIST; _b < BOAT_LIST_2.length; _b++) { var boatKey = BOAT_LIST_2[_b]; setText(getBoundKey(boatKey), 'Click to send boat'); } } var cached = { scrollWidth: 0 , scrollHeight: 0 }; function changeTooltipPosition(event) { var tooltipX = event.pageX - 8; var tooltipY = event.pageY + 8; var el = document.querySelector('body > div.tooltip'); if (!el) { return; } if (!this) { // init cached.scrollWidth = document.body.scrollWidth; cached.scrollHeight = document.body.scrollHeight; } var rect = el.getBoundingClientRect(); var css = { left: tooltipX , top: tooltipY , width: '' , height: '' , maxWidth: cached.scrollWidth , maxHeight: cached.scrollHeight }; var diffX = cached.scrollWidth - 20 - tooltipX - rect.width; if (diffX < 0) { css.left += diffX; css.width = rect.width - 42; } var diffY = cached.scrollHeight - 20 - tooltipY - rect.height; if (diffY < 0) { css.top += diffY; css.height = rect.height - 22; } win.$(el).css(css); } function fixTooltipPositioning() { win.changeTooltipPosition = changeTooltipPosition; win.loadTooltips(); } function fixCombatNavigation() { var backBtns = document.querySelectorAll('span.medium-button[onclick*="openTab(\'combat\')"]'); for (var i = 0; i < backBtns.length; i++) { var btn = backBtns.item(i); var img = btn.firstElementChild; var textNode = btn.lastChild; if (!img || img.tagName != 'IMG' || !textNode) { continue; } img.className = img.className.replace(/(-\d+)-b/, '$1'); textNode.textContent = ' back'; } } function fixPromethiumSmeltingTime() { var _getTimerPerBar = win.getTimerPerBar; win.getTimerPerBar = function (bar) { if (bar == 'promethiumBar') { return 80; } return _getTimerPerBar(bar); }; } function fixImage() { var oxygenEl = document.querySelector('img[src="images/oxygenPotion"]'); if (oxygenEl) { oxygenEl.src += '.png'; } } function init() { fixClientGameLoop(); fixScroller(); fixTooltipStyle(); fixRefreshingMagicRecipes(); moveStrangeLeafs(); fixTreasureMap(); fixWoodcutting(); fixQuestBook(); // apply fix for scroll images later to fix images in this code too fixHitText(); fixScrollImages(); fixQuest8BraveryRecipe(); fixBoatTooltips(); fixAlignments(); addHeroStatTooltips(); unifyTooltips(); fixTooltipPositioning(); fixCombatNavigation(); fixPromethiumSmeltingTime(); fixImage(); } temporaryFixes.init = init; })(temporaryFixes || (temporaryFixes = {})); /** * improve timer */ var timer; (function (timer) { timer.name = 'timer'; var IMPROVED_CLASS = 'improved'; var NOTIFICATION_AREA_ID = 'notifaction-area'; var PERCENT_CLASS = 'percent'; var REMAINING_CLASS = 'remaining'; var TIMER_CLASS = 'timer'; function bindNewFormatter() { function doBind() { win.formatTime = win.formatTimeShort = win.formatTimeShort2 = function (seconds) { return format.timer(seconds); }; } win.addEventListener('load', function () { return setTimeout(function () { return doBind(); }, 100); }); doBind(); setTimeout(function () { return doBind(); }, 100); } function applyStyle() { addStyle("\nspan.notif-box." + IMPROVED_CLASS + "\n{\n\tposition: relative;\n}\nspan.notif-box." + IMPROVED_CLASS + " > span:not(." + TIMER_CLASS + "):not(." + REMAINING_CLASS + "):not(." + PERCENT_CLASS + ")\n{\n\tdisplay: none;\n}\nspan.notif-box." + IMPROVED_CLASS + " > span." + REMAINING_CLASS + ",\nspan.notif-box." + IMPROVED_CLASS + " > span." + PERCENT_CLASS + "\n{\n\tposition: absolute;\n\tleft: 10px;\n\tfont-size: 0.9rem;\n\tbottom: 0px;\n\twidth: 50px;\n\ttext-align: right;\n\ttext-shadow: 1px 1px 4px black;\n}\nspan.notif-box." + IMPROVED_CLASS + " > span." + REMAINING_CLASS + "::before\n{\n\tcontent: '\\0D7';\n\tmargin-right: .25rem;\n\tmargin-left: -.5rem;\n}\nspan.notif-box." + IMPROVED_CLASS + " > span." + PERCENT_CLASS + "::after\n{\n\tcontent: '%';\n}\n\t\t"); } function improveSmeltingTimer() { var el = document.getElementById('notif-smelting'); if (!el) { return; } var smeltingNotifBox = el; smeltingNotifBox.classList.add(IMPROVED_CLASS); var smeltingTimerEl = document.createElement('span'); smeltingTimerEl.className = TIMER_CLASS; smeltingNotifBox.appendChild(smeltingTimerEl); var remainingBarsEl = document.createElement('span'); remainingBarsEl.className = REMAINING_CLASS; smeltingNotifBox.appendChild(remainingBarsEl); var delta = 0; function updatePercValues(init) { if (init === void 0) { init = false; } updateSmeltingTimer(delta = 0); if (init) { observer.add('smeltingPercD', function () { return updatePercValues(); }); observer.add('smeltingPerc', function () { return updatePercValues(); }); } } function updateSmeltingTimer(delta) { if (delta === void 0) { delta = 0; } var totalTime = win.smeltingPercD; // thanks at /u/marcus898 for your bug report var elapsedTime = Math.round(win.smeltingPerc * totalTime / 100) + delta; smeltingTimerEl.textContent = format.timer(Math.max(totalTime - elapsedTime, 0)); remainingBarsEl.textContent = (win.smeltingTotalAmount - win.smeltingAmount).toString(); } observer.addTick(function () { return updateSmeltingTimer(delta++); }); updatePercValues(true); } function improveTimer(cssRulePrefix, textColor, timerColor, infoIdPrefx, containerPrefix, updateFn) { addStyle("\n/* hide built in timer elements */\n" + cssRulePrefix + " > *:not(img):not(.info)\n{\n\tdisplay: none;\n}\n" + cssRulePrefix + " > div.info\n{\n\tcolor: " + textColor + ";\n\tmargin-top: 5px;\n\tpointer-events: none;\n\ttext-align: center;\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n}\n" + cssRulePrefix + " > div.info > div.name\n{\n\tfont-size: 1.2rem;\n}\n" + cssRulePrefix + " > div.info > div.timer\n{\n\tcolor: " + timerColor + ";\n}\n\t\t"); for (var i = 0; i < 6; i++) { var num = i + 1; var infoId = infoIdPrefx + num; var container = document.getElementById(containerPrefix + num); container.style.position = 'relative'; var infoEl = document.createElement('div'); infoEl.className = 'info'; infoEl.id = infoId; infoEl.innerHTML = "<div class=\"name\"></div><div class=\"timer\"></div>"; container.appendChild(infoEl); updateFn(num, infoId, true); } } function updateTreeInfo(placeId, infoElId, init) { if (init === void 0) { init = false; } var infoEl = document.getElementById(infoElId); var nameEl = infoEl.firstElementChild; var timerEl = infoEl.lastElementChild; var idKey = 'treeId' + placeId; var growTimerKey = 'treeGrowTimer' + placeId; var lockedKey = 'treeUnlocked' + placeId; var treeId = getGameValue(idKey); if (treeId == 0) { var isLocked = placeId > 4 && getGameValue(lockedKey) == 0; nameEl.textContent = isLocked ? 'Locked' : 'Empty'; timerEl.textContent = ''; } else { nameEl.textContent = key2Name(win.getTreeName(treeId)) || 'Unknown Tree'; var remainingTime = win.TREE_GROW_TIME[treeId - 1] - getGameValue(growTimerKey); timerEl.textContent = remainingTime > 0 ? '(' + format.timer(remainingTime) + ')' : 'Fully grown'; } if (init) { observer.add([idKey, growTimerKey, lockedKey], function () { return updateTreeInfo(placeId, infoElId, false); }); } } // add tree grow timer function improveTreeGrowTimer() { improveTimer('.woodcutting-tree', 'white', 'yellow', 'wc-tree-info-', 'wc-div-tree-', updateTreeInfo); } function updatePatchInfo(patchId, infoElId, init) { if (init === void 0) { init = false; } var infoEl = document.getElementById(infoElId); var nameEl = infoEl.querySelector('.name'); var timerEl = infoEl.querySelector('.timer'); var idKey = 'farmingPatchSeed' + patchId; var growTimeKey = 'farmingPatchGrowTime' + patchId; var timerKey = 'farmingPatchTimer' + patchId; var stageKey = 'farmingPatchStage' + patchId; var stage = getGameValue(stageKey); var seedName = PLANT_NAME[getGameValue(idKey)] || 'Unkown Plant'; if (stage == 0) { var isLocked = patchId > 4 && win.donorFarmingPatch == 0; nameEl.textContent = isLocked ? 'Locked' : 'Click to grow'; timerEl.textContent = ''; } else if (stage >= 4) { nameEl.textContent = stage > 4 ? 'Dead Plant' : seedName; timerEl.textContent = stage > 4 ? 'Click to remove' : 'Click to harvest'; } else { nameEl.textContent = seedName; var remainingTime = getGameValue(growTimeKey) - getGameValue(timerKey); timerEl.textContent = '(' + format.timer(remainingTime) + ')'; } if (init) { observer.add([idKey, timerKey, stageKey, 'donorFarmingPatch'], function () { return updatePatchInfo(patchId, infoElId, false); }); } } // add seed name and change color of timer function getSoonestTreeTimer() { if (win.treeStage1 == 4 || win.treeStage2 == 4 || win.treeStage3 == 4 || win.treeStage4 == 4 || win.treeStage5 == 4 || win.treeStage6 == 4) { return -1; } var minTimer = null; for (var i = 1; i <= 6; i++) { var treeId = getGameValue('treeId' + i); var unlocked = getGameValue('treeUnlocked' + i) == 1; var timerValue = getGameValue('treeGrowTimer' + i); if (unlocked && treeId !== 0 && timerValue > 0) { var remainingTime = win.TREE_GROW_TIME[treeId - 1] - timerValue; minTimer = minTimer === null ? remainingTime : Math.min(minTimer, remainingTime); } } return minTimer || 0; } function getSoonestFarmingTimer() { if (win.farmingPatchStage1 == 0 || win.farmingPatchStage1 == 4 || win.farmingPatchStage2 == 0 || win.farmingPatchStage2 == 4 || win.farmingPatchStage3 == 0 || win.farmingPatchStage3 == 4 || win.farmingPatchStage4 == 0 || win.farmingPatchStage4 == 4 || win.donorFarmingPatch != 0 && (win.farmingPatchStage5 == 0 || win.farmingPatchStage5 == 4 || win.farmingPatchStage6 == 0 || win.farmingPatchStage6 == 4)) { return -1; } var minTimer = null; for (var i = 1; i <= (win.donorFarmingPatch ? 6 : 4); i++) { var remainingTimer = getGameValue('farmingPatchGrowTime' + i) - getGameValue('farmingPatchTimer' + i); minTimer = minTimer === null ? remainingTimer : Math.min(minTimer, remainingTimer); } return minTimer || 0; } function improveSeedGrowTimer() { improveTimer('div[id^="farming-patch-area-"]', 'black', 'blue', 'farming-patch-info-', 'farming-patch-area-', updatePatchInfo); } function addTabTimer() { var TAB_TIMER_KEY = 'tabTimer'; addStyle("\ntable.tab-bar td\n{\n\tposition: relative;\n}\n." + TAB_TIMER_KEY + " table.tab-bar td.ready > img:first-child\n{\n\tbackground-image: linear-gradient(#161618, #48ab32);\n\tmargin: -2px -5px -3px;\n\tpadding: 6px 5px 7px;\n}\ntable.tab-bar td .info\n{\n\tcolor: yellow;\n\tdisplay: none;\n\tfont-size: 0.8rem;\n\tpadding-left: 50px;\n\tposition: absolute;\n\tleft: 0;\n\tright: 0;\n\ttext-align: center;\n}\n." + TAB_TIMER_KEY + " table.tab-bar td .info\n{\n\tdisplay: block;\n}\ntable.tab-bar td .info.timer\n{\n\tbottom: 0;\n\tpadding-bottom: 5px;\n}\ntable.tab-bar td .info.timer:not(:empty)::before\n{\n\tcontent: '(';\n}\ntable.tab-bar td .info.timer:not(:empty)::after\n{\n\tcontent: ')';\n}\nbody.short-tabs table.tab-bar td .info.timer\n{\n\tdisplay: none;\n}\ntable.tab-bar td .info.extra\n{\n\tcolor: white;\n\tpadding-top: 5px;\n\ttop: 0;\n}\nbody.short-tabs table.tab-bar td .info.extra\n{\n\tdisplay: none;\n}\n." + TAB_TIMER_KEY + " #dhqol-notif-woodcutting,\n." + TAB_TIMER_KEY + " #dhqol-notif-farming,\n." + TAB_TIMER_KEY + " #dhqol-notif-combat,\n." + TAB_TIMER_KEY + " #dhqol-notif-vial\n{\n\tdisplay: none !important;\n}\n\t\t"); function getTabEl(key) { return document.getElementById('tab-container-bar-' + key); } function addInfoDiv(key) { var infoDiv = document.createElement('div'); infoDiv.className = 'info'; var tab = getTabEl(key); if (tab) { tab.appendChild(infoDiv); } return infoDiv; } function createTabTimer(key, timerFn) { var tab = getTabEl(key); var timerDiv = addInfoDiv(key); if (!tab || !timerDiv) { return; } timerDiv.classList.add('timer'); function updateTimer() { var minTimer = timerFn(); if (tab) { tab.classList[minTimer == -1 ? 'add' : 'remove']('ready'); } timerDiv.textContent = minTimer <= 0 ? '' : format.timer(minTimer); } updateTimer(); observer.addTick(function () { return updateTimer(); }); } createTabTimer('woodcutting', getSoonestTreeTimer); createTabTimer('farming', getSoonestFarmingTimer); createTabTimer('combat', function () { return win.combatGlobalCooldown; }); var energyDiv = addInfoDiv('combat'); energyDiv.classList.add('extra'); function updateEnergy() { energyDiv.innerHTML = '<img src="images/steak.png" class="image-icon-15"> ' + format.number(win.energy); } updateEnergy(); observer.add('energy', function () { return updateEnergy(); }); // add highlight for stardust potions var potionDiv = addInfoDiv('brewing'); potionDiv.classList.add('extra'); var potionList = ['stardustPotion', 'superStardustPotion']; var potionImageList = []; function updatePotion(key, img, init) { if (init === void 0) { init = false; } var timerKey = key + 'Timer'; var show = getGameValue(key) > 0 && getGameValue(timerKey) === 0; img.style.display = show ? '' : 'none'; if (init) { observer.add(key, function () { return updatePotion(key, img); }); observer.add(timerKey, function () { return updatePotion(key, img); }); } } for (var i = 0; i < potionList.length; i++) { var key = potionList[i]; var img = document.createElement('img'); img.src = 'images/' + key + '.png'; img.className = 'image-icon-15'; potionImageList[i] = img; potionDiv.appendChild(img); updatePotion(key, img, true); } function updateVisibility() { document.body.classList[settings.get(settings.KEY.showTabTimer) ? 'add' : 'remove'](TAB_TIMER_KEY); } updateVisibility(); settings.observe(settings.KEY.showTabTimer, function () { return updateVisibility(); }); observer.add('profileShortTabs', function () { var short = !!win.profileShortTabs; document.body.classList[short ? 'add' : 'remove']('short-tabs'); }); } function addOilInfo() { var NULL_TYPE = 'null'; var PLUS_TYPE = 'plus'; var MINUS_TYPE = 'minus'; addStyle("\n#oil-filling-level\n{\n\tbackground-color: black;\n\tborder: 1px solid white;\n\tdisplay: inline-block;\n\tposition: absolute;\n\tbottom: 0;\n\ttop: 0;\n\ttransform: translateX(-10px);\n\twidth: 8px;\n}\n#oil-filling-level > div\n{\n\tbackground-color: white;\n\twidth: 100%;\n}\n\ntable.top-bar span[id^=\"dh2qol-oil\"]\n{\n\tdisplay: none;\n}\n#oil-flow-net\n{\n\tcolor: hsla(195, 100%, 50%, 1);\n\tfont-weight: bold;\n}\n#oil-flow-net[data-type=\"" + NULL_TYPE + "\"]\n{\n\tcolor: hsla(195, 100%, 50%, 1);\n}\n#oil-flow-net[data-type=\"" + PLUS_TYPE + "\"]\n{\n\tcolor: green;\n}\n#oil-flow-net[data-type=\"" + MINUS_TYPE + "\"]\n{\n\tcolor: red;\n}\n#oil-flow-net-timer[data-type=\"" + NULL_TYPE + "\"]\n{\n\tdisplay: none;\n}\n#oil-flow-net-timer[data-type=\"" + PLUS_TYPE + "\"]\n{\n\tcolor: yellow;\n}\n#oil-flow-net-timer[data-type=\"" + MINUS_TYPE + "\"]\n{\n\tcolor: orange;\n}\n\t\t"); var oilFlow = document.getElementById('oil-flow-values'); var parent = oilFlow && oilFlow.parentElement; if (!oilFlow || !parent) { return; } var container = document.createElement('div'); container.id = 'oil-filling-level'; var fillingLevel = document.createElement('div'); container.appendChild(fillingLevel); var first = parent.firstElementChild; if (first) { parent.insertBefore(container, first); } else { parent.appendChild(container); } parent.style.position = 'relative'; var netFlow = document.createElement('span'); netFlow.id = 'oil-flow-net'; parent.insertBefore(netFlow, oilFlow); var next = oilFlow.nextElementSibling; var netTimer = document.createElement('span'); netTimer.id = 'oil-flow-net-timer'; if (next) { parent.insertBefore(netTimer, next); } else { parent.appendChild(netTimer); } var oilNet; var oilNetType; function updateNetFlow(init) { if (init === void 0) { init = false; } oilNet = win.oilIn - win.oilOut; oilNetType = oilNet === 0 ? NULL_TYPE : (oilNet > 0 ? PLUS_TYPE : MINUS_TYPE); netFlow.dataset.type = oilNetType; var sign = oilNet === 0 ? PLUS_MINUS_SIGN : (oilNet > 0 ? '+' : ''); netFlow.textContent = sign + oilNet; if (init) { observer.add('oilIn', function () { return updateNetFlow(); }); observer.add('oilOut', function () { return updateNetFlow(); }); } updateFullTimer(init); } var hour2Color = (_a = {} , // 30min _a[.5 * 60 * 60] = 'rgb(255, 0, 0)' , _a[5 * 60 * 60] = 'rgb(255, 255, 0)' , _a[8 * 60 * 60] = 'rgb(255, 255, 255)' , _a); function updateFullTimer(init) { if (init === void 0) { init = false; } netTimer.dataset.type = oilNetType; var time = 0; if (oilNet > 0) { netTimer.title = 'full in...'; var diff = win.maxOil - win.oil; time = diff / oilNet; } else if (oilNet < 0) { netTimer.title = 'empty in...'; time = win.oil / Math.abs(oilNet); } netTimer.textContent = '(' + format.timer(Math.ceil(time)) + ')'; var filledPercent = win.oil / win.maxOil * 100; fillingLevel.style.height = (100 - filledPercent) + '%'; /** * colorize filling level according to the time it needs to be full/empty: * - red iff oil storage full/empty in 30min * - yellow iff oil storage full/empty in 5h * - white iff oil storage full/empty in 8h or more */ var color = oilNet === 0 ? '#ffffff' : colorGenerator.getColorTransition(time, hour2Color); container.style.borderColor = color; if (init) { observer.add('maxOil', function () { return updateFullTimer(); }); observer.add('oil', function () { return updateFullTimer(); }); observer.addTick(function () { return updateFullTimer(); }); } } updateNetFlow(true); var _a; } function addRocketTimer() { var notifArea = document.getElementById(NOTIFICATION_AREA_ID); if (!notifArea) { return; } var notifBox = document.createElement('span'); notifBox.className = 'notif-box ' + IMPROVED_CLASS; notifBox.id = 'notif-rocket'; notifBox.style.display = 'none'; notifBox.innerHTML = "<img src=\"images/rocket.png\" class=\"image-icon-50\" id=\"notif-rocket-img\" style=\"margin-right: 10px;\"><span class=\"timer\" data-item-display=\"rocketTimer\"></span><span class=\"" + PERCENT_CLASS + "\" data-item-display=\"rocketPercent\"></span>"; notifBox.title = 'This value is only an estimation based on an average speed of 15km per second.'; notifArea.appendChild(notifBox); var img = notifBox.getElementsByTagName('img').item(0); var timerEl = notifBox.getElementsByClassName(TIMER_CLASS).item(0); var percentEl = notifBox.getElementsByClassName(PERCENT_CLASS).item(0); var AVG_KM_PER_SEC = 15; var smoothedTime = 0; function updateRocketKm() { var hideStatic = win.rocketKm < MAX_ROCKET_KM; var hideTimer = win.rocketKm <= 0 || !hideStatic; notifBox.style.display = hideTimer ? 'none' : ''; var percent = win.rocketKm / MAX_ROCKET_KM; var diff = MAX_ROCKET_KM - win.rocketKm; if (win.rocketMoonId < 0) { percent = 1 - percent; diff = win.rocketKm; } var avgRemainingTime = Math.round(diff / AVG_KM_PER_SEC); // be more accurate in the last few seconds (may be the last 2 up to 16 seconds) var threshold = smoothedTime < 10 ? 1 : 8; if (Math.abs(smoothedTime - avgRemainingTime) >= threshold) { smoothedTime = avgRemainingTime + 1; } percentEl.textContent = Math.floor(percent * 100).toString(); } function tickRocketTimer() { if (smoothedTime > 0) { smoothedTime = Math.max(smoothedTime - 1, 0); timerEl.textContent = format.timer(smoothedTime); } } updateRocketKm(); observer.add('rocketKm', function (key, oldValue, newValue) { return updateRocketKm(); }); observer.addTick(function () { return tickRocketTimer(); }); function updateRocketDirection() { // alternatively: `transform: rotateZ(180deg) rotateY(180deg)` var transform = win.rocketMoonId >= 0 ? '' : 'rotate(90deg)'; img.style.transform = transform; var itemBox = document.getElementById('default-item-img-tag-boundRocket'); if (itemBox) { itemBox.style.transform = transform; } } updateRocketDirection(); observer.add('rocketMoonId', function () { return updateRocketDirection(); }); } function getLogTypeList() { var list = []; var els = document.querySelectorAll('input[id^="input-charcoalFoundry-"]'); for (var i = 0; i < els.length; i++) { list.push(els[i].id.replace(/^input-charcoalFoundry-/i, '')); } return list; } function improveFoundryTimer() { var el = document.getElementById('notif-charcoalFoundry'); if (!el) { return; } var notifBox = el; notifBox.classList.add(IMPROVED_CLASS); var timerEl = document.createElement('span'); timerEl.className = TIMER_CLASS; notifBox.appendChild(timerEl); var remainingEl = document.createElement('span'); remainingEl.className = REMAINING_CLASS; notifBox.appendChild(remainingEl); var logTypeList = null; observer.add('charcoalFoundryN', function (key, oldValue, newValue) { timerEl.textContent = format.timer(win.charcoalFoundryD - win.charcoalFoundryN); // init log type list when needed if (!logTypeList) { logTypeList = getLogTypeList(); } var woodAmount = win.charcoalFoundryTotal - win.charcoalFoundryCurrent; var coalPerLog = win.getCharcoalPerLog(logTypeList[win.charcoalFoundryLogId - 1]); var remainingCoal = woodAmount * (isNaN(coalPerLog) ? 1 : coalPerLog); remainingEl.textContent = remainingCoal.toString(); }); } function init() { bindNewFormatter(); applyStyle(); improveSmeltingTimer(); improveTreeGrowTimer(); improveSeedGrowTimer(); addTabTimer(); addOilInfo(); addRocketTimer(); improveFoundryTimer(); } timer.init = init; })(timer || (timer = {})); /** * improve smelting dialog */ var smelting; (function (smelting) { smelting.name = 'smelting'; var TIME_NEEDED_ID = 'smelting-time-needed'; var LAST_SMELTING_AMOUNT_KEY = 'lastSmeltingAmount'; var LAST_SMELTING_BAR_KEY = 'lastSmeltingBar'; var smeltingValue = null; var amountInput; function prepareAmountInput() { amountInput = document.getElementById('input-smelt-bars-amount'); amountInput.type = 'number'; amountInput.min = '0'; amountInput.step = '5'; function onValueChange() { smeltingValue = null; win.selectBar('', null, amountInput, document.getElementById('smelting-furnace-capacity').value); } amountInput.addEventListener('mouseup', onValueChange); amountInput.addEventListener('keyup', onValueChange); amountInput.setAttribute('onkeyup', ''); } function setBarCap(bar, capacity) { if (bar == '') { bar = win.selectedBar; } var requirements = SMELTING_REQUIREMENTS[bar]; var maxAmount = parseInt(capacity, 10); for (var key in requirements) { var req = requirements[key]; maxAmount = Math.min(Math.floor(getGameValue(key) / req), maxAmount); } var value = parseInt(amountInput.value, 10); if (value > maxAmount) { smeltingValue = value; amountInput.value = maxAmount.toString(); } else if (smeltingValue != null) { amountInput.value = Math.min(smeltingValue, maxAmount).toString(); if (smeltingValue <= maxAmount) { smeltingValue = null; } } } function prepareTimeNeeded() { var neededMatsEl = document.getElementById('dialogue-furnace-mats-needed'); var parent = neededMatsEl && neededMatsEl.parentElement; if (!neededMatsEl || !parent) { return; } var br = document.createElement('br'); var timeBox = document.createElement('div'); timeBox.className = 'basic-smallbox'; timeBox.innerHTML = "<img src=\"images/icons/hourglass.png\" class=\"image-icon-30\">\n\t\tDuration: <span id=\"" + TIME_NEEDED_ID + "\"></span>"; var next = neededMatsEl.nextElementSibling; parent.insertBefore(br, next); parent.insertBefore(timeBox, next); } function updateTimeNeeded(value) { var timeEl = document.getElementById(TIME_NEEDED_ID); if (!timeEl) { return; } var num = parseInt(value, 10); var timePerBar = win.getTimerPerBar(win.selectedBar); timeEl.textContent = format.timer(timePerBar * num); } function init() { prepareAmountInput(); prepareTimeNeeded(); var _selectBar = win.selectBar; var updateSmeltingRequirements = function (bar, inputElement, inputBarsAmountEl, capacity) { _selectBar(bar, inputElement, inputBarsAmountEl, capacity); var matsArea = document.getElementById('dialogue-furnace-mats-needed'); if (matsArea) { matsArea.innerHTML = format.numbersInText(matsArea.innerHTML); } updateTimeNeeded(inputBarsAmountEl.value); }; win.selectBar = function (bar, inputElement, inputBarsAmountEl, capacity) { setBarCap(bar, capacity); // save selected bar if (bar != '') { store.set(LAST_SMELTING_BAR_KEY, bar); } // save amount store.set(LAST_SMELTING_AMOUNT_KEY, inputBarsAmountEl.value); updateSmeltingRequirements(bar, inputElement, inputBarsAmountEl, capacity); }; var lastBar = store.get(LAST_SMELTING_BAR_KEY); var lastAmount = store.get(LAST_SMELTING_AMOUNT_KEY); var _openFurnaceDialogue = win.openFurnaceDialogue; win.openFurnaceDialogue = function (furnace) { var capacity = win.getFurnaceCapacity(furnace); if (win.smeltingBarType == 0) { amountInput.max = capacity.toString(); } // restore amount var inputBarsAmountEl = document.getElementById('input-smelt-bars-amount'); if (inputBarsAmountEl && inputBarsAmountEl.value == '-1' && lastAmount != null) { inputBarsAmountEl.value = lastAmount; } _openFurnaceDialogue(furnace); // restore selected bar if ((!win.selectedBar || win.selectedBar == 'none') && lastBar != null) { win.selectedBar = lastBar; } // update whether requirements are fulfilled var barInputId = 'input-furnace-' + split2Words(win.selectedBar, '-').toLowerCase(); var inputElement = document.getElementById(barInputId); if (inputElement && inputBarsAmountEl) { updateSmeltingRequirements(win.selectedBar, inputElement, inputBarsAmountEl, capacity.toString()); } }; } smelting.init = init; })(smelting || (smelting = {})); /** * add chance to time calculator */ var fishingInfo; (function (fishingInfo) { fishingInfo.name = 'fishingInfo'; /** * calculates the number of seconds until the event with the given chance happened at least once with the given * probability p (in percent) */ function calcSecondsTillP(chancePerSecond, p) { return Math.round(Math.log(1 - p / 100) / Math.log(1 - chancePerSecond)); } function addChanceTooltip(headline, chancePerSecond, elId, targetEl) { // ensure tooltip exists and is correctly binded var tooltipEl = ensureTooltip('chance-' + elId, targetEl); // set elements content var percValues = [1, 10, 20, 50, 80, 90, 99]; var percRows = ''; for (var _i = 0, percValues_1 = percValues; _i < percValues_1.length; _i++) { var p = percValues_1[_i]; percRows += "\n\t\t\t\t<tr>\n\t\t\t\t\t<td>" + p + "%</td>\n\t\t\t\t\t<td>" + format.time2NearestUnit(calcSecondsTillP(chancePerSecond, p), true) + "</td>\n\t\t\t\t</tr>"; } tooltipEl.innerHTML = "<h2>" + headline + "</h2>\n\t\t\t<table class=\"chance\">\n\t\t\t\t<tr>\n\t\t\t\t\t<th>Probability</th>\n\t\t\t\t\t<th>Time</th>\n\t\t\t\t</tr>\n\t\t\t\t" + percRows + "\n\t\t\t</table>\n\t\t"; } function addChanceStyle() { addStyle("\ntable.chance\n{\n\tborder-spacing: 0;\n}\ntable.chance th\n{\n\tborder-bottom: 1px solid gray;\n}\ntable.chance td:first-child\n{\n\tborder-right: 1px solid gray;\n\ttext-align: center;\n}\ntable.chance th,\ntable.chance td\n{\n\tpadding: 4px 8px;\n}\ntable.chance tr:nth-child(2n) td\n{\n\tbackground-color: white;\n}\n\t\t"); } function addXp() { var table = document.querySelector('#dialogue-id-fishingRod table'); if (!table) { return; } var rows = table.rows; for (var i = 0; i < rows.length; i++) { var row = rows.item(i); if (row.classList.contains('xp-added')) { continue; } if (i == 0) { var xpCell = document.createElement('th'); xpCell.textContent = 'XP'; row.appendChild(xpCell); } else { var cell = row.insertCell(-1); var rawFish = row.id.replace('dialogue-fishing-rod-tr-', ''); var xp = FISH_XP[rawFish]; cell.textContent = xp == null ? '?' : format.number(xp); } row.classList.add('xp-added'); } } function chance2TimeCalculator() { var table = document.querySelector('#dialogue-id-fishingRod table'); if (!table) { return; } var rows = table.rows; for (var i = 1; i < rows.length; i++) { var row = rows.item(i); var rawFish = row.id.replace('dialogue-fishing-rod-tr-', ''); var fish = rawFish.replace('raw', '').toLowerCase(); if (!rawFish || !fish) { continue; } var chanceCell = row.cells.item(row.cells.length - 2); var chance = (chanceCell.textContent || '') .replace(/[^\d\/]/g, '') .split('/') .reduce(function (p, c) { return p / parseInt(c, 10); }, 1); addChanceTooltip("One raw " + fish + " at least every:", chance, rawFish, row); } } function init() { addChanceStyle(); var _clicksShovel = win.clicksShovel; win.clicksShovel = function () { _clicksShovel(); var shovelChance = document.getElementById('dialogue-shovel-chance'); var titleEl = shovelChance.parentElement; var chance = 1 / win.getChanceOfDiggingSand(); addChanceTooltip('One sand at least every:', chance, 'shovel', titleEl); }; // depends on fishingXp var _clicksFishingRod = win.clicksFishingRod; win.clicksFishingRod = function () { _clicksFishingRod(); addXp(); chance2TimeCalculator(); }; } fishingInfo.init = init; })(fishingInfo || (fishingInfo = {})); /** * add tooltips for recipes */ var recipeTooltips; (function (recipeTooltips) { recipeTooltips.name = 'recipeTooltips'; function updateRecipeTooltips(recipeKey, recipes) { var table = document.getElementById('table-' + recipeKey + '-recipe'); var rows = table.rows; function recipe2Title(recipe) { return recipe.recipe .map(function (name, i) { return format.number(recipe.recipeCost[i]) + String.fromCharCode(160) + split2Words(name).toLowerCase(); }) .join(' + '); }; for (var i = 1; i < rows.length; i++) { var row = rows.item(i); var key = row.id.replace(recipeKey + '-', ''); var recipe = recipes[key]; var requirementCell = row.cells.item(3); requirementCell.title = recipe2Title(recipe); win.$(requirementCell).tooltip(); } } function updateTooltipsOnReinitRecipes(key) { var capitalKey = capitalize(key); var processKey = 'process' + capitalKey + 'Tab'; var _processTab = win[processKey]; win[processKey] = function () { var reinit = !!getGameValue('refreshLoad' + capitalKey + 'Table'); _processTab(); if (reinit) { updateRecipeTooltips(key, getGameValue(key + 'Recipes')); } }; } function init() { updateTooltipsOnReinitRecipes('crafting'); updateTooltipsOnReinitRecipes('brewing'); updateTooltipsOnReinitRecipes('magic'); updateTooltipsOnReinitRecipes('cooksBook'); } recipeTooltips.init = init; })(recipeTooltips || (recipeTooltips = {})); /** * fix formatting of numbers */ var fixNumbers; (function (fixNumbers) { fixNumbers.name = 'fixNumbers'; function prepareRecipeForTable(recipe) { // create a copy of the recipe to prevent requirement check from failing var newRecipe = JSON.parse(JSON.stringify(recipe)); newRecipe.recipeCost = recipe.recipeCost.map(function (cost) { return format.number(cost); }); newRecipe.description = format.numbersInText(newRecipe.description); newRecipe.xp = format.number(recipe.xp); return newRecipe; } function init() { var _addRecipeToBrewingTable = win.addRecipeToBrewingTable; win.addRecipeToBrewingTable = function (brewingRecipe) { _addRecipeToBrewingTable(prepareRecipeForTable(brewingRecipe)); }; var _addRecipeToMagicTable = win.addRecipeToMagicTable; win.addRecipeToMagicTable = function (magicRecipe) { _addRecipeToMagicTable(prepareRecipeForTable(magicRecipe)); }; var _addRecipeToCooksBookTable = win.addRecipeToCooksBookTable; win.addRecipeToCooksBookTable = function (cooksBookRecipe) { _addRecipeToCooksBookTable(prepareRecipeForTable(cooksBookRecipe)); }; var tooltipList = document.querySelectorAll('#tooltip-list div[id^="tooltip-"][id$="Seeds"]'); for (var i = 0; i < tooltipList.length; i++) { var tooltip = tooltipList[i]; tooltip.innerHTML = format.numbersInText(tooltip.innerHTML); } var fightEnergyCells = document.querySelectorAll('#dialogue-fight tr > td:nth-child(4)'); for (var i = 0; i < fightEnergyCells.length; i++) { var cell = fightEnergyCells[i]; cell.innerHTML = format.numbersInText(cell.innerHTML); } var _rocketTick = win.rocketTick; win.rocketTick = function () { _rocketTick(); var rocketBox = document.getElementById('itembox-rocket'); if (rocketBox && /^\d+\s*Km$/i.test(rocketBox.textContent || '')) { rocketBox.innerHTML = format.numbersInText(rocketBox.innerHTML).replace('Km', 'km'); } }; } fixNumbers.init = init; })(fixNumbers || (fixNumbers = {})); /** * add slider for machines */ var machineDialog; (function (machineDialog) { machineDialog.name = 'machineDialog'; var $slider; function createSlider() { var br = document.querySelector('#dialogue-machinery-current-total ~ br'); var parent = br && br.parentElement; if (!br || !parent) { return; } addStyle("\n#dialogue-id-boundMachinery .ui-slider\n{\n\tmargin: 10px 5px;\n}\n#dialogue-id-boundMachinery .ui-slider:not([data-owned=\"10\"])::after\n{\n\tbackground: hsla(0, 0%, 0%, 1);\n\tborder: 1px solid #c5c5c5;\n\tborder-radius: 3px;\n\tborder-top-left-radius: 0;\n\tborder-bottom-left-radius: 0;\n\tcontent: '';\n\tmargin-left: -3px;\n\tpadding-left: 3px;\n\theight: 100%;\n\twidth: 0%;\n\tposition: absolute;\n\tleft: 100%;\n\ttop: -1px;\n}\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"9\"] { width: calc((100% - 10px - 2px) / 10*9); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"9\"]::after { width: calc(100% / 9 * 1); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"8\"] { width: calc((100% - 10px - 2px) / 10*8); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"8\"]::after { width: calc(100% / 8 * 2); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"7\"] { width: calc((100% - 10px - 2px) / 10*7); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"7\"]::after { width: calc(100% / 7 * 3); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"6\"] { width: calc((100% - 10px - 2px) / 10*6); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"6\"]::after { width: calc(100% / 6 * 4); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"5\"] { width: calc((100% - 10px - 2px) / 10*5); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"5\"]::after { width: calc(100% / 5 * 5); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"4\"] { width: calc((100% - 10px - 2px) / 10*4); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"4\"]::after { width: calc(100% / 4 * 6); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"3\"] { width: calc((100% - 10px - 2px) / 10*3); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"3\"]::after { width: calc(100% / 3 * 7); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"2\"] { width: calc((100% - 10px - 2px) / 10*2); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"2\"]::after { width: calc(100% / 2 * 8); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"1\"] { width: calc((100% - 10px - 2px) / 10*1); }\n#dialogue-id-boundMachinery .ui-slider[data-owned=\"1\"]::after { width: calc(100% / 1 * 9); }\n\t\t"); var slider = document.createElement('div'); parent.insertBefore(slider, br); $slider = win.$(slider) .slider( { range: 'max' , min: 0 , max: 10 , value: 0 , slide: function (event, ui) { return updateValue(ui.value); } }); // hide br and up/down arrows br.style.display = 'none'; var arrows = document.querySelectorAll('input[onclick^="turnOn("]'); for (var i = 0; i < arrows.length; i++) { arrows[i].style.display = 'none'; } var els = document.querySelectorAll('[onclick*="openMachineryDialogue("]'); var boundMachineKeyList = []; for (var i = 0; i < els.length; i++) { var match = els[i].id.match(/openMachineryDialogue\('(.+?)'\)/); if (match) { boundMachineKeyList.push(getBoundKey(match[1])); } } observer.add(boundMachineKeyList, function () { return updateMax(); }); } function updateMax() { var machineEl = document.getElementById('dialogue-machinery-chosen'); if (machineEl && machineEl.value != '') { var boundMachineKey = getBoundKey(machineEl.value); var ownedNum = getGameValue(boundMachineKey); $slider.slider('option', 'max', ownedNum); $slider.get(0).dataset.owned = ownedNum.toString(); } } function updateValue(value) { var typeEl = document.getElementById('dialogue-machinery-chosen'); var numEl = document.getElementById('dialogue-machinery-current-on'); if (numEl && typeEl) { var valueBefore = parseInt(numEl.textContent || '0', 10); var machine = typeEl.value; var increment = valueBefore < value; var diff = Math.abs(valueBefore - value); for (var i = 0; i < diff; i++) { win.turnOn(machine, increment); } } } function init() { if (!settings.get(settings.KEY.changeMachineDialog)) { return; } createSlider(); var _openMachineryDialogue = win.openMachineryDialogue; win.openMachineryDialogue = function (machineType) { _openMachineryDialogue(machineType); updateMax(); $slider.slider('value', getGameValue(machineType + 'On')); }; } machineDialog.init = init; })(machineDialog || (machineDialog = {})); /** * improve behaviour of amount inputs */ var amountInputs; (function (amountInputs) { amountInputs.name = 'amountInputs'; function getVialType(recipe) { return recipe.levelReq < 35 ? 'vialOfWater' : (recipe.levelReq < 65 ? 'largeVialOfWater' : 'hugeVialOfWater'); } function getSimpleMax(recipe) { var max = Number.MAX_SAFE_INTEGER; for (var i = 0; i < recipe.recipe.length; i++) { max = Math.min(max, Math.floor(getGameValue(recipe.recipe[i]) / recipe.recipeCost[i])); } return max; } function getMax(recipe) { var max = getSimpleMax(recipe); if (/Potion$/.test(recipe.itemName)) { var vialType = getVialType(recipe); max = Math.min(max, getGameValue(vialType)); } return max; } function ensureNumberInput(idOrEl) { var numInput = typeof idOrEl === 'string' ? document.getElementById(idOrEl) : idOrEl; if (numInput) { if (numInput.type != 'number' && settings.get(settings.KEY.makeNumberInputs)) { var width = numInput.clientWidth; if (width !== 0) { numInput.style.width = width + 'px'; } numInput.type = 'number'; numInput.min = '0'; var onkeyup_1 = numInput.getAttribute('onkeyup'); if (onkeyup_1) { numInput.setAttribute('onmouseup', onkeyup_1); } } else if (numInput.type == 'number' && !settings.get(settings.KEY.makeNumberInputs)) { numInput.style.width = ''; numInput.type = ''; numInput.removeAttribute('onmouseup'); } } return numInput; } function getCurrentMax(keyId, recipeCollection) { var keyEl = document.getElementById(keyId); if (!keyEl) { return 0; } var key = keyEl.value; return getMax(recipeCollection[key]); }; function ensureMaxBtn(keyId, inputId, recipeCollection, key) { var recipe = recipeCollection[key]; var numInput = ensureNumberInput(inputId); var next = numInput && numInput.nextElementSibling; var parent = numInput && numInput.parentElement; if (numInput && parent) { if ((!next || next.nodeName !== 'BUTTON') && settings.get(settings.KEY.addMaxBtn)) { var btn = document.createElement('button'); btn.textContent = 'Max'; btn.addEventListener('click', function () { numInput.value = getCurrentMax(keyId, recipeCollection).toString(); }); parent.appendChild(btn); } else if (next && next.nodeName === 'BUTTON' && !settings.get(settings.KEY.addMaxBtn)) { parent.removeChild(next); } numInput.value = Math.min(1, getMax(recipe)).toString(); numInput.select(); } } function watchKeepInput(event) { var itemInput = document.getElementById('npc-sell-item-chosen'); var numInput = ensureNumberInput('dialogue-input-cmd'); if (!itemInput || !numInput) { return; } var item = itemInput.value; var newValue = Math.max(getGameValue(item) - Number(this.value), 0); numInput.value = newValue.toString(); } function updateKeepMaxValue(keepInput, init) { if (init === void 0) { init = false; } var itemInput = document.getElementById('npc-sell-item-chosen'); if (!itemInput) { return; } var item = itemInput.value; var max = getGameValue(item); keepInput.max = max.toString(); if (init) { observer.addTick(function () { return updateKeepMaxValue(keepInput); }); } } function ensureKeepInput(item) { var numInput = ensureNumberInput('dialogue-input-cmd'); var parent = numInput && numInput.parentElement; var next = numInput && numInput.nextElementSibling; var nextNext = next && next.nextElementSibling; if (next && nextNext && parent) { if (nextNext.nodeName === 'BR' && settings.get(settings.KEY.addKeepInput)) { var div = document.createElement('div'); var text = document.createTextNode('Keep: '); div.appendChild(text); var keepInput = document.createElement('input'); keepInput.type = 'number'; keepInput.value = keepInput.min = '0'; keepInput.max = getGameValue(item).toString(); keepInput.addEventListener('keyup', watchKeepInput); keepInput.addEventListener('mouseup', watchKeepInput); updateKeepMaxValue(keepInput, true); div.appendChild(keepInput); parent.insertBefore(div, nextNext); } else if (nextNext.nodeName !== 'BR' && !settings.get(settings.KEY.addKeepInput)) { var br = document.createElement('br'); parent.insertBefore(br, nextNext); parent.removeChild(nextNext); } } } function init() { var _multiCraft = win.multiCraft; win.multiCraft = function (item) { _multiCraft(item); ensureMaxBtn('dialogue-multicraft-chosen', 'dialogue-multicraft-input', win.craftingRecipes, item); }; var _brew = win.brew; win.brew = function (potion) { _brew(potion); ensureMaxBtn('dialogue-potion-chosen', 'dialogue-brewing-input', win.brewingRecipes, potion); }; var _cooksBookInputDialogue = win.cooksBookInputDialogue; win.cooksBookInputDialogue = function (food) { _cooksBookInputDialogue(food); ensureMaxBtn('dialogue-cooksBook-chosen', 'dialogue-cooksBook-input', win.cooksBookRecipes, food); }; var _openSellNPCDialogue = win.openSellNPCDialogue; win.openSellNPCDialogue = function (item) { _openSellNPCDialogue(item); ensureKeepInput(item); }; var allowedInputs = [ 'dialogue-ashes' , 'dialogue-bindDonorCoins' , 'dialogue-bonemeal' , 'dialogue-bones' , 'dialogue-brewing' , 'dialogue-buy-item-2' , 'dialogue-buyFromMarket' , 'dialogue-charcoalFoundry' , 'dialogue-consume' , 'dialogue-cooksBook' , 'dialogue-createArrows' , 'dialogue-createFireArrows' , 'dialogue-createIceArrows' , 'dialogue-furnace' , 'dialogue-iceBones' , 'dialogue-id-boundHammer' , 'dialogue-id-boundPickaxe' , 'dialogue-id-cook-food' , 'dialogue-id-oven-addheat' , 'dialogue-market-chosenpostitem' , 'dialogue-multicraft' , 'dialogue-oilBarrels' , 'dialogue-oilFactory' , 'dialogue-sell-item' , 'dialogue-stardustCrystals' , 'dialogue-wand' ]; var _openDialogue = win.openDialogue; win.openDialogue = function (id, width, position) { _openDialogue(id, width, position); if (allowedInputs.indexOf(id) === -1 || id === 'dialogue-buyFromMarket' && market.detectTedsUI() || id === 'dialogue-market-chosenpostitem' && market.detectTedsUI()) { return; } var dialog = document.getElementById(id); var input = dialog && dialog.querySelector('input[type="text"],input[type="number"]'); if (!input) { return; } ensureNumberInput(input); }; } amountInputs.init = init; })(amountInputs || (amountInputs = {})); /** * improves the top bar */ var newTopbar; (function (newTopbar) { newTopbar.name = 'newTopbar'; var linkCell, tabCell, infoCell; var addQueues = { link: [] , tab: [] , info: [] }; function createPipeNode() { return document.createTextNode('|'); } function addLinkEntry(el) { if (!linkCell) { addQueues.link.push(el); } else { linkCell.appendChild(createPipeNode()); linkCell.appendChild(el); } } newTopbar.addLinkEntry = addLinkEntry; function addTabEntry(el) { if (!tabCell) { addQueues.tab.push(el); } else { tabCell.appendChild(createPipeNode()); tabCell.appendChild(el); } } newTopbar.addTabEntry = addTabEntry; function addInfoEntry(el) { if (!infoCell) { addQueues.info.push(el); } else { if (infoCell.firstChild) { infoCell.insertBefore(createPipeNode(), infoCell.firstChild); infoCell.insertBefore(el, infoCell.firstChild); } else { infoCell.appendChild(createPipeNode()); infoCell.appendChild(el); } } } newTopbar.addInfoEntry = addInfoEntry; function init() { if (!settings.get(settings.KEY.useNewToolbar)) { return; } addStyle("\ntable.top-links,\ntable.top-links *\n{\n\tpadding: 0;\n}\ntable.top-links td > *\n{\n\tdisplay: inline-block;\n\tpadding: 2px 6px;\n}\n\t\t"); var table = document.querySelector('table.top-links'); if (!table) { return; } var row = table.rows.item(0); var cells = row.cells; var tabIdx = [2, 5]; var infoIdx = [6, 7]; var newRow = table.insertRow(-1); linkCell = newRow.insertCell(-1); tabCell = newRow.insertCell(-1); tabCell.style.textAlign = 'center'; infoCell = newRow.insertCell(-1); infoCell.style.textAlign = 'right'; for (var i = 0; i < cells.length; i++) { var container = linkCell; if (tabIdx.indexOf(i) != -1) { container = tabCell; } else if (infoIdx.indexOf(i) != -1) { container = infoCell; } var cell = cells.item(i); var el = cell.firstElementChild; if (cell.childNodes.length > 1) { el = document.createElement('span'); el.style.color = 'yellow'; while (cell.childNodes.length > 0) { el.appendChild(cell.childNodes[0]); } } if (container.children.length > 0) { container.appendChild(createPipeNode()); } if (el) { container.appendChild(el); } } var parent = row.parentElement; if (parent) { parent.removeChild(row); } for (var _i = 0, _a = addQueues.link; _i < _a.length; _i++) { var el = _a[_i]; addLinkEntry(el); } for (var _b = 0, _c = addQueues.tab; _b < _c.length; _b++) { var el = _c[_b]; addTabEntry(el); } for (var _d = 0, _e = addQueues.info; _d < _e.length; _d++) { var el = _e[_d]; addInfoEntry(el); } var _openTab = win.openTab; win.openTab = function (newTab) { var oldTab = win.currentOpenTab; _openTab(newTab); var children = tabCell.children; for (var i = 0; i < children.length; i++) { var el = children[i]; var match = (el.getAttribute('onclick') || '').match(/openTab\('([^']+)'\)/); if (!match) { continue; } var tab = match[1]; if (oldTab == tab) { el.style.color = ''; } if (newTab == tab) { el.style.color = 'white'; } } }; } newTopbar.init = init; })(newTopbar || (newTopbar = {})); /** * style tweaks */ var styleTweaks; (function (styleTweaks) { styleTweaks.name = 'styleTweaks'; var bodyRegex = /(\bbody)(\s|$)/i; function addTweakStyle(setting, style) { if (setting != '') { var prefix_1 = setting === '' ? '' : 'body.' + setting + ' '; style = style .replace(/(^\s*|\}\s*)([^\{\}]+)(?=\s*\{)/g, function (wholeMatch, before, rules) { return before + rules.split(',').map(function (rule) { if (bodyRegex.test(rule) && setting !== '') { return rule.replace(bodyRegex, '$1.' + setting + '$2'); } return rule.replace(/^(\s*\n\s*)?/, '$1' + prefix_1); }).join(','); }); document.body.classList.add(setting); } addStyle(style, setting != '' ? setting : null); } // tweak oil production/consumption function tweakOil() { addTweakStyle('tweak-oil', "\nspan#oil-flow-values\n{\n\tmargin-left: .5em;\n\tpadding-left: 2rem;\n\tposition: relative;\n}\n#oil-flow-values > span:nth-child(-n+2)\n{\n\tfont-size: 0px;\n\tposition: absolute;\n\tleft: 0;\n\ttop: -0.75rem;\n\tvisibility: hidden;\n}\n#oil-flow-values > span:nth-child(-n+2) > span\n{\n\tfont-size: 1rem;\n\tvisibility: visible;\n}\n#oil-flow-values > span:nth-child(2)\n{\n\ttop: 0.75rem;\n}\n#oil-flow-values span[data-item-display=\"oilIn\"]::before\n{\n\tcontent: '+';\n}\n#oil-flow-values span[data-item-display=\"oilOut\"]::before\n{\n\tcontent: '-';\n}\n\t\t"); // make room for oil cell on small devices var oilFlowValues = document.getElementById('oil-flow-values'); var oilFlowCell = oilFlowValues.parentElement; oilFlowCell.style.width = '30%'; } function tweakSelection() { addTweakStyle('no-select', "\ntable.tab-bar,\nspan.item-box,\ndiv.farming-patch,\ndiv.farming-patch-locked,\ndiv#tab-sub-container-combat > span,\ntable.top-links a,\n#hero-area > div:last-child\n{\n\t-webkit-user-select: none;\n\t-moz-user-select: none;\n\t-ms-user-select: none;\n\tuser-select: none;\n}\n\t\t"); } // tweak stardust monitor of DH2QoL to keep it in place function tweakStardust() { addTweakStyle('dh2qol', "\n#dh2qol-stardustMonitor\n{\n\tdisplay: inline-block;\n\tmargin-left: .25rem;\n\ttext-align: left;\n\twidth: 2.5rem;\n}\n\t\t"); } function tweakSkillLevelText() { addTweakStyle('', "\ndiv.skill-xp-label\n{\n\ttext-shadow: white 0px 0px 0.5rem;\n}\n\t\t"); } function tweakFightDialog() { addTweakStyle('smaller-fight-dialog', "\n#dialogue-fight img[width=\"150px\"]\n{\n\twidth: 120px;\n\theight: 50px;\n}\n#dialogue-fight img[src=\"images/icons/combat.png\"] ~ br\n{\n\tdisplay: none;\n}\n\t\t"); } function addAdditionalSkillBars() { var _loadSkillTabs = win.loadSkillTabs; win.loadSkillTabs = function () { _loadSkillTabs(); for (var _i = 0, SKILL_LIST_1 = SKILL_LIST; _i < SKILL_LIST_1.length; _i++) { var skill = SKILL_LIST_1[_i]; var unlocked = getGameValue(skill + 'Unlocked') == 1; if (!unlocked) { continue; } var xp = getGameValue(skill + 'Xp'); var currentLevelXp = win.getXpNeeded(win.getLevel(xp)); var nextLevelXp = win.getXpNeeded(win.getLevel(xp) + 1); var perc = (xp - currentLevelXp) / (nextLevelXp - currentLevelXp) * 100; var progress = document.getElementById('skill-progress-' + skill); if (progress) { progress.style.width = perc + '%'; } } }; // init additional skill bars addStyle("\ntd[id^=\"top-bar-level-td-\"]\n{\n\tposition: relative;\n}\n#top-bar-levels .skill-bar\n{\n\tbackground-color: grey;\n\theight: 5px;\n\tposition: absolute;\n\tbottom: 5px;\n\tleft: 60px;\n\tright: 10px;\n}\n#top-bar-levels .skill-bar > .skill-progress\n{\n\tbackground-color: rgb(51, 204, 51);\n\theight: 100%;\n\twidth: 0%;\n}\n\t\t"); for (var _i = 0, SKILL_LIST_2 = SKILL_LIST; _i < SKILL_LIST_2.length; _i++) { var skill = SKILL_LIST_2[_i]; var cell = document.getElementById('top-bar-level-td-' + skill); if (!cell) { continue; } var levelBar = document.createElement('div'); levelBar.className = 'skill-bar'; var progress = document.createElement('div'); progress.id = 'skill-progress-' + skill; progress.className = 'skill-progress'; levelBar.appendChild(progress); cell.appendChild(levelBar); // update skill level progress bars on click levelBar.addEventListener('click', function () { return win.loadSkillTabs(); }); } win.loadSkillTabs(); } // highlight cooking level requirement when not matched function highlightCookinglevel() { var _cookFoodDialogue = win.cookFoodDialogue; win.cookFoodDialogue = function (rawFood) { _cookFoodDialogue(rawFood); var dialog = document.getElementById('dialogue-id-cook-food'); if (!dialog) { return; } var levelReq = document.getElementById('dialogue-cook-levelReq'); var levelReqLabel = levelReq && levelReq.previousElementSibling; if (!levelReq || !levelReqLabel) { return; } var fulfilled = win.getCookingLevelReq(rawFood) > win.getLevel(win.cookingXp); levelReq.style.color = fulfilled ? 'rgb(204, 0, 0)' : ''; levelReq.style.fontWeight = fulfilled ? 'bold' : ''; levelReqLabel.style.color = fulfilled ? 'rgb(204, 0, 0)' : ''; var ratioEl = document.getElementById('dialogue-cook-ratio'); if (!ratioEl) { var cookReqBox = levelReq.parentElement; var br = document.createElement('br'); cookReqBox.appendChild(br); var b = document.createElement('b'); b.innerHTML = "<img src=\"images/steak.png\" class=\"image-icon-20\" title=\"Energy\"> per <img src=\"images/icons/fire.png\" class=\"image-icon-20\" title=\"Heat\">: "; cookReqBox.appendChild(b); ratioEl = document.createElement('span'); ratioEl.id = 'dialogue-cook-ratio'; cookReqBox.appendChild(ratioEl); } var heat = win.getHeatNeeded(rawFood); var energy = win.getEnergyGained(rawFood); ratioEl.textContent = format.number(Math.round(energy / heat * 100) / 100); }; } function amountStyle() { var tweakName = 'amount-symbol'; addTweakStyle(tweakName, "\n.item-box:not(#item-box-special-case-questsUnlocked):not(#item-box-pirate):not(#item-box-miner):not(#item-box-boundPumpjacks):not([onclick^=\"openMachineryDialogue(\"]):not(#item-box-sandCollectorsQuest):not(#item-box-boundFilledBonemealBin) > span[data-item-display]::before\n{\n\tcontent: '\\0D7';\n\tmargin-right: .25rem;\n\tmargin-left: -.5rem;\n}\n\t\t"); function setAmountSymbolVisibility(init) { if (init === void 0) { init = false; } var show = settings.get(settings.KEY.amountSymbol); document.body.classList[show ? 'add' : 'remove'](tweakName); if (init) { settings.observe(settings.KEY.amountSymbol, function () { return setAmountSymbolVisibility(); }); } } setAmountSymbolVisibility(true); } function efficiency() { var EFFICIENCY_CLASS = 'efficiency'; addTweakStyle(EFFICIENCY_CLASS, "\nbody\n{\n\tmargin: 0;\n}\nbody > br\n{\n\tdisplay: none;\n}\ntable.top-links\n{\n\tborder-left-width: 0px;\n\tborder-right-width: 0px;\n}\n#game-div\n{\n\tmargin-top: 29px;\n}\n#game-div > table.top-bar,\n#game-div > table.tab-bar,\n#div-chat\n{\n\tborder-width: 0;\n\tmargin-top: 0;\n}\n#game-div > table.top-bar#top-bar-levels\n{\n\tborder-width: 1px 0;\n}\n#notifaction-area\n{\n\tpadding: 0;\n}\nspan.notif-box\n{\n\tmargin: -1px;\n\tmargin-left: 0;\n\tpadding: 5px;\n}\n#game-div > div.tab-container\n{\n\tborder-width: 1px 0 0;\n\tpadding: 0;\n}\ndiv.tab-container > h1.container-title:first-child\n{\n\tdisplay: none;\n}\ndiv.item-box-area,\n#tab-sub-container-farming,\n#tab-sub-container-magic-items\n{\n\tmargin: 0;\n\tpadding: 1px 1px 0 0;\n}\nspan.item-box\n{\n\tmargin: -1px -1px 0 0;\n}\ndiv.tab-container > center > table.table-default,\n#table-crafting-recipe,\n#table-brewing-recipe,\n#table-magic-recipe\n{\n\twidth: calc(100% - 1px);\n}\nul.settings-container,\n#tab-container-crafting .settings-container\n{\n\tmargin: 0;\n}\ndiv.tab-container > br:last-child,\n#tab-sub-container-crafting + br,\n#tab-sub-container-woodcutting + br,\n#tab-sub-container-farming + br,\n#tab-sub-container-brewing + br,\n#tab-sub-container-spells > br,\n#tab-container-shop > br:last-child\n{\n\tdisplay: none;\n}\n\ndiv.side-by-side > div\n{\n\tmargin: 0 !important;\n\twidth: 50%;\n}\n.side-by-side h1.container-title\n{\n\tmargin: 2px;\n}\n.side-by-side h1.container-title + br,\n.side-by-side h1.container-title + br + br,\n.side-by-side input[type=\"image\"] + br,\n#hiscores-table-ingame + br\n{\n\tdisplay: none;\n}\n\ndiv.farming-patch,\ndiv.farming-patch-locked\n{\n\tborder-width: 0;\n\tmargin: 0;\n}\n\n#combat-table-area\n{\n\tborder-width: 0;\n}\n#combat-table-area > tbody > tr > td\n{\n\tborder-width: 0;\n\tborder-right-width: 1px;\n}\n#combat-table-area > tbody > tr > td:last-child\n{\n\tborder-right-width: 0;\n}\n#combat-table-area span.large-button,\n#combat-table-area span.medium-button\n{\n\tmargin: 2px 2px 4px;\n}\n#combat-loot-tables\n{\n\tmargin-top: -3px;\n}\n#combat-loot-tables > table.hiscores-table\n{\n\tmargin: 2px -1px 0 0;\n\twidth: calc(33.33% - 4px);\n}\n#combat-loot-tables > div[style*=\"both\"]\n{\n\theight: 0px;\n}\n\t\t"); var farmingTab = document.getElementById('tab-container-farming'); if (farmingTab) { removeWhitespaceChildNodes(farmingTab); } var combatSubTab = document.getElementById('tab-sub-container-combat'); if (combatSubTab) { removeWhitespaceChildNodes(combatSubTab); } function checkSetting(init) { if (init === void 0) { init = false; } var show = settings.get(settings.KEY.useEfficiencyStyle); document.body.classList[show ? 'add' : 'remove'](EFFICIENCY_CLASS); if (init) { settings.observe(settings.KEY.useEfficiencyStyle, function () { return checkSetting(); }); } } checkSetting(true); } function hardcore() { if (win.isHardcore != 1) { return; } addStyle("\nspan#shop-giant-button-playermarket\n{\n\tbackground-color: gray;\n\tbackground-image: none;\n\tcursor: not-allowed;\n}\n\t\t"); var marketBtn = document.getElementById('shop-giant-button-playermarket'); if (marketBtn) { marketBtn.removeAttribute('onclick'); marketBtn.setAttribute('title', 'The player market is disabled for hardcore accounts'); } } function smallScreen() { addStyle("\ntable.top-links\n{\n\tz-index: 10;\n}\n\t\t"); } function init() { tweakOil(); tweakSelection(); tweakStardust(); tweakSkillLevelText(); tweakFightDialog(); addAdditionalSkillBars(); highlightCookinglevel(); amountStyle(); efficiency(); hardcore(); smallScreen(); } styleTweaks.init = init; })(styleTweaks || (styleTweaks = {})); /** * add ingame notification boxes */ var notifBoxes; (function (notifBoxes) { notifBoxes.name = 'notifBoxes'; function addNotifBox(imageKey, itemKey, showFront) { if (itemKey === void 0) { itemKey = null; } if (showFront === void 0) { showFront = false; } var notifBox = document.createElement('span'); notifBox.className = 'notif-box'; notifBox.id = 'notif-' + imageKey; notifBox.style.display = 'none'; if (showFront) { notifBox.style.cssFloat = 'left'; } notifBox.innerHTML = "<img src=\"images/" + imageKey + ".png\" class=\"image-icon-50\" id=\"notif-" + imageKey + "-img\">"; if (itemKey != null) { notifBox.innerHTML += "<span data-item-display=\"" + itemKey + "\" style=\"margin-left: 10px;\"></span>"; } var notifArea = document.getElementById('notifaction-area'); if (notifArea) { notifArea.appendChild(notifBox); } return notifBox; } function addWorker() { var notifBox = addNotifBox('workers', null, true); function setVisibility() { var show = win.workersTimer === 1; notifBox.style.display = show ? '' : 'none'; } setVisibility(); observer.add('workersTimer', function () { return setVisibility(); }); } function init() { addStyle("\n#notifaction-area\n{\n\tpadding: 5px 0;\n}\nspan.notif-box\n{\n\tfont-size: 1rem;\n\tmargin: 0;\n\tmargin-right: 5px;\n}\ntable.tab-bar\n{\n\tmargin-top: 0;\n}\nspan.notif-box,\ntable.tab-bar td\n{\n\tborder-color: gray;\n}\nspan.notif-box[id^=\"notification-static-\"]\n{\n\tbackground: linear-gradient(rgb(22, 22, 24), rgb(72, 171, 50));\n}\n\t\t"); // remove pure text nodes var notifArea = document.getElementById('notifaction-area'); if (notifArea) { removeWhitespaceChildNodes(notifArea); } addWorker(); } notifBoxes.init = init; })(notifBoxes || (notifBoxes = {})); /** * extend market */ var market; (function (market) { market.name = 'market'; // max limit age: 5min var MAX_LIMIT_AGE = 5 * 60 * 1e3; var PRICE_HISTORY_KEY = 'priceHistory'; // restrict the size of the history of each item to 2000 entries (for a number comparison: 1 entry per minute, would result in 1440 entries per day) var MAX_ENTRIES_PER_ITEM = 2e3; var SYNC_URL_REGEX = /^(?:https?:\/\/)?(?:(?:www\.)?myjson\.com\/|api\.myjson\.com\/bins\/)([^\/]+)$/i; var detectedTedsUIOnce = false; function detectTedsUI() { return detectedTedsUIOnce = detectedTedsUIOnce || typeof win.changeSetting === 'function'; } market.detectTedsUI = detectTedsUI; var priceHistory = store.has(PRICE_HISTORY_KEY) ? store.get(PRICE_HISTORY_KEY) : {}; var getItemColor = function (H, S, L) { return [ "hsl(" + H + ", " + S + "%, " + L + "%)" , "hsl(" + H + ", " + S + "%, " + (L < 35 ? L + 35 : L - 35) + "%)" ]; }; var itemColor = { 'blewitMushroom': getItemColor(255, 100, 78) , 'bronzeBar': getItemColor(39, 100, 46) , 'crystalLeaf': getItemColor(226, 100, 50) , 'diamond': getItemColor(186, 76, 82) , 'dottedGreenLeaf': getItemColor(92, 63, 19) , 'emerald': getItemColor(110, 100, 48) , 'goldLeaf': getItemColor(50, 100, 50) , 'goldBar': getItemColor(54, 100, 46) , 'greenLeaf': getItemColor(92, 63, 28) , 'ironBar': getItemColor(44, 11, 46) , 'limeLeaf': getItemColor(110, 72, 40) , 'promethiumBar': getItemColor(354, 81, 46) , 'redMushroom': getItemColor(0, 83, 48) , 'ruby': getItemColor(5, 87, 45) , 'sapphire': getItemColor(197, 100, 32) , 'shrimp': getItemColor(17, 88, 50) , 'silverBar': getItemColor(0, 0, 74) , 'snapegrass': getItemColor(120, 99, 42) , 'stardust': getItemColor(37, 100, 50) , 'strangeLeaf': getItemColor(195, 100, 40) }; // use ambassadors to name the categories var categoryAmbassador2CategoryName = { 'stone': 'Ores' // 0 , 'emptyChisel': 'Crystals' // 1 , 'bronzeBar': 'Bars' // 2 , 'dottedGreenLeafSeeds': 'Seeds' // 3 , 'logs': 'Logs' // 4 , 'dottedGreenLeaf': 'Ingredients' // 5 , 'rawShrimp': 'Fish' // 6 , 'shrimp': 'Food' // 7 , 'stinger': 'Equipment' // 8 , 'promethiumHelmetMould': 'Mould' // 9 , 'essence': 'Magic' // 10 , 'blueFishingRodOrb': 'Orbs' // 11 , 'stardust': 'Other' // 12 }; var item2Category = new Map(); var category2Name = new Map(); var item2Resolver = new Map(); var itemLimits = new Map(); var offerPerItem = new Map(); var offerList = new Array(); var lastSyncValue = '{}'; function getSyncUrl() { if (!settings.get(settings.KEY.syncPriceHistory)) { return null; } var url = settings.getSub(settings.KEY.syncPriceHistory, 'url'); var match = url.match(SYNC_URL_REGEX); if (!match) { console.error('URL "' + url + '" does not match the expected pattern: ' + SYNC_URL_REGEX.source); return null; } return 'https://api.myjson.com/bins/' + match[1]; } function integratePriceData(data, responseText) { var changed = recIntegrate(data, priceHistory); lastSyncValue = responseText; return changed; function recIntegrate(source, target) { var changed = false; if (typeof source !== typeof target) { console.error('Different data types. Could not integrate data into local price history.\nsource: ' + JSON.stringify(source) + '\ntarget: ' + JSON.stringify(target)); } else if (typeof source === 'object') { for (var key in source) { if (source.hasOwnProperty(key)) { if (!target.hasOwnProperty(key)) { target[key] = source[key]; changed = true; } else if (recIntegrate(source[key], target[key])) { changed = true; } } } } else { // do nothing and prefer the local value } return changed; } } function loadPriceHistory() { var url = getSyncUrl(); if (url) { win.$.get(url, function (data, textStatus, jqXHR) { if (integratePriceData(data, jqXHR.responseText)) { savePriceHistory(true); } }); } } function savePriceHistory(forceWrite) { if (forceWrite === void 0) { forceWrite = false; } for (var itemKey in priceHistory) { var history_1 = priceHistory[itemKey]; var timestampList = Object.keys(history_1).sort(); var i = 0; for (var _i = 0, timestampList_1 = timestampList; _i < timestampList_1.length; _i++) { var timestamp = timestampList_1[_i]; i++; if (i > MAX_ENTRIES_PER_ITEM) { delete history_1[timestamp]; } } } store.set(PRICE_HISTORY_KEY, priceHistory); var url = getSyncUrl(); if (url) { var doPut_1 = function () { $.ajax( { url: url , type: 'PUT' , data: JSON.stringify(priceHistory) , contentType: 'application/json; charset=utf-8' , dataType: 'json' , success: function (data, textStatus, jqXHR) { lastSyncValue = jqXHR.responseText; } }); }; if (forceWrite === true) { doPut_1(); } else { win.$.get(url, function (data, textStatus, jqXHR) { if (lastSyncValue !== jqXHR.responseText) { integratePriceData(data, jqXHR.responseText); } doPut_1(); }); } } } function processMarketData(data) { var nowKey = now(); offerPerItem = new Map(); offerList = new Array(); if (data != 'NONE') { offerList = data.split(';').map(function (offerData) { var values = offerData.split('~'); var itemId = Number(values[1]); var itemKey = win.jsItemArray[itemId]; var itemName = key2Name(itemKey); var categoryId = item2Category.has(itemKey) ? item2Category.get(itemKey) : -1; var offer = { offerId: Number(values[0]) , itemId: itemId , itemKey: itemKey , itemName: itemName , categoryId: categoryId , amount: Number(values[2]) , price: Number(values[3]) , timeLeft: values[4] , playerId: Number(values[5]) }; if (!offerPerItem.has(itemKey)) { offerPerItem.set(itemKey, []); } offerPerItem.get(itemKey).push(offer); var history = priceHistory[itemKey]; if (!history) { history = {}; priceHistory[itemKey] = history; } if (!history.hasOwnProperty(nowKey) || history[nowKey] > offer.price) { history[nowKey] = offer.price; } return offer; }); } savePriceHistory(); } function processItemLimits(itemKey, lowerLimit, upperLimit) { var limit = { timestamp: now() , min: lowerLimit , max: upperLimit }; itemLimits.set(itemKey, limit); if (item2Resolver.has(itemKey)) { var limitArr_1 = [lowerLimit, upperLimit]; item2Resolver.get(itemKey).forEach(function (resolve) { return resolve(limitArr_1); }); item2Resolver.delete(itemKey); return false; } return true; } function showOfferCancelCooldown() { if (detectTedsUI()) { return; } addStyle("\n.market-slot-cancel:not([data-cooldown=\"0\"])\n{\n\tbackground: linear-gradient(hsla(12, 40%, 50%, 1), hsla(12, 40%, 40%, 1));\n\tcursor: not-allowed;\n\tposition: relative;\n}\n.market-slot-cancel:not([data-cooldown=\"0\"]):hover\n{\n\tbackground-color: hsla(0, 40%, 50%, 1);\n}\n.market-slot-cancel:not([data-cooldown=\"0\"])::after\n{\n\tcontent: attr(data-cooldown);\n\tposition: absolute;\n\tright: 10px;\n}\n\t\t"); function slotCooldown(i, init) { if (init === void 0) { init = false; } var cooldownKey = 'marketCancelCooldownSlot' + i; var btn = document.getElementById('market-slot-' + i + '-cancel-btn'); if (btn) { btn.dataset.cooldown = detectTedsUI() ? '0' : getGameValue(cooldownKey).toString(); } if (init) { observer.add(cooldownKey, function () { return slotCooldown(i); }); } } for (var i = 1; i <= 3; i++) { slotCooldown(i, true); } } function addExtraBtns() { var browseBtn = document.querySelector('.market-browse-button'); if (!browseBtn) { return; } var HISTORY_CLASS = 'local-history'; var paddingLeft = 30 + 42; var paddingRight = 30; addStyle("\ncenter > span.market-browse-button,\n#ted-market-ui > span.market-browse-button\n{\n\tposition: relative;\n}\ncenter > span.market-browse-button\n{\n\tpadding-left: " + paddingLeft + "px;\n\tpadding-right: " + paddingRight + "px;\n}\nspan.market-browse-button > span.market-browse-button\n{\n\tpadding: 10px 20px;\n\tposition: absolute;\n\ttop: -1px;\n\tbottom: -1px;\n}\n/*\n*/\nspan.market-browse-button > span.market-browse-button." + HISTORY_CLASS + "\n{\n\tleft: -1px;\n}\nspan.market-browse-button > span.market-browse-button::before\n{\n\tbackground-color: transparent;\n\tbackground-position: center;\n\tbackground-repeat: no-repeat;\n\tbackground-size: 30px;\n\tcontent: '';\n\tposition: absolute;\n\tleft: 0;\n\ttop: 0;\n\tbottom: 0;\n\tright: 0;\n}\n/*\n*/\nspan.market-browse-button." + HISTORY_CLASS + "::before\n{\n\tbackground-image: " + icons.getMd(icons.CHART_LINE) + ";\n}\n/*\n*/\n#ted-market-ui > span.market-browse-button > span.market-browse-button." + HISTORY_CLASS + "\n{\n\tborder-left: 0;\n\tleft: 0;\n}\n\t\t"); var historyBtn = document.createElement('span'); historyBtn.className = 'market-browse-button ' + HISTORY_CLASS; browseBtn.appendChild(historyBtn); var historyItemKey = null; var _postItemDialogue = win.postItemDialogue; win.postItemDialogue = function (offerTypeEl, itemName, inputEl) { historyItemKey = itemName; _postItemDialogue(offerTypeEl, itemName, inputEl); }; var PRICE_HISTORY_DIALOG_ID = 'dialog-price-history'; var PRICE_HISTORY_ID = 'price-history'; var PRICE_HISTORY_ITEM_SELECT_ID = 'price-history-item-select'; addStyle("\n#" + PRICE_HISTORY_DIALOG_ID + "\n{\n\tdisplay: flex;\n\tflex-direction: column;\n}\n#" + PRICE_HISTORY_ID + "\n{\n\tflex-grow: 1;\n\tposition: relative;\n\t-webkit-user-select: none;\n\t-moz-user-select: none;\n\t-ms-user-select: none;\n\tuser-select: none;\n}\n#" + PRICE_HISTORY_ID + " > div\n{\n\tposition: absolute !important;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n}\n#" + PRICE_HISTORY_ID + " .anychart-credits\n{\n\tdisplay: none;\n}\n\t\t"); var dialog = document.createElement('dialog'); dialog.id = PRICE_HISTORY_DIALOG_ID; dialog.style.display = 'none'; dialog.style.overflowX = 'hidden'; dialog.innerHTML = "\n\t\t<select id=\"" + PRICE_HISTORY_ITEM_SELECT_ID + "\" multiple=\"multiple\" data-placeholder=\"Add items\" style=\"width: 100%\"></select>\n\t\t<div id=\"" + PRICE_HISTORY_ID + "\"></div>\n\t\t"; document.body.appendChild(dialog); var itemSelect = document.getElementById(PRICE_HISTORY_ITEM_SELECT_ID); var $itemSelect = win.$(itemSelect); function loadScripts(urlList, callback) { var url = urlList[0]; if (!url) { callback && callback(); return; } var script = document.createElement('script'); script.src = url; script.onload = function () { return loadScripts(urlList.slice(1), callback); }; document.head.appendChild(script); } var monthArray = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; var lastHistoryItemKey; var itemKey2SeriesId = {}; var chart; var stage; // add style for select2 var style = document.createElement('link'); style.rel = 'stylesheet'; style.href = 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css'; document.head.appendChild(style); loadScripts([ 'https://cdn.anychart.com/js/7.14.3/anychart.min.js' , 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js' ], function () { chart = win.anychart.area(); // pass the container id, chart will be displayed there stage = anychart.graphics.create(PRICE_HISTORY_ID); chart.container(stage); var tooltip = chart.tooltip(); tooltip.displayMode('union'); tooltip.format(passThis(function (context) { var name = context.seriesName || 'Price'; return name + ': ' + (isNaN(context.value) ? '-' : format.number(context.value)); })); tooltip.titleFormat(passThis(function (context) { var d = new Date(context.x); return monthArray[d.getMonth()] + ' ' + d.getDate() + ' @ ' + zeroPadLeft(d.getHours()) + ':' + zeroPadLeft(d.getMinutes()) + ':' + zeroPadLeft(d.getSeconds()); })); var valueAxis = chart.yAxis(); valueAxis.title().text('Price').enabled(true); valueAxis.labels().format(passThis(function (context) { return format.number(context.value); })); var timeAxis = chart.xAxis(); timeAxis.labels().format(passThis(function (context) { var d = new Date(context.tickValue); return d.getDate() + '. ' + monthArray[d.getMonth()]; })); var timeScale = win.anychart.scales.dateTime(); var ticks = timeScale.ticks(); ticks.interval(0, 0, 1); chart.xScale(timeScale); var timeScroller = chart.xScroller(); timeScroller.enabled(true); chart.animation(true, 300); chart.legend(true); }); historyBtn.addEventListener('click', function (event) { event.preventDefault(); event.stopPropagation(); var height = Math.floor(.66 * window.innerHeight); var width = Math.min(Math.floor(.66 * window.innerWidth), window.innerWidth - 30); win.$(dialog).dialog( { title: 'Price history from local data' , height: height , width: width }); dialog.style.height = (height) + 'px'; var itemKeyList = Object.keys(priceHistory).sort(); itemSelect.innerHTML = ""; var category2OptGroup = {}; function ensureOptGroup(categoryId) { var optGroup = category2OptGroup[categoryId]; if (!optGroup) { optGroup = document.createElement('optgroup'); optGroup.label = category2Name.get(categoryId) || 'Stuff'; itemSelect.appendChild(optGroup); category2OptGroup[categoryId] = optGroup; } return optGroup; } var categoryList = Array.from(category2Name.keys()).map(function (id) { return Number(id); }).sort(); for (var _i = 0, categoryList_1 = categoryList; _i < categoryList_1.length; _i++) { var categoryId = categoryList_1[_i]; ensureOptGroup(categoryId); } var itemKey2EnabledFn = {}; function replaceEnabled(itemKey, series) { var _enabled = series.enabled.bind(series); itemKey2EnabledFn[itemKey] = _enabled; series.enabled = function (value) { if (value !== undefined) { var itemList = $itemSelect.val(); var index = itemList.indexOf(itemKey); if (index !== -1) { itemList.splice(index, 1); } else { itemList.push(itemKey); } $itemSelect.val(itemList).trigger('change'); } return _enabled(value); }; } var min = Number.MAX_SAFE_INTEGER; var max = 0; var enabledSeriesList = []; var _loop_1 = function (itemKey) { if (!itemColor[itemKey]) { var baseColor = colorGenerator.getRandom( { format: 'hslArray' }); var borderColor = baseColor.slice(0); if (borderColor[2] < 35) { borderColor[2] += 35; } else { borderColor[2] -= 35; } itemColor[itemKey] = [ "hsl(" + baseColor[0] + ", " + baseColor[1] + "%, " + baseColor[2] + "%)" , "hsl(" + borderColor[0] + ", " + borderColor[1] + "%, " + borderColor[2] + "%)" ]; } var history_2 = priceHistory[itemKey]; var keyList = Object.keys(history_2).sort(); var data = keyList .map(function (n) { return ([ Number(n) , history_2[n] ]); }); min = Math.min(Number(keyList[0]), min); max = Math.max(Number(keyList[keyList.length - 1]), max); var id = itemKey2SeriesId[itemKey]; var series = void 0; if (id != null) { series = chart.getSeries(id); series.data(data); } else { var hoverifyColor = function (hslColor) { return ( { color: hslColor , opacity: .8 }); }; series = chart.area(data); itemKey2SeriesId[itemKey] = series.id(); series.name(key2Name(itemKey)); var bgColor = itemColor[itemKey][0]; var strokeColor = itemColor[itemKey][1]; series.fill(bgColor); var bgColorHover = hoverifyColor(bgColor); series.selectFill(bgColorHover); series.hoverFill(bgColorHover); series.stroke(strokeColor, 2); var strokeColorHover = hoverifyColor(strokeColor); series.hoverStroke(strokeColorHover, 2); series.selectStroke(strokeColorHover, 2); var markerOptions = { fill: strokeColor , size: 5 , type: 'circle' }; series.hoverMarkers(markerOptions); series.selectMarkers(markerOptions); replaceEnabled(itemKey, series); } if (lastHistoryItemKey !== historyItemKey) { if (itemKey === historyItemKey) { enabledSeriesList.push(series); } series.enabled(false); } var categoryId = item2Category.has(itemKey) ? item2Category.get(itemKey) : -1; var optGroup = ensureOptGroup(categoryId); var option = document.createElement('option'); option.value = itemKey; option.textContent = key2Name(itemKey); optGroup.appendChild(option); }; for (var _a = 0, itemKeyList_1 = itemKeyList; _a < itemKeyList_1.length; _a++) { var itemKey = itemKeyList_1[_a]; _loop_1(itemKey); } stage.listenOnce('renderfinish', function () { enabledSeriesList.forEach(function (series) { return series.enabled(true); }); }); var timeScale = chart.xScale(); timeScale.minimum(min); timeScale.maximum(max); var timeZoom = chart.xZoom(); var threeDaysLong = 3 * 24 * 60 * 60 * 1e3; timeZoom.setToValues(Math.max(max - threeDaysLong, min), max); // call the chart draw() method to initiate chart display chart.draw(true); // init item select if ($itemSelect.data('select2')) { $itemSelect.select2('destroy'); } $itemSelect.select2(); function getEnabledFn(event) { var data = event.params.data; var itemKey = data.id; var enabledFn = itemKey2EnabledFn[itemKey]; if (enabledFn) { return enabledFn; } else { var id = itemKey2SeriesId[itemKey]; var series = chart.getSeries(id); return series.enabled.bind(series); } } $itemSelect.on('select2:select', function (event) { getEnabledFn(event)(true); }); $itemSelect.on('select2:unselect', function (event) { getEnabledFn(event)(false); // close select menu when it was closed before an element has been removed var openBefore = $itemSelect.data('select2').$container.hasClass('select2-container--open'); setTimeout(function () { if (!openBefore && $itemSelect.data('select2').$container.hasClass('select2-container--open')) { $itemSelect.select2('close'); } }); }); lastHistoryItemKey = historyItemKey; }); } var categoryList = [-1]; var itemListPerCategory = new Map(); function improveOfferList() { var itemArea = document.getElementById('dialogue-market-items-area'); if (itemArea) { var children = itemArea.children; for (var i = 1; i < children.length; i++) { var categoryId = i - 1; categoryList.push(categoryId); var box = children.item(i); var inputs = box.children; for (var j = 0; j < inputs.length; j++) { var match = inputs.item(j).src.match(/images\/([^\/]+)\.(?:png|jpe?g|gif)/); if (!match) { continue; } var itemKey = match[1]; item2Category.set(itemKey, categoryId); if (categoryAmbassador2CategoryName[itemKey]) { category2Name.set(categoryId, categoryAmbassador2CategoryName[itemKey]); } if (!itemListPerCategory.has(categoryId)) { itemListPerCategory.set(categoryId, []); } itemListPerCategory.get(categoryId).push(itemKey); } } } } function getItemLimit(itemKey) { // TODO: combine list of offers with min/max-boundries var limit = itemLimits.get(itemKey); if (limit && limit.timestamp > now() - MAX_LIMIT_AGE) { return Promise.resolve([limit.min, limit.max]); } else if (!win.jsTradalbeItems.hasOwnProperty(itemKey)) { return Promise.resolve([0, 0]); } return new Promise(function (resolve, reject) { win.postItemDialogue( { value: 'sell' }, itemKey, null); if (!item2Resolver.has(itemKey)) { item2Resolver.set(itemKey, []); } item2Resolver.get(itemKey).push(resolve); setTimeout(function () { return reject(new Error('Request timed out')); }, 30e3); }); } function calcMarketValue(items) { var itemKeyList = Object.keys(items); return Promise.all(itemKeyList.map(function (key) { return getItemLimit(key); })) .then(function (limitList) { var sum = [0, 0]; for (var i = 0; i < itemKeyList.length; i++) { var amount = items[itemKeyList[i]]; var limit = limitList[i]; sum[0] += amount * limit[0]; sum[1] += amount * limit[1]; } return sum; }); } market.calcMarketValue = calcMarketValue; function init() { showOfferCancelCooldown(); addExtraBtns(); improveOfferList(); var _chosenPostItemDialogue = win.chosenPostItemDialogue; win.chosenPostItemDialogue = function (itemName, lowerLimit, upperLimit) { if (processItemLimits(itemName, Number(lowerLimit), Number(upperLimit))) { _chosenPostItemDialogue(itemName, lowerLimit, upperLimit); } }; var _addToPlayerMarket = win.addToPlayerMarket; win.addToPlayerMarket = function (data) { processMarketData(data); _addToPlayerMarket(data); }; loadPriceHistory(); // delay (debounce) sending the request for 3s var startDebouncedRequest = debounce(function () { return loadPriceHistory(); }, 3e3); settings.observe(settings.KEY.syncPriceHistory, function () { return startDebouncedRequest(); }); settings.observeSub(settings.KEY.syncPriceHistory, 'url', function () { return startDebouncedRequest(); }); } market.init = init; })(market || (market = {})); var combat; (function (combat) { combat.name = 'combat'; var LOOT_TABLE_URL = '/wiki/combat.php'; var COMBAT_LOOT_TABLES_ID = 'combat-loot-tables'; var CAT_2_NAME = { 'always': 'Always' , 'common': 'Common' , 'uncommon': 'Uncommon' , 'rare': 'Rare' , 'veryrare': 'Very Rare' }; var lootInfoInitialized = false; var lootInfo = {}; function readLootTable(table) { var monsterImg = table.getElementsByTagName('img').item(0); var src = monsterImg.getAttribute('src') || ''; var monsterId = src.replace(/.+npc\/(\d+)\.png$/, '$1'); var info = { always: [] , common: [] , uncommon: [] , rare: [] , veryrare: [] }; for (var i = 2; i < table.rows.length; i++) { var row = table.rows.item(i); var match = row.cells.item(0).innerHTML.match(/images\/(.+)\.png/); if (!match) { console.error('no item key found:', row.innerHTML); continue; } var itemKey = match[1]; var amount = row.cells.item(1).textContent || ''; var rarityCategory = row.cells.item(2).className; if (!info.hasOwnProperty(rarityCategory)) { console.error('unknown rarity category:', rarityCategory); continue; } info[rarityCategory].push( { key: itemKey , amount: amount.split(' - ').map(function (s) { return Number(s.replace(/\D/g, '')); }) }); } lootInfo[monsterId] = info; lootInfoInitialized = true; } function updateLootTableInfo() { return doGet(LOOT_TABLE_URL) .then(function (response) { var parser = new DOMParser(); var doc = parser.parseFromString(response, 'text/html'); var tables = doc.getElementsByTagName('table'); for (var i = 0; i < tables.length; i++) { readLootTable(tables.item(i)); } return lootInfo; }) .then(function (info) { setLootTableTabContent(info); }); } function addLootTableTab() { var subTabContainer = document.getElementById('tab-sub-container-combat'); var itemContainer = document.getElementById('tab-sub-container-combat-large-btns'); var afterEl = itemContainer && itemContainer.previousElementSibling; if (!subTabContainer || !afterEl) { return; } addStyle("\nspan.medium-button.active\n{\n\tbackground: hsla(109, 55%, 43%, 1);\n\tcursor: not-allowed;\n}\n#combat-table-area:not([style$=\"auto;\"]) > tbody > tr > td:last-child\n{\n\twidth: 100%;\n}\n#" + COMBAT_LOOT_TABLES_ID + " td.always\n{\n\tbackground-color: #ccffff;\n}\n#" + COMBAT_LOOT_TABLES_ID + " td.common\n{\n\tbackground-color: #ccffcc;\n}\n#" + COMBAT_LOOT_TABLES_ID + " td.uncommon\n{\n\tbackground-color: #ffffcc;\n}\n#" + COMBAT_LOOT_TABLES_ID + " td.rare\n{\n\tbackground-color: #ffcc99;\n}\n#" + COMBAT_LOOT_TABLES_ID + " td.veryrare\n{\n\tbackground-color: #ff9999;\n}\n\n#" + COMBAT_LOOT_TABLES_ID + " table.hiscores-table\n{\n\tfloat: left;\n\tmargin: 0 10px;\n\twidth: calc(33.3% - 20px);\n}\n#" + COMBAT_LOOT_TABLES_ID + " table.hiscores-table img.image-icon-50\n{\n\twidth: auto;\n}\n\t\t"); var REFRESH_LOOT_TABLE_ID = 'refresh-loot-table'; var subTab = document.createElement('span'); subTab.className = 'large-button'; subTab.innerHTML = "<img class=\"image-icon-50\" src=\"images/combatDropTable.png\" style=\"filter: grayscale(100%);\">Loot"; subTab.addEventListener('click', function () { var _confirmDialogue = win.confirmDialogue; win.confirmDialogue = function () {}; win.clicksOpenDropTable(); win.confirmDialogue = _confirmDialogue; win.openSubTab('loot'); }); function setLootTabVisibility() { var show = settings.get(settings.KEY.showLootTab); subTab.style.display = show ? '' : 'none'; var dropTableItemBox = document.getElementById('item-box-combatDropTable'); if (dropTableItemBox) { dropTableItemBox.style.display = show ? 'none' : ''; } if (show && !lootInfoInitialized) { updateLootTableInfo(); } } setLootTabVisibility(); settings.observe(settings.KEY.showLootTab, function () { return setLootTabVisibility(); }); subTabContainer.insertBefore(subTab, afterEl); var combatSubTab = document.getElementById('tab-sub-container-combat'); var equipSubTab = document.getElementById('tab-sub-container-equip'); var spellsSubTab = document.getElementById('tab-sub-container-spells'); var subPanelContainer = combatSubTab.parentElement; var lootSubTab = document.createElement('div'); lootSubTab.id = 'tab-sub-container-loot'; lootSubTab.style.display = 'none'; lootSubTab.innerHTML = "<span onclick=\"openTab('combat')\" class=\"medium-button\"><img class=\"image-icon-30\" src=\"images/icons/back.png\"> back</span>\n\t\t<span id=\"" + REFRESH_LOOT_TABLE_ID + "\" class=\"medium-button\">refresh</span>\n\t\t<div id=\"" + COMBAT_LOOT_TABLES_ID + "\">Loading...</div>"; subPanelContainer.appendChild(lootSubTab); var refreshBtn = document.getElementById(REFRESH_LOOT_TABLE_ID); if (refreshBtn) { refreshBtn.addEventListener('click', function () { if (refreshBtn.classList.contains('active')) { return; } refreshBtn.classList.add('active'); updateLootTableInfo() .then(function () { return refreshBtn.classList.remove('active'); }) .catch(function () { return refreshBtn.classList.remove('active'); }); }); } var _openSubTab = win.openSubTab; win.openSubTab = function (tab) { combatSubTab.style.display = 'none'; equipSubTab.style.display = 'none'; spellsSubTab.style.display = 'none'; lootSubTab.style.display = 'none'; _openSubTab(tab); if (tab == 'loot') { lootSubTab.style.display = 'block'; } }; var _loadDefaultCombatTab = win.loadDefaultCombatTab; win.loadDefaultCombatTab = function () { _loadDefaultCombatTab(); lootSubTab.style.display = 'none'; }; } function setLootTableTabContent(lootInfo) { var combatTableWrapper = document.getElementById(COMBAT_LOOT_TABLES_ID); if (!combatTableWrapper) { return; } combatTableWrapper.innerHTML = ""; for (var monsterId in lootInfo) { var info = lootInfo[monsterId]; var monsterNum = Number(monsterId); if (monsterNum > 1 && monsterNum % 3 === 1) { var lineBreak = document.createElement('div'); lineBreak.style.clear = 'both'; lineBreak.innerHTML = "<br>"; combatTableWrapper.appendChild(lineBreak); } var table = document.createElement('table'); table.className = 'hiscores-table'; var imgRow = table.insertRow(-1); imgRow.innerHTML = "<td colspan=\"3\">\n\t\t\t\t<img src=\"../images/hero/npc/" + monsterId + ".png\" class=\"image-icon-50\">\n\t\t\t</td>"; var headerRow = table.insertRow(-1); headerRow.innerHTML = "<th>Item</th><th>Amount</th><th>Rarity</th>"; for (var rarityCategory in info) { var itemList = info[rarityCategory]; for (var i = 0; i < itemList.length; i++) { var item = itemList[i]; var row = table.insertRow(-1); row.innerHTML = "<td><img src=\"../images/" + item.key + ".png\" class=\"image-icon-40\"></td><td>" + item.amount.map(function (n) { return format.number(n); }).join(' - ') + "</td><td class=\"" + rarityCategory + "\">" + CAT_2_NAME[rarityCategory] + "</td>"; } } combatTableWrapper.appendChild(table); } } function init() { addLootTableTab(); if (settings.get(settings.KEY.showLootTab)) { updateLootTableInfo(); } } combat.init = init; })(combat || (combat = {})); /** * farming improvements */ var farming; (function (farming) { farming.name = 'farming'; var SEED_INFO_REGEX = { minLevel: />\s*Level:/ , stopsDyingLevel: />\s*Stops\s+Dying\s+Level:/ , bonemeal: />\s*Bonemeal:/ , woodcuttingLevel: />\s*Woodcutting\s+Level:/ }; var seedInfoSpans = {}; var seedInfo = {}; var checkInfo = { bonemeal: function (amount) { return amount <= win.bonemeal; } , minLevel: function (level) { return level <= win.getLevel(win.farmingXp); } , stopsDyingLevel: function (level) { return level <= win.getLevel(win.farmingXp); } , woodcuttingLevel: function (level) { return level <= win.getLevel(win.woodcuttingXp); } }; var RED = 'rgb(204, 0, 0)'; function addBetterStyle() { var CLASS_NAME = 'seedHighlight'; addStyle("\n#dialogue-plant-farming input.input-img-farming-patch-dialogue-seeds\n{\n\tpadding: 2px 4px;\n}\n#dialogue-plant-farming #dialogue-plant-grassSeeds\n{\n\theight: 75px;\n\tpadding: 0;\n\twidth: 75px;\n}\n#dialogue-plant-farming #dialogue-plant-treeSeeds,\n#dialogue-plant-farming #dialogue-plant-oakTreeSeeds,\n#dialogue-plant-farming #dialogue-plant-willowTreeSeeds,\n#dialogue-plant-farming #dialogue-plant-mapleTreeSeeds\n{\n\tpadding: 0;\n}\n\nbody." + CLASS_NAME + " #dialogue-plant-farming input.input-img-farming-patch-dialogue-seeds:hover\n{\n\tbackground-color: transparent;\n\tborder: 1px solid black;\n\tmargin: -1px;\n\ttransform: scale(1.1);\n}\n\t\t"); // seedHighlight function updateHoverStyle() { document.body.classList[settings.get(settings.KEY.highlightUnplantableSeed) ? 'add' : 'remove'](CLASS_NAME); } updateHoverStyle(); settings.observe(settings.KEY.highlightUnplantableSeed, function () { return updateHoverStyle(); }); } function readSeedInfo(seedName, tooltipEl) { var spans = tooltipEl.querySelectorAll(':scope > span'); var infoSpans = { bonemeal: null , minLevel: null , stopsDyingLevel: null , woodcuttingLevel: null }; var info = { bonemeal: 0 , minLevel: 0 , stopsDyingLevel: 0 , woodcuttingLevel: 0 }; var i = 2; for (var key in SEED_INFO_REGEX) { if (SEED_INFO_REGEX[key].test(spans[i].innerHTML)) { infoSpans[key] = spans.item(i); var textNode = spans.item(i).lastChild; info[key] = parseInt(textNode.textContent || '', 10); i++; } } seedInfoSpans[seedName] = infoSpans; seedInfo[seedName] = info; } function checkSpan(span, fulfilled) { span.style.color = fulfilled ? '' : RED; span.style.fontWeight = fulfilled ? '' : 'bold'; } function checkSeedInfo(seedName, init) { if (init === void 0) { init = false; } var highlight = settings.get(settings.KEY.highlightUnplantableSeed); var info = seedInfo[seedName]; var spans = seedInfoSpans[seedName]; var canBePlanted = true; for (var key in info) { var span = spans[key]; if (span) { var fulfilled = checkInfo[key](info[key]); checkSpan(span, !highlight || fulfilled); canBePlanted = !highlight || canBePlanted && (key == 'stopsDyingLevel' || fulfilled); } } var itemBox = document.getElementById('item-box-' + seedName); if (itemBox) { itemBox.style.opacity = (!highlight || canBePlanted) ? '' : '.5'; } var plantInput = document.getElementById('dialogue-plant-' + seedName); if (plantInput) { plantInput.style.backgroundColor = (!highlight || canBePlanted) ? '' : 'hsla(0, 100%, 50%, .5)'; } if (init) { observer.add('bonemeal', function () { return checkSeedInfo(seedName); }); observer.add('farmingXp', function () { return checkSeedInfo(seedName); }); observer.add('woodcuttingXp', function () { return checkSeedInfo(seedName); }); settings.observe(settings.KEY.highlightUnplantableSeed, function () { return checkSeedInfo(seedName); }); } } function getSeedInfo(seedName) { return seedInfo[seedName]; } farming.getSeedInfo = getSeedInfo; function init() { addBetterStyle(); // read all seed information var tooltipEls = document.querySelectorAll('div[id^="tooltip-"][id$="Seeds"]'); for (var i = 0; i < tooltipEls.length; i++) { var tooltipEl = tooltipEls[i]; var seedName = tooltipEl.id.replace(/^tooltip-/, ''); readSeedInfo(seedName, tooltipEl); checkSeedInfo(seedName, true); } } farming.init = init; })(farming || (farming = {})); /** * general features which doesn't really belong anywhere */ var general; (function (general) { general.name = 'general'; // disable the drink button for 3 seconds var DRINK_DELAY = 3; function getSentBoat() { for (var i = 0; i < BOAT_LIST.length; i++) { if (getGameValue(BOAT_LIST[i] + 'Timer') > 0) { return BOAT_LIST[i]; } } return null; } function checkBoat(boat) { var boatDialog = null; var sendBtn = null; var initiatedDialogs = document.querySelectorAll('div[role="dialog"]'); for (var i = 0; i < initiatedDialogs.length; i++) { var dialog = initiatedDialogs[i]; if (dialog.style.display !== 'none') { var btn = dialog.querySelector('input[type="button"][value="Send Boat"]'); if (btn) { sendBtn = btn; boatDialog = dialog; break; } } } if (!boatDialog || !sendBtn) { return; } var smallboxes = boatDialog.querySelectorAll('div.basic-smallbox'); var baitBox = smallboxes[0]; var runningBox = smallboxes[1]; if (smallboxes.length === 1) { runningBox = document.createElement('div'); runningBox.className = 'basic-smallbox'; runningBox.style.display = 'none'; var parent_1 = baitBox.parentElement; var next = baitBox.nextElementSibling; if (parent_1) { if (next) { parent_1.insertBefore(runningBox, next); } else { parent_1.appendChild(runningBox); } } } var sentBoat = getSentBoat(); baitBox.style.display = sentBoat !== null ? 'none' : ''; runningBox.style.display = sentBoat !== null ? '' : 'none'; // just in case Smitty changes this game mechanic somehow, don't disable the button: // sendBtn.disabled = sentBoat !== null; sendBtn.style.color = sentBoat !== null ? 'gray' : ''; win.$(boatDialog).on('dialogclose', function () { if (sendBtn) { sendBtn.style.color = ''; } }); if (sentBoat === boat) { runningBox.innerHTML = "<b>Returning in:</b> <span data-item-display=\"" + boat + "Timer\">" + format.timer(getGameValue(boat + 'Timer')) + "</span>"; } else if (sentBoat !== null) { runningBox.innerHTML = "Wait for the other boat to return."; } else { var enoughBaitAndCoal = win.fishingBait >= win.fishingBaitCost(boat) && (boat !== 'steamBoat' || win.charcoal >= 300); baitBox.style.color = enoughBaitAndCoal ? '' : 'red'; } } function initBoatDialog() { var _clicksBoat = win.clicksBoat; win.clicksBoat = function (boat) { _clicksBoat(boat); checkBoat(boat); }; var _doCommand = win.doCommand; win.doCommand = function (data) { _doCommand(data); if (data.startsWith('RUN_FUNC=SAIL_BOAT_WIND')) { checkBoat('sailBoat'); } }; } var potionDrinkEnable = null; var POTION_ACTIVE_HTML = "<br>It's already active."; function updateDialogEls(timerKey, dialog, close) { if (close === void 0) { close = false; } var timer = getGameValue(timerKey); var showActive = settings.get(settings.KEY.usePotionWarning) && timer > 0 && !close; var confirmText = document.getElementById('dialogue-confirm-text'); var br = confirmText && confirmText.nextElementSibling; if (confirmText && br) { if (showActive) { confirmText.innerHTML += POTION_ACTIVE_HTML; } else { confirmText.innerHTML = confirmText.innerHTML.replace(POTION_ACTIVE_HTML, ''); } br.style.display = showActive ? 'none' : ''; } var confirmBtn = document.getElementById('dialogue-confirm-yes'); if (confirmBtn && showActive) { confirmBtn.disabled = true; var i_1 = DRINK_DELAY; var updateValue_1 = function () { confirmBtn.value = 'Drink' + (i_1 > 0 ? ' (' + i_1 + ')' : ''); if (i_1 === 0) { potionDrinkEnable && potionDrinkEnable(); } else { i_1--; } }; var countDownInterval_1; var dialogClose_1 = function () { return potionDrinkEnable && potionDrinkEnable(); }; potionDrinkEnable = function () { potionDrinkEnable = null; win.$(dialog).off('dialogclose', dialogClose_1); countDownInterval_1 && clearInterval(countDownInterval_1); confirmBtn.disabled = false; confirmBtn.value = 'Drink'; }; updateValue_1(); countDownInterval_1 = setInterval(function () { return updateValue_1(); }, 1e3); win.$(dialog).on('dialogclose', dialogClose_1); } else if (!showActive) { potionDrinkEnable && potionDrinkEnable(); } } function checkPotionActive(potion) { var dialog = document.getElementById('dialogue-confirm'); var parent = dialog && dialog.parentElement; if (!dialog || !parent || parent.style.display === 'none') { return; } var timerKey = potion + 'Timer'; updateDialogEls(timerKey, dialog); var fn = observer.add(timerKey, function (key, oldValue, newValue) { if (oldValue < newValue && oldValue === 0 || oldValue > newValue && newValue === 0) { updateDialogEls(timerKey, dialog); } }); win.$(dialog).on('dialogclose', function () { updateDialogEls(timerKey, dialog, true); observer.remove(timerKey, fn); }); } function initPotionDialog() { var _confirmDialogue = win.confirmDialogue; win.confirmDialogue = function (width, text, btn1Text, btn2Text, cmd) { potionDrinkEnable && potionDrinkEnable(); _confirmDialogue(width, text, btn1Text, btn2Text, cmd); }; var _clicksPotion = win.clicksPotion; win.clicksPotion = function (potion) { _clicksPotion(potion); checkPotionActive(potion); }; } function init() { initBoatDialog(); initPotionDialog(); } general.init = init; })(general || (general = {})); /** * init */ var scriptInitialized = false; function init() { console.info('[%s] "DH2 Fixed %s" up and running.', (new Date).toLocaleTimeString(), version); scriptInitialized = true; var initModules = [ settings , notifications , log , gameEvents , temporaryFixes , crafting , itemBoxes , chat , timer , smelting , fishingInfo , recipeTooltips , fixNumbers , machineDialog , amountInputs , newTopbar , styleTweaks , notifBoxes , market , combat , farming , general ]; for (var _i = 0, initModules_1 = initModules; _i < initModules_1.length; _i++) { var module = initModules_1[_i]; try { module.init(); } catch (error) { console.error('Error during initialization in module "' + module.name + '":', error); } } } document.addEventListener('DOMContentLoaded', function () { var oldValues = new Map(); var _doCommand = win.doCommand; win.doCommand = function (data) { if (data.startsWith('REFRESH_ITEMS=')) { oldValues = new Map(); for (var _i = 0, _a = win.jsItemArray; _i < _a.length; _i++) { var key = _a[_i]; oldValues.set(key, getGameValue(key)); } _doCommand(data); if (!scriptInitialized) { init(); } return; } else if (!scriptInitialized) { if (data.startsWith('CHAT=')) { var parts = data.substr(5).split('~'); return chat.newAddToChatBox(parts[0], parts[1], parts[2], parts[3], 0); } else if (data.startsWith('PM=')) { return chat.newAddToChatBox(win.username, '0', '0', data.substr(3), 1); } } var ret = commands.process(data); if (ret === void 0) { ret = _doCommand(commands.formatData(data)); } return ret; }; var _refreshItemValues = win.refreshItemValues; win.refreshItemValues = function (itemKeyList, firstLoad) { _refreshItemValues(itemKeyList, firstLoad); for (var _i = 0, itemKeyList_2 = itemKeyList; _i < itemKeyList_2.length; _i++) { var key = itemKeyList_2[_i]; observer.notify(key, oldValues.get(key)); } observer.notifyTick(); }; }); /** * fix web socket errors */ var main; (function (main) { var WS_TIMEOUT_SEC = 30; var WS_TIMEOUT_CODE = 3000; var WS_OPEN_TIMEOUT_SEC = 2 * 60; // 2 minutes // reload the page after 5 consecutive reconnect attempts without successfully opening the websocket once var MAX_RECONNECTS = 5; function webSocketLoaded(event) { if (win.webSocket == null) { console.error('WebSocket instance not initialized!'); return; } // cache old event listener var _onClose = win.webSocket.onclose; var _onError = win.webSocket.onerror; var _onMessage = win.webSocket.onmessage; var _onOpen = win.webSocket.onopen; var commandQueue = []; var _cBytes = win.cBytes; win.cBytes = function (command) { if (win.webSocket && win.webSocket.readyState === WebSocket.OPEN) { _cBytes(command); } else { commandQueue.push(command); } }; var pageLoaded = false; var wsTimeout = null; var reconnectAttempts = 0; function onTimeout() { wsTimeout = null; // renew the websocket if (reconnectAttempts <= MAX_RECONNECTS) { win.webSocket = new WebSocket(win.SSL_ENABLED); win.ignoreBytesTracker = Date.now(); initWSListener(win.webSocket); reconnectAttempts++; } if (win.webSocket) { win.webSocket.close(WS_TIMEOUT_CODE, 'Connection timed out after ' + WS_TIMEOUT_SEC + ' seconds'); } } function updateWSTimeout() { if (wsTimeout) { win.clearTimeout(wsTimeout); } wsTimeout = win.setTimeout(onTimeout, WS_TIMEOUT_SEC * 1e3); } var messageQueue = []; function onMessage(event) { if (pageLoaded) { updateWSTimeout(); return _onMessage.call(this, event); } else { messageQueue.push(event); } }; var wsOpenTimeout = null; function onOpenTimeout() { wsOpenTimeout = null; location.reload(); } function onOpen(event) { reconnectAttempts = 0; if (wsOpenTimeout) { win.clearTimeout(wsOpenTimeout); wsOpenTimeout = null; } // do the handshake first _onOpen.call(this, event); commandQueue.forEach(function (command) { return win.cBytes(command); }); } function onError(event) { console.error('error in websocket:', event); return _onError.call(this, event); } function onClose(event) { console.info('websocket closed:', event); if (event.code !== WS_TIMEOUT_CODE || reconnectAttempts > MAX_RECONNECTS) { location.reload(); } return _onClose.call(this, event); } function initWSListener(ws) { if (ws.readyState === WebSocket.CONNECTING) { wsOpenTimeout = win.setTimeout(onOpenTimeout, WS_OPEN_TIMEOUT_SEC * 1e3); } ws.onclose = onClose; ws.onerror = onError; ws.onmessage = onMessage; ws.onopen = onOpen; } initWSListener(win.webSocket); document.addEventListener('DOMContentLoaded', function () { pageLoaded = true; messageQueue.forEach(function (event) { return win.webSocket.onmessage(event); }); }); } function isScriptElement(el) { return el.nodeName === 'SCRIPT'; } function isWebSocketScript(script) { return script.src.includes('socket.js'); } var found = false; if (document.head) { var scripts = document.head.querySelectorAll('script'); for (var i = 0; i < scripts.length; i++) { if (isWebSocketScript(scripts[i])) { // does this work? scripts[i].onload = webSocketLoaded; found = true; } } } if (!found) { // create an observer instance var mutationObserver_1 = new MutationObserver(function (mutationList) { mutationList.forEach(function (mutation) { if (mutation.addedNodes.length === 0) { return; } for (var i = 0; i < mutation.addedNodes.length; i++) { var node = mutation.addedNodes[i]; if (isScriptElement(node) && isWebSocketScript(node)) { mutationObserver_1.disconnect(); node.onload = webSocketLoaded; return; } } }); }); mutationObserver_1.observe(document.head , { childList: true }); } // fix scrollText (e.g. when joining the game and receiving xp at that moment) win.mouseX = win.innerWidth / 2; win.mouseY = win.innerHeight / 2; var _confirm = win.confirm; win.confirm = function (message) { // don't show the annoying update confirm box (instead of a confirm box, an ingame dialog could be used...) if (message && message.indexOf('Ted\'s Market Script') !== -1) { return false; } return _confirm(message); }; })(main || (main = {})); })();