DH2 Fixed's temporary fixed

Improve Diamond Hunt 2's DH2 Fixed

目前为 2018-03-29 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name DH2 Fixed's temporary fixed
  3. // @namespace FileFace
  4. // @description Improve Diamond Hunt 2's DH2 Fixed
  5. // @version 1.3.04
  6. // @license ISC; http://opensource.org/licenses/ISC
  7. // @grant none
  8. // @run-at document-start
  9. // @include *.diamondhunt.co/*
  10. // @match https://www.diamondhunt.co
  11.  
  12.  
  13. // Total errors: 883
  14. // To-do list:
  15. // add xp and stats into table loot mobs
  16.  
  17. // ==/UserScript==
  18. /*jshint multistr: true */
  19. /*jslint es5: true */
  20. // This is a continue developing script from Zorbing's since he has been inactive for a long time, with help from other players
  21. /**
  22. * ISC License (ISC)
  23. *
  24. * Copyright (c) 2017, Martin Boekhoff
  25. *
  26. * Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby
  27. * granted, provided that the above copyright notice and this permission notice appear in all copies.
  28. *
  29. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  30. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  31. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  32. * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  33. * PERFORMANCE OF THIS SOFTWARE.
  34. *
  35. * Source: http://opensource.org/licenses/ISC
  36. */
  37.  
  38. // main script
  39. (function ()
  40. {
  41. 'use strict';
  42. var version = '0.246.2';
  43. var buildTime = new Date('2017-08-12T16:37:11.942Z');
  44. var win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;
  45.  
  46.  
  47. /**
  48. * observer
  49. */
  50. var observer;
  51. (function (observer)
  52. {
  53. observer.GAME_TICK_KEY = 'dh2.gameTick';
  54. var observedKeys = new Map();
  55.  
  56. function add(key, fn)
  57. {
  58. if (key instanceof Array)
  59. {
  60. for (var _i = 0, key_1 = key; _i < key_1.length; _i++)
  61. {
  62. var k = key_1[_i];
  63. add(k, fn);
  64. }
  65. }
  66. else
  67. {
  68. if (!observedKeys.has(key))
  69. {
  70. observedKeys.set(key, new Set());
  71. }
  72. observedKeys.get(key).add(fn);
  73. }
  74. return fn;
  75. }
  76.  
  77. observer.add = add;
  78.  
  79. function notify(key, oldValue)
  80. {
  81. var newValue = getGameValue(key);
  82. if (observedKeys.has(key))
  83. {
  84. observedKeys.get(key).forEach(function (fn)
  85. {
  86. return fn(key, oldValue, newValue);
  87. });
  88. }
  89. }
  90. observer.notify = notify;
  91.  
  92. function notifyTick()
  93. {
  94. notify(observer.GAME_TICK_KEY, Math.floor(now() / 1000));
  95. }
  96. observer.notifyTick = notifyTick;
  97.  
  98. function remove(key, fn)
  99. {
  100. if (key instanceof Array)
  101. {
  102. var ret = [];
  103. for (var _i = 0, key_2 = key; _i < key_2.length; _i++)
  104. {
  105. var k = key_2[_i];
  106. ret.push(remove(k, fn));
  107. }
  108. return ret;
  109. }
  110. if (!observedKeys.has(key))
  111. {
  112. return false;
  113. }
  114. return observedKeys.get(key).delete(fn);
  115. }
  116. observer.remove = remove;
  117.  
  118. function addTick(fn)
  119. {
  120. return add(observer.GAME_TICK_KEY, fn);
  121. }
  122. observer.addTick = addTick;
  123.  
  124. function removeTick(fn)
  125. {
  126. return remove(observer.GAME_TICK_KEY, fn);
  127. }
  128. observer.removeTick = removeTick;
  129. })(observer || (observer = {}));
  130. /**
  131. * global constants
  132. */
  133. var PLUS_MINUS_SIGN = String.fromCharCode(177);
  134. var TIER_LEVELS = ['empty', 'sapphire', 'emerald', 'ruby', 'diamond'];
  135. var TIER_NAMES = ['Standard', 'Sapphire', 'Emerald', 'Ruby', 'Diamond'];
  136. var TIER_ITEMS = ['pickaxe', 'shovel', 'hammer', 'axe', 'rake', 'trowel', 'fishingRod', 'chisel'];
  137. var ORB_ITEMS = ['pickaxe', 'shovel', 'hammer', 'axe', 'rake', 'trowel', 'fishingRod', 'chisel', 'oilPipe'];
  138. var TIER_ITEMS_NOT_BINDABLE = ['rake', 'trowel'];
  139. var FURNACE_LEVELS = ['stone', 'bronze', 'iron', 'silver', 'gold', 'promethium', 'runite'];
  140. var OVEN_LEVELS = ['bronze', 'iron', 'silver', 'gold', 'promethium', 'runite'];
  141. var WAND_LEVELS = ['wooden', 'oak', 'willow', 'maple', 'stardust', 'strange', 'ancient'];
  142. var OIL_STORAGE_SIZES = [10e3, 50e3, 100e3, 300e3, 600e3, 2e6];
  143. var RECIPE_MAX = {
  144. 'brewing':
  145. {
  146. 'braveryPotion':
  147. {
  148. max: 1
  149. }
  150. , 'stardustCrystalPotion':
  151. {
  152. max: 1
  153. }
  154. }
  155. , 'cooksBook':
  156. {}
  157. , 'crafting':
  158. {
  159. 'drills':
  160. {
  161. max: 10
  162. }
  163. , 'crushers':
  164. {
  165. max: 10
  166. }
  167. , 'giantDrills':
  168. {
  169. max: 10
  170. }
  171. , 'excavators':
  172. {
  173. max: 10
  174. }
  175. , 'oilPipe':
  176. {
  177. max: 1
  178. }
  179. , 'pumpjacks':
  180. {
  181. max: 10
  182. }
  183. , 'rowBoat':
  184. {
  185. max: 1
  186. }
  187. , 'canoe':
  188. {
  189. max: 1
  190. }
  191. , 'sailBoat':
  192. {
  193. max: 1
  194. }
  195. , 'steamBoat':
  196. {
  197. max: 1
  198. }
  199. // thanks aguyd
  200. , 'bonemealBin':
  201. {
  202. extraKeys: ['boundFilledBonemealBin']
  203. , max: 1
  204. }
  205. , 'oilFactory':
  206. {
  207. max: 1
  208. }
  209. , 'brewingKit':
  210. {
  211. max: 1
  212. }
  213. , 'rocket':
  214. {
  215. max: 1
  216. }
  217. }
  218. , 'magic':
  219. {}
  220. };
  221. var SMELTING_REQUIREMENTS = {
  222. 'glass':
  223. {
  224. sand: 1
  225. , oil: 10
  226. }
  227. , 'bronzeBar':
  228. {
  229. copper: 1
  230. , tin: 1
  231. , oil: 10
  232. }
  233. , 'ironBar':
  234. {
  235. iron: 1
  236. , oil: 100
  237. }
  238. , 'silverBar':
  239. {
  240. silver: 1
  241. , oil: 300
  242. }
  243. , 'goldBar':
  244. {
  245. gold: 1
  246. , oil: 1e3
  247. }
  248. , 'promethiumBar':
  249. {
  250. promethium: 1
  251. , charcoal: 1
  252. }
  253. };
  254. var PLANT_NAME = {
  255. '1': 'Dark Mushrooms'
  256. , '2': 'Red Mushrooms'
  257. , '3': 'Dotted Green Leaves'
  258. , '4': 'Green Leaves'
  259. , '5': 'Lime Leaves'
  260. , '6': 'Gold Leaves'
  261. , '7': 'Striped Gold Leaves'
  262. , '8': 'Crystal Leaves'
  263. , '9': 'Striped Crystal Leaves'
  264. , '10': 'Blewit Mushrooms'
  265. , '11': 'Snapegrass'
  266. , '12': 'Tree'
  267. , '13': 'Oak Tree'
  268. , '14': 'Wheat'
  269. , '15': 'Willow Tree'
  270. , '16': 'Grass'
  271. , '17': 'Maple Tree'
  272. , '18': 'Stardust Tree'
  273. , '19': 'Carrots'
  274. , '20': 'Tomatoes'
  275. , '21': 'Potatoes'
  276. , '22': 'Strange Leaf Tree'
  277. , '23': 'Light Mushrooms'
  278. , '24': 'Pumpkins'
  279. , '25': 'Ancient Tree'
  280. , '26': 'Stardust Plant'
  281. , '27': 'White Leaf'
  282. };
  283. var SKILL_LIST = ['mining', 'crafting', 'woodcutting', 'farming', 'brewing', 'combat', 'fishing', 'cooking', 'magic'];
  284. var AREA_LIST = ['fields', 'forests', 'caves', 'volcano', 'northFields', 'hauntedMansion'];
  285. var AREA_NAMES = ['Fields', 'Forests', 'Caves', 'Volcano', 'Northern Fields', 'Haunted Mansion', 'Moon', 'Dark Forest'];
  286.  
  287. function getAreaName(areaId)
  288. {
  289. if (areaId === 33)
  290. {
  291. return 'Quest';
  292. }
  293. else if (areaId === 34)
  294. {
  295. return "Faradox's Tombs";
  296. }
  297. else if (areaId === 35)
  298. {
  299. return "Goblin Hideout";
  300. }
  301. else
  302. {
  303. return AREA_NAMES[areaId];
  304. }
  305. }
  306. var MONSTER_NAMES = ['Chicken', 'Rat', 'Bee', 'Snake', 'Forest Tree', 'Thief', 'Bear', 'Bat', 'Skeleton', 'Golem', 'Fire Bird', 'Volcano Mage', 'Lizard', 'Northern Tree', 'Ice Bird', 'Phantom', 'Ghost', 'Grim Reaper', 'Troll', 'Five Eyed', 'Robot', 'Dark Mage', 'Pirate Skeleton', 'Dark Witch'];
  307.  
  308. function getMonsterName(monsterId)
  309. {
  310. if (monsterId === 101)
  311. {
  312. return 'Ghostly Old Mage';
  313. }
  314. else if (monsterId === 99)
  315. {
  316. return 'Evil Snake';
  317. }
  318. else if (monsterId === 100)
  319. {
  320. return 'Easter Bunny';
  321. }
  322. else if (monsterId === 102)
  323. {
  324. return '1st Tomb Monster';
  325. }
  326. else if (monsterId === 103)
  327. {
  328. return '2nd Tomb Monster';
  329. }
  330. else if (monsterId === 104)
  331. {
  332. return '3rd Tomb Monster';
  333. }
  334. else if (monsterId === 105)
  335. {
  336. return '4th Tomb Monster';
  337. }
  338. else if (monsterId === 106)
  339. {
  340. return '5th Tomb Monster';
  341. }
  342. else if (monsterId === 107)
  343. {
  344. return 'Gem Goblin';
  345. }
  346. else
  347. {
  348. return MONSTER_NAMES[monsterId];
  349. }
  350. }
  351. var FISH_XP = {
  352. 'rawShrimp': 50
  353. , 'rawSardine': 500
  354. , 'rawSalmon': 700
  355. , 'rawTuna': 3e3
  356. , 'rawLobster': 5e3
  357. , 'rawSwordfish': 5e3
  358. , 'rawEel': 6e3
  359. , 'rawShark': 12e3
  360. , 'rawWhale': 20e3
  361. , 'rawRainbowFish': 30e3
  362. };
  363. var BOAT_LIST = ['rowBoat', 'canoe', 'sailBoat', 'steamBoat'];
  364. var TRIP_DURATION = {
  365. 'rowBoat': 3
  366. , 'canoe': 5
  367. , 'sailBoat': 7
  368. , 'steamBoat': 10
  369. };
  370. var MAX_ROCKET_MOON_KM = 384400;
  371. var MAX_ROCKET_MARS_KM = 54600000;
  372. var format;
  373. (function (format)
  374. {
  375. var UNITS = [
  376. {
  377. threshold: 10e3
  378. , factor: 1e3
  379. , token: 'k'
  380. }
  381. , {
  382. threshold: 1e6
  383. , factor: 1e6
  384. , token: 'M'
  385. }
  386. , {
  387. threshold: 1e9
  388. , factor: 1e9
  389. , token: 'B'
  390. }
  391. , {
  392. threshold: 1e12
  393. , factor: 1e12
  394. , token: 'T'
  395. }
  396. , {
  397. threshold: 1e15
  398. , factor: 1e15
  399. , token: 'Q'
  400. }];
  401. var TIME_STEPS = [
  402. {
  403. threshold: 1
  404. , name: 'second'
  405. , short: 'sec'
  406. , padp: 0
  407. }
  408. , {
  409. threshold: 60
  410. , name: 'minute'
  411. , short: 'min'
  412. , padp: 0
  413. }
  414. , {
  415. threshold: 3600
  416. , name: 'hour'
  417. , short: 'h'
  418. , padp: 1
  419. }
  420. , {
  421. threshold: 86400
  422. , name: 'day'
  423. , short: 'd'
  424. , padp: 2
  425. }];
  426.  
  427. function ensureNumber(num)
  428. {
  429. return (typeof num === 'number' ? num : Number(num));
  430. }
  431.  
  432. function number(num, shorten)
  433. {
  434. if (shorten === void 0)
  435. {
  436. shorten = false;
  437. }
  438. num = ensureNumber(num);
  439. if (shorten)
  440. {
  441. for (var i = UNITS.length - 1; i >= 0; i--)
  442. {
  443. var unit = UNITS[i];
  444. if (num >= unit.threshold)
  445. {
  446. return number(Math.round(num / unit.factor)) + unit.token;
  447. }
  448. }
  449. }
  450. return num.toLocaleString('en');
  451. }
  452. format.number = number;
  453.  
  454. function numbersInText(text)
  455. {
  456. return text.replace(/\d(?:[\d',\.]*\d)?/g, function (numStr)
  457. {
  458. return number(numStr.replace(/\D/g, ''));
  459. });
  460. }
  461. format.numbersInText = numbersInText;
  462. // use time format established in DHQoL (https://greasyfork.org/scripts/16041-dhqol)
  463. function timer(timer, shorten)
  464. {
  465. if (shorten === void 0)
  466. {
  467. shorten = true;
  468. }
  469. if (typeof timer === 'string')
  470. {
  471. timer = parseInt(timer, 10);
  472. }
  473. timer = Math.max(timer, 0);
  474. var days = Math.floor(timer / 86400); // 24 * 60 * 60
  475. var hours = Math.floor((timer % 86400) / 3600); // 60 * 60
  476. var minutes = Math.floor((timer % 3600) / 60);
  477. var seconds = timer % 60;
  478. return (shorten && days === 0 ? '' : days + 'd ')
  479. + (shorten && days === 0 && hours === 0 ? '' : zeroPadLeft(hours) + ':')
  480. + zeroPadLeft(minutes) + ':'
  481. + zeroPadLeft(seconds);
  482. }
  483. format.timer = timer;
  484.  
  485. function time2NearestUnit(time, long)
  486. {
  487. if (long === void 0)
  488. {
  489. long = false;
  490. }
  491. var step = TIME_STEPS[0];
  492. for (var i = TIME_STEPS.length - 1; i > 0; i--)
  493. {
  494. if (time >= TIME_STEPS[i].threshold)
  495. {
  496. step = TIME_STEPS[i];
  497. break;
  498. }
  499. }
  500. var factor = Math.pow(10, step.padp);
  501. var num = Math.round(time / step.threshold * factor) / factor;
  502. var unit = long ? step.name + (num === 1 ? '' : 's') : step.short;
  503. return num + ' ' + unit;
  504. }
  505. format.time2NearestUnit = time2NearestUnit;
  506.  
  507. function sec2Str(seconds)
  508. {
  509. seconds = Number(seconds);
  510. if (seconds < 0)
  511. {
  512. return seconds.toString();
  513. }
  514. var s = seconds % 60;
  515. var m = Math.floor(seconds / 60) % 60;
  516. var h = Math.floor(seconds / 3600);
  517. var strs = [];
  518. if (h > 0)
  519. {
  520. strs.push(h + ' hour' + (h == 1 ? '' : 's'));
  521. }
  522. if (m > 0)
  523. {
  524. strs.push(m + ' minute' + (m == 1 ? '' : 's'));
  525. }
  526. if (s > 0)
  527. {
  528. strs.push(s + ' second' + (s == 1 ? '' : 's'));
  529. }
  530. if (strs.length > 1)
  531. {
  532. var glue = ' and ';
  533. for (var i = strs.length - 2; i >= 0; i--)
  534. {
  535. strs[i] = strs[i] + glue + strs[i + 1];
  536. glue = ', ';
  537. }
  538. return strs[0];
  539. }
  540. else
  541. {
  542. return strs[0] || '';
  543. }
  544. }
  545. format.sec2Str = sec2Str;
  546.  
  547. function min2Str(minutes)
  548. {
  549. return sec2Str(Number(minutes) * 60);
  550. }
  551. format.min2Str = min2Str;
  552. })(format || (format = {}));
  553.  
  554. /**
  555. * general functions
  556. */
  557. function getStyle(elId)
  558. {
  559. var id = elId != null ? 'style-' + elId : null;
  560. var styleElement = id != null ? document.getElementById(id) : null;
  561. if (styleElement == null)
  562. {
  563. styleElement = document.createElement('style');
  564. if (id != null)
  565. {
  566. styleElement.id = id;
  567. }
  568. styleElement.type = 'text/css';
  569. document.head.appendChild(styleElement);
  570. }
  571. return styleElement;
  572. }
  573.  
  574. function addStyle(styleCode, elId)
  575. {
  576. var styleElement = getStyle(elId);
  577. styleElement.innerHTML += styleCode;
  578. }
  579.  
  580. function zeroPadLeft(num)
  581. {
  582. return (num < 10 ? '0' : '') + num;
  583. }
  584.  
  585. function capitalize(str)
  586. {
  587. return str[0].toUpperCase() + str.substr(1);
  588. }
  589.  
  590. function key2Name(key, lowerCase)
  591. {
  592. if (lowerCase === void 0)
  593. {
  594. lowerCase = false;
  595. }
  596. var name = key.replace(/[A-Z]/g, function (c)
  597. {
  598. return ' ' + (lowerCase ? c.toLowerCase() : c);
  599. });
  600. return lowerCase ? name : capitalize(name);
  601. }
  602.  
  603. function pluralize(name)
  604. {
  605. return name.replace(/([^aeiou])y$/, '$1ie').replace(/s?$/, '') + 's';
  606. }
  607.  
  608. function split2Words(str, char)
  609. {
  610. if (char === void 0)
  611. {
  612. char = ' ';
  613. }
  614. return str.replace(/[A-Z]/g, char + '$&');
  615. }
  616.  
  617. function getBoundKey(key)
  618. {
  619. return 'bound' + capitalize(key);
  620. }
  621.  
  622. function getTierKey(key, tierLevel)
  623. {
  624. return TIER_LEVELS[tierLevel] + capitalize(key);
  625. }
  626.  
  627. function getWikiaKey(key)
  628. {
  629. return key2Name(key.replace(/^bound-?|^special-case-/i, '').replace(/\d+[km]?$/i, ''))
  630. .replace(/^\s/, '').replace(/[ -]/g, '_')
  631. .replace(/^(?:Empty|Sapphire|Emerald|Ruby|Diamond|Raw|Uncooked|Filled)_/, '')
  632. .replace(/^(?:Bronze|Iron|Silver|Gold|Promethium|Runite)_(?!Bar)/, '')
  633. .replace(/^Npc_/, 'Monster_')
  634. .replace(/_(?:Unlocked|Quest)$/, '');
  635. }
  636.  
  637. function getWikiaLink(key)
  638. {
  639. return 'http://diamondhuntonline.wikia.com/wiki/' + getWikiaKey(key);
  640. }
  641.  
  642. function now()
  643. {
  644. return (new Date()).getTime();
  645. }
  646.  
  647. function ensureTooltip(id, target)
  648. {
  649. var tooltipId = 'tooltip-' + id;
  650. var tooltipEl = document.getElementById(tooltipId);
  651. if (!tooltipEl)
  652. {
  653. tooltipEl = document.createElement('div');
  654. tooltipEl.id = tooltipId;
  655. tooltipEl.style.display = 'none';
  656. var tooltipList = document.getElementById('tooltip-list');
  657. tooltipList.appendChild(tooltipEl);
  658. }
  659. // ensure binded events to show the tooltip
  660. if (target.dataset.tooltipId == null)
  661. {
  662. target.dataset.tooltipId = tooltipId;
  663. win.$(target).bind(
  664. {
  665. mousemove: win.changeTooltipPosition
  666. , mouseenter: win.showTooltip
  667. , mouseleave: function (event)
  668. {
  669. var target = event.target;
  670. var parent = target.parentElement;
  671. // ensure tooltips inside an tooltip element is possible
  672. if (!!target.dataset.tooltipId && parent && !!parent.dataset.tooltipId)
  673. {
  674. win.showTooltip.call(parent, event);
  675. }
  676. else
  677. {
  678. win.hideTooltip(event);
  679. }
  680. }
  681. });
  682. }
  683. return tooltipEl;
  684. }
  685. var timeStr2Sec = (function ()
  686. {
  687. var unitFactors = {
  688. 'd': 24 * 60 * 60
  689. , 'h': 60 * 60
  690. , 'm': 60
  691. , 's': 1
  692. };
  693. return function timeStr2Sec(str)
  694. {
  695. return str
  696. .replace(/(\d+)([hms])/g, function (wholeMatch, num, unit)
  697. {
  698. return parseInt(num) * (unitFactors[unit] || 1) + '+';
  699. })
  700. .split('+')
  701. .map(function (s)
  702. {
  703. return parseInt(s, 10);
  704. })
  705. .filter(function (n)
  706. {
  707. return !isNaN(n);
  708. })
  709. .reduce(function (p, c)
  710. {
  711. return p + c;
  712. }, 0);
  713. };
  714. })();
  715.  
  716. function getGameValue(key)
  717. {
  718. return win[key];
  719. }
  720.  
  721. function getFurnaceLevel()
  722. {
  723. for (var i = FURNACE_LEVELS.length - 1; i >= 0; i--)
  724. {
  725. if (getGameValue(getBoundKey(FURNACE_LEVELS[i] + 'Furnace')) > 0)
  726. {
  727. return i;
  728. }
  729. }
  730. return -1;
  731. }
  732.  
  733. function getFurnaceLevelName()
  734. {
  735. return FURNACE_LEVELS[getFurnaceLevel()] || '';
  736. }
  737.  
  738. function getPrice(item)
  739. {
  740. var price = win.getPrice(item);
  741. if (typeof price === 'number')
  742. {
  743. return price;
  744. }
  745. var match = price.match(/(\d+)([kM])/);
  746. if (!match)
  747. {
  748. return parseInt(price, 10);
  749. }
  750. var FACTORS = {
  751. 'k': 1e3
  752. , 'M': 1e6
  753. };
  754. return parseInt(match[1], 10) * (FACTORS[match[2]] || 1);
  755. }
  756.  
  757. function doGet(url)
  758. {
  759. return new Promise(function (resolve, reject)
  760. {
  761. var request = new XMLHttpRequest();
  762. request.onreadystatechange = function (event)
  763. {
  764. if (request.readyState != XMLHttpRequest.DONE)
  765. {
  766. return;
  767. }
  768. if (request.status != 200)
  769. {
  770. return reject(event);
  771. }
  772. resolve(request.responseText);
  773. };
  774. request.open('GET', url);
  775. request.send();
  776. });
  777. }
  778.  
  779. function removeWhitespaceChildNodes(el)
  780. {
  781. for (var i = 0; i < el.childNodes.length; i++)
  782. {
  783. var child = el.childNodes.item(i);
  784. if (child.nodeType === Node.TEXT_NODE && /^\s*$/.test(child.textContent || ''))
  785. {
  786. el.removeChild(child);
  787. i--;
  788. }
  789. }
  790. }
  791.  
  792. function debounce(func, wait, immediate)
  793. {
  794. var timeout;
  795. return function ()
  796. {
  797. var _this = this;
  798. var args = [];
  799. for (var _i = 0; _i < arguments.length; _i++)
  800. {
  801. args[_i] = arguments[_i];
  802. }
  803. var callNow = immediate && !timeout;
  804. timeout && clearTimeout(timeout);
  805. timeout = setTimeout(function ()
  806. {
  807. timeout = null;
  808. if (!immediate)
  809. {
  810. func.apply(_this, args);
  811. }
  812. }, wait);
  813. if (callNow)
  814. {
  815. func.apply(this, args);
  816. }
  817. };
  818. }
  819.  
  820. function passThis(fn)
  821. {
  822. return function ()
  823. {
  824. var args = [];
  825. for (var _i = 0; _i < arguments.length; _i++)
  826. {
  827. args[_i] = arguments[_i];
  828. }
  829. return fn.apply(void 0, [this].concat(args));
  830. };
  831. }
  832. /**
  833. * persistence store
  834. */
  835. var store;
  836. (function (store)
  837. {
  838. var oldPrefix = 'dh2-';
  839. var storePrefix = 'dh2.';
  840.  
  841. function update(key, keepOldValue)
  842. {
  843. if (keepOldValue === void 0)
  844. {
  845. keepOldValue = true;
  846. }
  847. if (localStorage.hasOwnProperty(oldPrefix + key))
  848. {
  849. if (keepOldValue)
  850. {
  851. localStorage.setItem(storePrefix + key, localStorage.getItem(oldPrefix + key));
  852. }
  853. localStorage.removeItem(oldPrefix + key);
  854. }
  855. }
  856. var changeListener = new Map();
  857.  
  858. function changeDetected(key, oldValue, newValue)
  859. {
  860. if (changeListener.has(key))
  861. {
  862. setTimeout(function ()
  863. {
  864. changeListener.get(key).forEach(function (fn)
  865. {
  866. return fn(key, oldValue, newValue);
  867. });
  868. });
  869. }
  870. }
  871.  
  872. function watchFn(fnName)
  873. {
  874. var _fn = localStorage[fnName];
  875. localStorage[fnName] = function (key)
  876. {
  877. var args = [];
  878. for (var _i = 1; _i < arguments.length; _i++)
  879. {
  880. args[_i - 1] = arguments[_i];
  881. }
  882. var oldValue = localStorage.getItem(key);
  883. _fn.apply(localStorage, [key].concat(args));
  884. var newValue = localStorage.getItem(key);
  885. if (oldValue !== newValue)
  886. {
  887. changeDetected(key, oldValue, newValue);
  888. }
  889. };
  890. }
  891. watchFn('setItem');
  892. watchFn('removeItem');
  893. var _clear = localStorage.clear;
  894. localStorage.clear = function ()
  895. {
  896. var oldValues = new Map();
  897. for (var i = 0; i < localStorage.length; i++)
  898. {
  899. var key = localStorage.key(i);
  900. oldValues.set(key, localStorage.getItem(key));
  901. }
  902. _clear();
  903. for (var key in oldValues)
  904. {
  905. var newValue = localStorage.getItem(key);
  906. if (oldValues.get(key) !== newValue)
  907. {
  908. changeDetected(key, oldValues.get(key), newValue);
  909. }
  910. }
  911. };
  912.  
  913. function addChangeListener(key, fn)
  914. {
  915. if (!changeListener.has(key))
  916. {
  917. changeListener.set(key, new Set());
  918. }
  919. changeListener.get(key).add(fn);
  920. }
  921. store.addChangeListener = addChangeListener;
  922.  
  923. function removeChangeListener(key, fn)
  924. {
  925. if (changeListener.has(key))
  926. {
  927. changeListener.get(key).delete(fn);
  928. }
  929. }
  930. store.removeChangeListener = removeChangeListener;
  931.  
  932. function get(key)
  933. {
  934. update(key);
  935. var value = localStorage.getItem(storePrefix + key);
  936. if (value != null)
  937. {
  938. try
  939. {
  940. return JSON.parse(value);
  941. }
  942. catch (e)
  943. {}
  944. }
  945. return value;
  946. }
  947. store.get = get;
  948.  
  949. function has(key)
  950. {
  951. update(key);
  952. return localStorage.hasOwnProperty(storePrefix + key);
  953. }
  954. store.has = has;
  955.  
  956. function remove(key)
  957. {
  958. update(key, false);
  959. localStorage.removeItem(storePrefix + key);
  960. }
  961. store.remove = remove;
  962.  
  963. function set(key, value)
  964. {
  965. update(key, false);
  966. localStorage.setItem(storePrefix + key, JSON.stringify(value));
  967. }
  968. store.set = set;
  969. })(store || (store = {}));
  970.  
  971. var settings;
  972. (function (settings)
  973. {
  974. settings.name = 'settings';
  975. var DIALOG_WIDTH = 450;
  976. var KEY;
  977. (function (KEY)
  978. {
  979. KEY[KEY["hideCraftingRecipes"] = 0] = "hideCraftingRecipes";
  980. KEY[KEY["hideUselessItems"] = 1] = "hideUselessItems";
  981. KEY[KEY["useNewChat"] = 2] = "useNewChat";
  982. KEY[KEY["colorizeChat"] = 3] = "colorizeChat";
  983. KEY[KEY["intelligentScrolling"] = 4] = "intelligentScrolling";
  984. KEY[KEY["showTimestamps"] = 5] = "showTimestamps";
  985. KEY[KEY["showIcons"] = 6] = "showIcons";
  986. KEY[KEY["showTags"] = 7] = "showTags";
  987. KEY[KEY["enableSpamDetection"] = 8] = "enableSpamDetection";
  988. KEY[KEY["useTombNotif"] = 9] = "useTombNotif";
  989. KEY[KEY["useWorkerNotif"] = 10] = "useWorkerNotif";
  990. KEY[KEY["useBobsUncleNotif"] = 11] = "useBobsUncleNotif";
  991. KEY[KEY["showNotifications"] = 12] = "showNotifications";
  992. KEY[KEY["wikiaLinks"] = 13] = "wikiaLinks";
  993. KEY[KEY["newXpAnimation"] = 14] = "newXpAnimation";
  994. KEY[KEY["amountSymbol"] = 15] = "amountSymbol";
  995. KEY[KEY["showTabTimer"] = 16] = "showTabTimer";
  996. KEY[KEY["showLootTab"] = 17] = "showLootTab";
  997. KEY[KEY["useEfficiencyStyle"] = 18] = "useEfficiencyStyle";
  998. KEY[KEY["makeNumberInputs"] = 19] = "makeNumberInputs";
  999. KEY[KEY["addKeepInput"] = 20] = "addKeepInput";
  1000. KEY[KEY["addMaxBtn"] = 21] = "addMaxBtn";
  1001. KEY[KEY["highlightUnplantableSeed"] = 22] = "highlightUnplantableSeed";
  1002. KEY[KEY["showSdChange"] = 23] = "showSdChange";
  1003. KEY[KEY["usePotionWarning"] = 24] = "usePotionWarning";
  1004. KEY[KEY["showCaptions"] = 25] = "showCaptions";
  1005. KEY[KEY["syncPriceHistory"] = 26] = "syncPriceHistory";
  1006. KEY[KEY["useNewToolbar"] = 27] = "useNewToolbar";
  1007. KEY[KEY["changeMachineDialog"] = 28] = "changeMachineDialog";
  1008. KEY[KEY["skillBars"] = 29] = "skillBars";
  1009. })(KEY = settings.KEY || (settings.KEY = {}));;
  1010. var CFG = (_a = {}
  1011. , _a[KEY.hideCraftingRecipes] = {
  1012. name: 'Hide crafting recipes of finished items'
  1013. , 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>"
  1014. , defaultValue: true
  1015. }
  1016. , _a[KEY.hideUselessItems] = {
  1017. name: 'Hide useless items'
  1018. , 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>"
  1019. , defaultValue: false
  1020. }
  1021. , _a[KEY.useNewChat] = {
  1022. name: 'Use the new chat'
  1023. , 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"
  1024. , defaultValue: true
  1025. }
  1026. , _a[KEY.colorizeChat] = {
  1027. name: 'Colorize chat messages'
  1028. , description: "Colorize chat messages according to a unique color for each user"
  1029. , defaultValue: false
  1030. , sub:
  1031. {
  1032. 'colorizer':
  1033. {
  1034. defaultValue: 0
  1035. , label: ['Equally Distributed', 'Random (light colors)', 'Random (dark colors)']
  1036. , options: ['equallyDistributed', 'random1', 'random2']
  1037. }
  1038. }
  1039. }
  1040. , _a[KEY.intelligentScrolling] = {
  1041. name: 'Intelligent scrolling'
  1042. , 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."
  1043. , defaultValue: true
  1044. }
  1045. , _a[KEY.showTimestamps] = {
  1046. name: 'Show timestamps'
  1047. , description: "Enables showing timestamps in chat"
  1048. , defaultValue: true
  1049. }
  1050. , _a[KEY.showIcons] = {
  1051. name: 'Show user-icons'
  1052. , description: "Enables showing icons (formerly sigils) for each user in chat"
  1053. , defaultValue: true
  1054. }
  1055. , _a[KEY.showTags] = {
  1056. name: 'Show user-tags'
  1057. , description: "Enables showing tags (Dev, Mod, Contributor) and colors for messages in chat"
  1058. , defaultValue: true
  1059. }
  1060. , _a[KEY.enableSpamDetection] = {
  1061. name: 'Enable spam detection'
  1062. , description: "Enables simple spam detection"
  1063. , defaultValue: true
  1064. }
  1065. , _a[KEY.useTombNotif] = {
  1066. name: 'Use Tomb notification'
  1067. , description: "Shows notification when Faradox's tomb is ready to fight"
  1068. , defaultValue: false
  1069. }
  1070. , _a[KEY.useWorkerNotif] = {
  1071. name: 'Use Worker notification'
  1072. , description: "Shows notification when workers come back"
  1073. , defaultValue: true
  1074. }
  1075. , _a[KEY.useBobsUncleNotif] = {
  1076. name: 'Use Bobs uncle notification'
  1077. , description: "Shows notification when Bob's uncle farm is ready to harvest"
  1078. , defaultValue: true
  1079. }
  1080. , _a[KEY.showNotifications] = {
  1081. name: 'Show browser notifications'
  1082. , description: "Shows browser notifications for enabled events (click the little gear for more options)"
  1083. , defaultValue: true
  1084. , sub:
  1085. {
  1086. 'showType':
  1087. {
  1088. defaultValue: 0
  1089. , label: ['only when window inactive', 'always']
  1090. , options: ['whenInactive', 'always']
  1091. }
  1092. , 'smelting':
  1093. {
  1094. defaultValue: true
  1095. , label: 'Smelting finishes'
  1096. }
  1097. , 'chopping':
  1098. {
  1099. defaultValue: true
  1100. , label: 'A tree is fully grown'
  1101. }
  1102. , 'harvest':
  1103. {
  1104. defaultValue: true
  1105. , label: 'A plant can be harvested'
  1106. }
  1107. , 'potionEffect':
  1108. {
  1109. defaultValue: true
  1110. , label: 'A potion\'s effect ends'
  1111. }
  1112. , 'boatReturned':
  1113. {
  1114. defaultValue: true
  1115. , label: 'A boat returns'
  1116. }
  1117. , 'heroReady':
  1118. {
  1119. defaultValue: true
  1120. , label: 'The hero is fully recovered and ready to fight'
  1121. }
  1122. , 'itemsSold':
  1123. {
  1124. defaultValue: true
  1125. , label: 'Items are sold on the market'
  1126. }
  1127. , 'pirate':
  1128. {
  1129. defaultValue: true
  1130. , label: 'A pirate has found a treasure map'
  1131. }
  1132. , 'rocket':
  1133. {
  1134. defaultValue: true
  1135. , label: 'The rocket has landed on the moon or earth'
  1136. }
  1137. , 'wind':
  1138. {
  1139. defaultValue: true
  1140. , label: 'The wind for the sail boat has changed'
  1141. }
  1142. , 'perk':
  1143. {
  1144. defaultValue: true
  1145. , label: 'A new perk is unlocked (achievement set completed)'
  1146. }
  1147. , 'pm':
  1148. {
  1149. defaultValue: true
  1150. , label: 'A private messages (pm) arrives'
  1151. }
  1152. , 'mention':
  1153. {
  1154. defaultValue: true
  1155. , label: 'The username is mentioned in chat'
  1156. }
  1157. , 'keyword':
  1158. {
  1159. defaultValue: true
  1160. , label: 'A keyword is mentioned in chat'
  1161. }
  1162. , 'serverMsg':
  1163. {
  1164. defaultValue: true
  1165. , label: 'Server messages (like <em>Server is restarting...</em>)'
  1166. }
  1167. }
  1168. }
  1169. , _a[KEY.wikiaLinks] = {
  1170. name: 'Show wikia links'
  1171. , description: "Show wikia links for every item on hover (the little icon in the upper left corner)"
  1172. , defaultValue: true
  1173. }
  1174. , _a[KEY.newXpAnimation] = {
  1175. name: 'New XP-gain animation'
  1176. , description: "Show gained xp on top skill bar instead on the position of the mouse"
  1177. , defaultValue: true
  1178. }
  1179. , _a[KEY.amountSymbol] = {
  1180. name: 'Show \u00D7 on items'
  1181. , description: "Show a tiny \u00D7-symbol before amount numbers of items"
  1182. , defaultValue: true
  1183. }
  1184. , _a[KEY.showTabTimer] = {
  1185. name: 'Show tab timer and info'
  1186. , description: "Show timer on tabs for trees, plants and hero"
  1187. , defaultValue: true
  1188. }
  1189. , _a[KEY.showLootTab] = {
  1190. name: 'Show sub tab for loot table'
  1191. , description: "Show a sub tab for combat drop table in combat"
  1192. , defaultValue: true
  1193. }
  1194. , _a[KEY.useEfficiencyStyle] = {
  1195. name: 'Use space efficient style'
  1196. , description: "Use a space efficient style with less blank space"
  1197. , defaultValue: false
  1198. }
  1199. , _a[KEY.makeNumberInputs] = {
  1200. name: 'Turn text inputs into number inputs'
  1201. , description: "Number inputs allow you to change the amount via arrow buttons"
  1202. , defaultValue: true
  1203. }
  1204. , _a[KEY.addKeepInput] = {
  1205. name: 'Add keep input for selling to npc shop'
  1206. , description: "A keep input allows you to set the amount of items you want to keep when selling"
  1207. , defaultValue: true
  1208. }
  1209. , _a[KEY.addMaxBtn] = {
  1210. name: 'Add max button for some crafting inputs'
  1211. , description: "Add max button for crafting (e.g. vials), brewing potions and cooking food"
  1212. , defaultValue: true
  1213. }
  1214. , _a[KEY.highlightUnplantableSeed] = {
  1215. name: 'Show whether a seed can be planted'
  1216. , description: "Fades the item box of a seed when it's not plantable"
  1217. , defaultValue: true
  1218. }
  1219. , _a[KEY.showSdChange] = {
  1220. name: 'Show stardust change'
  1221. , description: "Shows the amount of stardust earned or spent in the last tick"
  1222. , defaultValue: true
  1223. }
  1224. , _a[KEY.usePotionWarning] = {
  1225. name: 'Use drink warning for active potions'
  1226. , description: "Disable drink button for 3 seconds if the potion is already active"
  1227. , defaultValue: true
  1228. }
  1229. , _a[KEY.showCaptions] = {
  1230. name: 'Show item captions'
  1231. , description: "Show item captions for some items instead of the number of owned items"
  1232. , defaultValue: true
  1233. }
  1234. , _a[KEY.syncPriceHistory] = {
  1235. name: 'Sync price history'
  1236. , description: "Synchronize the local price history"
  1237. , defaultValue: false
  1238. , sub:
  1239. {
  1240. 'url':
  1241. {
  1242. defaultValue: ''
  1243. , label: 'paste url here'
  1244. }
  1245. }
  1246. }
  1247. , _a[KEY.useNewToolbar] = {
  1248. name: 'Use new toolbar'
  1249. , description: "Use new reordered toolbar"
  1250. , defaultValue: true
  1251. , requiresReload: true
  1252. }
  1253. , _a[KEY.changeMachineDialog] = {
  1254. name: 'Use slider for machine dialog'
  1255. , description: "Change buttons in machine dialog into slider"
  1256. , defaultValue: true
  1257. , requiresReload: true
  1258. }
  1259. , _a[KEY.skillBars] = {
  1260. name: 'Show XP bars'
  1261. , description: "Show the XP bars under skills on top"
  1262. , defaultValue: true
  1263. , requiresReload: true
  1264. }
  1265. , _a);
  1266. var SETTINGS_TABLE_ID = 'dh2-settings';
  1267. var SETTING_ID_PREFIX = 'dh2-setting-';
  1268. var settings2Init = Object.keys(CFG);
  1269. /**
  1270. * settings
  1271. */
  1272. function toName(key, subKey)
  1273. {
  1274. var name = typeof key === 'string' ? key : KEY[key];
  1275. if (subKey !== undefined)
  1276. {
  1277. return name + '.' + subKey;
  1278. }
  1279. return name;
  1280. }
  1281.  
  1282. function getStoreKey(key, subKey)
  1283. {
  1284. return 'setting.' + toName(key, subKey);
  1285. }
  1286. var observedSettings = new Map();
  1287. var observedSubSettings = new Map();
  1288.  
  1289. function observe(key, fn)
  1290. {
  1291. var n = toName(key);
  1292. if (!observedSettings.has(n))
  1293. {
  1294. observedSettings.set(n, new Set());
  1295. }
  1296. observedSettings.get(n).add(fn);
  1297. }
  1298. settings.observe = observe;
  1299.  
  1300. function observeSub(key, subKey, fn)
  1301. {
  1302. var n = toName(key, subKey);
  1303. if (!observedSubSettings.has(n))
  1304. {
  1305. observedSubSettings.set(n, new Set());
  1306. }
  1307. observedSubSettings.get(n).add(fn);
  1308. }
  1309. settings.observeSub = observeSub;
  1310.  
  1311. function unobserve(key, fn)
  1312. {
  1313. var n = toName(key);
  1314. if (!observedSettings.has(n))
  1315. {
  1316. return false;
  1317. }
  1318. return observedSettings.get(n).delete(fn);
  1319. }
  1320. settings.unobserve = unobserve;
  1321.  
  1322. function unobserveSub(key, subKey, fn)
  1323. {
  1324. var n = toName(key, subKey);
  1325. if (!observedSubSettings.has(n))
  1326. {
  1327. return false;
  1328. }
  1329. return observedSubSettings.get(n).delete(fn);
  1330. }
  1331. settings.unobserveSub = unobserveSub;
  1332. var settingsProxies = new Map();
  1333.  
  1334. function get(key)
  1335. {
  1336. if (!CFG.hasOwnProperty(key))
  1337. {
  1338. return false;
  1339. }
  1340. if (settingsProxies.has(key))
  1341. {
  1342. var proxy = settingsProxies.get(key);
  1343. return proxy.get(key);
  1344. }
  1345. var name = getStoreKey(key);
  1346. return store.has(name) ? store.get(name) : CFG[key].defaultValue;
  1347. }
  1348. settings.get = get;
  1349.  
  1350. function getSub(key, subKey)
  1351. {
  1352. if (!CFG.hasOwnProperty(key))
  1353. {
  1354. return null;
  1355. }
  1356. var name = getStoreKey(key, subKey);
  1357. var def = CFG[key].sub[subKey].defaultValue;
  1358. if (store.has(name))
  1359. {
  1360. var stored = store.get(name);
  1361. if (def instanceof Array)
  1362. {
  1363. for (var i = 0; i < def.length; i++)
  1364. {
  1365. if (stored.indexOf(def[i]) === -1)
  1366. {
  1367. stored.push(def[i]);
  1368. }
  1369. }
  1370. for (var i = 0; i < stored.length; i++)
  1371. {
  1372. if (def.indexOf(stored[i]) === -1)
  1373. {
  1374. stored.splice(i, 1);
  1375. i--;
  1376. }
  1377. }
  1378. }
  1379. return stored;
  1380. }
  1381. else
  1382. {
  1383. return def;
  1384. }
  1385. }
  1386. settings.getSub = getSub;
  1387.  
  1388. function set(key, newValue)
  1389. {
  1390. if (!CFG.hasOwnProperty(key))
  1391. {
  1392. return;
  1393. }
  1394. var oldValue = get(key);
  1395. var n = toName(key);
  1396. if (settingsProxies.has(key))
  1397. {
  1398. var proxy = settingsProxies.get(key);
  1399. proxy.set(key, oldValue, newValue);
  1400. }
  1401. else
  1402. {
  1403. store.set(getStoreKey(key), newValue);
  1404. }
  1405. if (oldValue !== newValue && observedSettings.has(n))
  1406. {
  1407. observedSettings.get(n).forEach(function (fn)
  1408. {
  1409. return fn(key, oldValue, newValue);
  1410. });
  1411. }
  1412. }
  1413. settings.set = set;
  1414.  
  1415. function setSub(key, subKey, newValue)
  1416. {
  1417. if (!CFG.hasOwnProperty(key))
  1418. {
  1419. return;
  1420. }
  1421. var oldValue = getSub(key, subKey);
  1422. var n = toName(key, subKey);
  1423. store.set(getStoreKey(key, subKey), newValue);
  1424. if (oldValue !== newValue && observedSubSettings.has(n))
  1425. {
  1426. observedSubSettings.get(n).forEach(function (fn)
  1427. {
  1428. return fn(key, subKey, oldValue, newValue);
  1429. });
  1430. }
  1431. }
  1432. settings.setSub = setSub;
  1433.  
  1434. function getSubCfg(key)
  1435. {
  1436. if (!CFG.hasOwnProperty(key))
  1437. {
  1438. return;
  1439. }
  1440. return CFG[key].sub;
  1441. }
  1442. settings.getSubCfg = getSubCfg;
  1443.  
  1444. function initSettingsStyle()
  1445. {
  1446. 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");
  1447. }
  1448.  
  1449. function getSettingId(key, subKey)
  1450. {
  1451. var name = toName(key) + (subKey !== undefined ? '-' + subKey : '');
  1452. return SETTING_ID_PREFIX + split2Words(name, '-').toLowerCase();
  1453. }
  1454.  
  1455. function initSettingTable()
  1456. {
  1457. function insertAfter(newChild, oldChild)
  1458. {
  1459. var parent = oldChild.parentElement;
  1460. if (oldChild.nextElementSibling == null)
  1461. {
  1462. parent.appendChild(newChild);
  1463. }
  1464. else
  1465. {
  1466. parent.insertBefore(newChild, oldChild.nextElementSibling);
  1467. }
  1468. }
  1469.  
  1470. function getCheckImageSrc(value)
  1471. {
  1472. return 'images/icons/' + (value ? 'check' : 'x') + '.png';
  1473. }
  1474. var profileTable = document.getElementById('profile-toggleTable');
  1475. if (!profileTable)
  1476. {
  1477. return;
  1478. }
  1479. var settingsHeader = document.createElement('h2');
  1480. settingsHeader.className = 'section-title';
  1481. 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>";
  1482. var requiresReloadNote = settingsHeader.querySelector('.note');
  1483. insertAfter(settingsHeader, profileTable);
  1484. var settingsTable = document.createElement('table');
  1485. settingsTable.id = SETTINGS_TABLE_ID;
  1486. settingsTable.className = 'table-style1';
  1487. settingsTable.width = '40%';
  1488. 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";
  1489.  
  1490. function addRowClickListener(row, key, settingId)
  1491. {
  1492. row.addEventListener('click', function ()
  1493. {
  1494. var newValue = !get(key);
  1495. set(key, newValue);
  1496. document.getElementById(settingId).src = getCheckImageSrc(newValue);
  1497. });
  1498. }
  1499.  
  1500. function addSubClickListener(btn, dialog)
  1501. {
  1502. btn.addEventListener('click', function (event)
  1503. {
  1504. initJQueryDialog(dialog);
  1505. event.stopPropagation();
  1506. event.preventDefault();
  1507. });
  1508. }
  1509. for (var _i = 0, settings2Init_1 = settings2Init; _i < settings2Init_1.length; _i++)
  1510. {
  1511. var k = settings2Init_1[_i];
  1512. // convert it into a KEY
  1513. var key = parseInt(k, 10);
  1514. var setting = CFG[key];
  1515. if (setting == null)
  1516. {
  1517. console.error('missing setting entry:', key, toName(key));
  1518. continue;
  1519. }
  1520. var settingId = getSettingId(key);
  1521. var row = settingsTable.insertRow(-1);
  1522. row.classList.add('setting');
  1523. if (setting.requiresReload)
  1524. {
  1525. row.classList.add('reload');
  1526. requiresReloadNote.style.display = '';
  1527. }
  1528. row.setAttribute('onclick', '');
  1529. 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";
  1530. if (setting.sub)
  1531. {
  1532. row.classList.add('sub');
  1533. var subBtn = document.createElement('button');
  1534. subBtn.innerHTML = "<img src=\"images/icons/gearOff.gif\" class=\"image-icon-15\">";
  1535. row.cells.item(0).appendChild(subBtn);
  1536. var dialog = createSubSettingDialog(key);
  1537. addSubClickListener(subBtn, dialog);
  1538. }
  1539. var tooltipEl = ensureTooltip(settingId, row);
  1540. tooltipEl.innerHTML = setting.description;
  1541. if (setting.requiresReload)
  1542. {
  1543. 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>";
  1544. }
  1545. addRowClickListener(row, key, settingId);
  1546. }
  1547. insertAfter(settingsTable, settingsHeader);
  1548. }
  1549.  
  1550. function initProxies()
  1551. {
  1552. var row = document.querySelector('tr[data-tooltip-id="tooltip-profile-removeCraftingFilter"]');
  1553. if (row)
  1554. {
  1555. var valueCache_1 = getGameValue('profileRemoveCraftingFilter') != 1;
  1556. settingsProxies.set(KEY.hideCraftingRecipes
  1557. , {
  1558. get: function (key)
  1559. {
  1560. return getGameValue('profileRemoveCraftingFilter') != 1;
  1561. }
  1562. , set: function (key, oldValue, newValue)
  1563. {
  1564. if (valueCache_1 != newValue)
  1565. {
  1566. row.click();
  1567. valueCache_1 = newValue;
  1568. }
  1569. }
  1570. });
  1571. observer.add('profileRemoveCraftingFilter', function ()
  1572. {
  1573. set(KEY.hideCraftingRecipes, getGameValue('profileRemoveCraftingFilter') != 1);
  1574. });
  1575. }
  1576. }
  1577. var subDialog;
  1578. (function (subDialog)
  1579. {
  1580. function defaultHandler(key, dialog)
  1581. {
  1582. var setting = CFG[key];
  1583. var subSettings = setting.sub;
  1584. var settingContainer = createSubSettingsContainer(key, subSettings);
  1585. dialog.appendChild(settingContainer);
  1586. }
  1587.  
  1588. function colorizeChat(dialog)
  1589. {
  1590. defaultHandler(KEY.colorizeChat, dialog);
  1591. }
  1592. subDialog.colorizeChat = colorizeChat;
  1593.  
  1594. function showNotifications(dialog)
  1595. {
  1596. dialog.appendChild(document.createTextNode('Show notifications\u2026'));
  1597. defaultHandler(KEY.showNotifications, dialog);
  1598. dialog.appendChild(document.createTextNode('Events for which notifications are shown:'));
  1599. var ulNotifType = dialog.lastElementChild;
  1600. var ulEvents = ulNotifType.cloneNode(false);
  1601. while (ulNotifType.children.length > 1)
  1602. {
  1603. ulEvents.appendChild(ulNotifType.children.item(1));
  1604. }
  1605. dialog.appendChild(ulEvents);
  1606. }
  1607. subDialog.showNotifications = showNotifications;
  1608.  
  1609. function syncPriceHistory(dialog)
  1610. {
  1611. var setting = CFG[KEY.syncPriceHistory];
  1612. var subSettings = setting.sub;
  1613. var instructionEl = document.createElement('div');
  1614. instructionEl.className = 'instruction';
  1615. 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:";
  1616. dialog.appendChild(instructionEl);
  1617. var settingContainer = createSubSettingsContainer(KEY.syncPriceHistory, subSettings);
  1618. dialog.appendChild(settingContainer);
  1619. }
  1620. subDialog.syncPriceHistory = syncPriceHistory;
  1621. })(subDialog || (subDialog = {}));
  1622.  
  1623. function createSubSettingDialog(key)
  1624. {
  1625. var settingId = getSettingId(key);
  1626. var setting = CFG[key];
  1627. var dialog = document.createElement('div');
  1628. dialog.id = 'dialog-' + settingId;
  1629. dialog.style.display = 'none';
  1630. dialog.innerHTML = "<h2>" + setting.name + "</h2>";
  1631. var name = toName(key);
  1632. if (subDialog.hasOwnProperty(name))
  1633. {
  1634. subDialog[name](dialog);
  1635. }
  1636. else
  1637. {
  1638. console.warn('missing setting handler for "%s"', name);
  1639. var todoEl = document.createElement('span');
  1640. todoEl.textContent = 'TODO';
  1641. dialog.appendChild(todoEl);
  1642. }
  1643. document.body.appendChild(dialog);
  1644. return dialog;
  1645. }
  1646.  
  1647. function createSubSettingsContainer(parentKey, subSettings)
  1648. {
  1649. var settingsContainer = document.createElement('ul');
  1650. settingsContainer.className = 'settings-container';
  1651.  
  1652. function addCheckbox(listEl, subKey, id, setting)
  1653. {
  1654. var checkbox = document.createElement('input');
  1655. checkbox.type = 'checkbox';
  1656. checkbox.id = id;
  1657. checkbox.name = id;
  1658. checkbox.checked = getSub(parentKey, subKey);
  1659. var label = document.createElement('label');
  1660. label.htmlFor = id;
  1661. label.innerHTML = setting.label;
  1662. checkbox.addEventListener('change', function ()
  1663. {
  1664. return setSub(parentKey, subKey, checkbox.checked);
  1665. });
  1666. listEl.appendChild(checkbox);
  1667. listEl.appendChild(label);
  1668. }
  1669.  
  1670. function addSelectmenu(listEl, subKey, id, setting)
  1671. {
  1672. var select = document.createElement('select');
  1673. select.id = id;
  1674. select.name = id;
  1675. var options = setting.options;
  1676. var selectedIndex = getSub(parentKey, subKey);
  1677. for (var i = 0; i < options.length; i++)
  1678. {
  1679. var option = document.createElement('option');
  1680. option.value = options[i];
  1681. if (setting.label)
  1682. {
  1683. option.innerHTML = setting.label[i];
  1684. }
  1685. else
  1686. {
  1687. option.innerHTML = key2Name(options[i]);
  1688. }
  1689. option.selected = i == selectedIndex;
  1690. select.appendChild(option);
  1691. }
  1692. select.addEventListener('change', function ()
  1693. {
  1694. return setSub(parentKey, subKey, select.selectedIndex);
  1695. });
  1696. listEl.appendChild(select);
  1697. }
  1698.  
  1699. function addInput(listEl, subKey, id, setting)
  1700. {
  1701. var input = document.createElement('input');
  1702. input.type = 'text';
  1703. input.placeholder = setting.label || '';
  1704. input.value = getSub(parentKey, subKey);
  1705. var onChange = function ()
  1706. {
  1707. return setSub(parentKey, subKey, input.value);
  1708. };
  1709. input.addEventListener('click', onChange);
  1710. input.addEventListener('change', onChange);
  1711. input.addEventListener('keyup', onChange);
  1712. listEl.appendChild(input);
  1713. }
  1714. var keyList = Object.keys(subSettings);
  1715. var orderIndex = keyList.findIndex(function (k)
  1716. {
  1717. return subSettings[k].defaultValue instanceof Array;
  1718. });
  1719. var isSortable = orderIndex != -1;
  1720. if (isSortable)
  1721. {
  1722. keyList = getSub(parentKey, keyList[orderIndex]);
  1723. }
  1724. for (var _i = 0, keyList_1 = keyList; _i < keyList_1.length; _i++)
  1725. {
  1726. var subKey = keyList_1[_i];
  1727. var settingId = getSettingId(parentKey, subKey);
  1728. var setting = subSettings[subKey];
  1729. var listEl = document.createElement('li');
  1730. listEl.classList.add('setting');
  1731. if (isSortable)
  1732. {
  1733. listEl.dataset.subKey = subKey;
  1734. var sortableIcon = document.createElement('span');
  1735. sortableIcon.className = 'ui-icon ui-icon-arrowthick-2-n-s handle';
  1736. listEl.appendChild(sortableIcon);
  1737. }
  1738. if (setting.options)
  1739. {
  1740. addSelectmenu(listEl, subKey, settingId, setting);
  1741. }
  1742. else if (typeof setting.defaultValue === 'boolean')
  1743. {
  1744. addCheckbox(listEl, subKey, settingId, setting);
  1745. }
  1746. else if (typeof setting.defaultValue === 'string')
  1747. {
  1748. addInput(listEl, subKey, settingId, setting);
  1749. }
  1750. settingsContainer.appendChild(listEl);
  1751. }
  1752. return settingsContainer;
  1753. }
  1754.  
  1755. function initJQueryDialog(dialog)
  1756. {
  1757. var $dialog = win.$(dialog);
  1758. $dialog.dialog(
  1759. {
  1760. width: DIALOG_WIDTH + 'px'
  1761. });
  1762. $dialog.find('input[type="checkbox"]').checkboxradio()
  1763. .next().children(':first-child').removeClass('ui-state-hover');
  1764. $dialog.find('button:not(.sub)').button();
  1765. $dialog.find('input:text').button()
  1766. .addClass('ui-textfield')
  1767. .off('mouseenter').off('mousedown').off('keydown');
  1768. $dialog.find('select').selectmenu(
  1769. {
  1770. change: function (event, ui)
  1771. {
  1772. var changeEvent = document.createEvent('HTMLEvents');
  1773. changeEvent.initEvent('change', false, true);
  1774. event.target.dispatchEvent(changeEvent);
  1775. }
  1776. });
  1777. $dialog.find('.sortable').sortable(
  1778. {
  1779. handle: '.handle'
  1780. , update: function (event, ui)
  1781. {
  1782. var newOrder = [];
  1783. var children = event.target.children;
  1784. for (var i = 0; i < children.length; i++)
  1785. {
  1786. var child = children[i];
  1787. newOrder.push(child.dataset.subKey);
  1788. }
  1789. var updateEvent = new CustomEvent('sortupdate'
  1790. , {
  1791. detail: newOrder
  1792. });
  1793. event.target.dispatchEvent(updateEvent);
  1794. }
  1795. });
  1796. return $dialog;
  1797. }
  1798.  
  1799. function createSettingsContainer(settingList)
  1800. {
  1801. var settingsContainer = document.createElement('ul');
  1802. settingsContainer.className = 'settings-container';
  1803.  
  1804. function addOpenDialogClickListener(el, dialog)
  1805. {
  1806. el.addEventListener('click', function (event)
  1807. {
  1808. initJQueryDialog(dialog);
  1809. event.stopPropagation();
  1810. event.preventDefault();
  1811. });
  1812. }
  1813.  
  1814. function addChangeListener(key, checkbox)
  1815. {
  1816. checkbox.addEventListener('change', function ()
  1817. {
  1818. set(key, checkbox.checked);
  1819. });
  1820. }
  1821. for (var _i = 0, settingList_1 = settingList; _i < settingList_1.length; _i++)
  1822. {
  1823. var key = settingList_1[_i];
  1824. var settingId = getSettingId(key);
  1825. var setting = CFG[key];
  1826. var index = settings2Init.indexOf(key.toString());
  1827. if (index != -1)
  1828. {
  1829. settings2Init.splice(index, 1);
  1830. }
  1831. var listEl = document.createElement('li');
  1832. listEl.classList.add('setting');
  1833. if (setting.requiresReload)
  1834. {
  1835. listEl.classList.add('reload');
  1836. }
  1837. var checkbox = document.createElement('input');
  1838. checkbox.type = 'checkbox';
  1839. checkbox.id = settingId;
  1840. checkbox.checked = get(key);
  1841. var label = document.createElement('label');
  1842. label.htmlFor = settingId;
  1843. label.textContent = setting.name;
  1844. addChangeListener(key, checkbox);
  1845. listEl.appendChild(checkbox);
  1846. listEl.appendChild(label);
  1847. if (setting.sub)
  1848. {
  1849. var moreBtn = document.createElement('button');
  1850. moreBtn.className = 'sub';
  1851. moreBtn.innerHTML = "<img src=\"images/icons/gearOff.gif\" class=\"image-icon-20\" />";
  1852. listEl.appendChild(moreBtn);
  1853. var dialog = createSubSettingDialog(key);
  1854. addOpenDialogClickListener(moreBtn, dialog);
  1855. }
  1856. settingsContainer.appendChild(listEl);
  1857. var tooltipEl = ensureTooltip(settingId, listEl);
  1858. tooltipEl.innerHTML = setting.description;
  1859. if (setting.requiresReload)
  1860. {
  1861. 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>";
  1862. }
  1863. }
  1864. return settingsContainer;
  1865. }
  1866.  
  1867. function initCraftingSettings()
  1868. {
  1869. var craftingItems = document.getElementById('tab-sub-container-crafting');
  1870. if (!craftingItems)
  1871. {
  1872. return;
  1873. }
  1874. var br = craftingItems.nextElementSibling;
  1875. var after = br.nextElementSibling;
  1876. var parent = after.parentElement;
  1877. var settingList = [KEY.hideCraftingRecipes, KEY.hideUselessItems];
  1878. var settingsContainer = createSettingsContainer(settingList);
  1879. parent.insertBefore(settingsContainer, after);
  1880. }
  1881.  
  1882. function initMuteDialog(settingsContainer)
  1883. {
  1884. // muted people dialog
  1885. var dialog = document.createElement('div');
  1886. dialog.id = 'dialog-chat-muted-people';
  1887. dialog.style.display = 'none';
  1888. dialog.innerHTML = "<h2>Muted people</h2>";
  1889. var input = document.createElement('input');
  1890. input.type = 'text';
  1891. input.placeholder = 'username';
  1892. dialog.appendChild(input);
  1893. var addBtn = document.createElement('button');
  1894. addBtn.textContent = '+';
  1895. dialog.appendChild(addBtn);
  1896. var listEl = document.createElement('ul');
  1897. listEl.className = 'settings-container list';
  1898. var username2Item = {};
  1899. var username2Btn = {};
  1900.  
  1901. function removeListener(event)
  1902. {
  1903. var target = event.target;
  1904. var username = target.dataset.username || '';
  1905. var index = win.mutedPeople.indexOf(username);
  1906. if (index !== -1)
  1907. {
  1908. win.mutedPeople.splice(index, 1);
  1909. }
  1910. }
  1911.  
  1912. function add2List(username)
  1913. {
  1914. var item = document.createElement('li');
  1915. item.innerHTML = "<span class=\"content\">" + username + "</span>";
  1916. var removeBtn = document.createElement('button');
  1917. removeBtn.dataset.username = username;
  1918. removeBtn.textContent = '-';
  1919. win.$(removeBtn).button();
  1920. removeBtn.addEventListener('click', removeListener);
  1921. username2Btn[username] = removeBtn;
  1922. item.appendChild(removeBtn);
  1923. username2Item[username] = item;
  1924. listEl.appendChild(item);
  1925. }
  1926. var _push = win.mutedPeople.push;
  1927. win.mutedPeople.push = function ()
  1928. {
  1929. var items = [];
  1930. for (var _i = 0; _i < arguments.length; _i++)
  1931. {
  1932. items[_i] = arguments[_i];
  1933. }
  1934. items.forEach(function (username)
  1935. {
  1936. return add2List(username);
  1937. });
  1938. return _push.call.apply(_push, [win.mutedPeople].concat(items));
  1939. };
  1940. var _splice = win.mutedPeople.splice;
  1941. win.mutedPeople.splice = function (start, deleteCount)
  1942. {
  1943. var items = [];
  1944. for (var _i = 2; _i < arguments.length; _i++)
  1945. {
  1946. items[_i - 2] = arguments[_i];
  1947. }
  1948. for (var i = 0; i < deleteCount; i++)
  1949. {
  1950. var username = win.mutedPeople[start + i];
  1951. var item = username2Item[username];
  1952. delete username2Item[username];
  1953. listEl.removeChild(item);
  1954. var btn = username2Btn[username];
  1955. delete username2Btn[username];
  1956. btn.removeEventListener('click', removeListener);
  1957. }
  1958. items.forEach(function (username)
  1959. {
  1960. return add2List(username);
  1961. });
  1962. return _splice.call.apply(_splice, [win.mutedPeople, start, deleteCount].concat(items));
  1963. };
  1964. dialog.appendChild(listEl);
  1965. addBtn.addEventListener('click', function ()
  1966. {
  1967. win.mutedPeople.push(input.value);
  1968. input.value = '';
  1969. });
  1970. document.body.appendChild(dialog);
  1971. var listItem = document.createElement('li');
  1972. listItem.classList.add('setting');
  1973. var dialogBtn = document.createElement('button');
  1974. dialogBtn.innerHTML = "List of muted people";
  1975. dialogBtn.addEventListener('click', function ()
  1976. {
  1977. initJQueryDialog(dialog);
  1978. });
  1979. listItem.appendChild(dialogBtn);
  1980. settingsContainer.appendChild(listItem);
  1981. }
  1982.  
  1983. function initKeywordDialog(settingsContainer)
  1984. {
  1985. // keyword dialog
  1986. var dialog = document.createElement('div');
  1987. dialog.id = 'dialog-chat-keyword-list';
  1988. dialog.style.display = 'none';
  1989. dialog.innerHTML = "<h2>Keywords</h2>";
  1990. var input = document.createElement('input');
  1991. input.type = 'text';
  1992. input.placeholder = 'keyword';
  1993. dialog.appendChild(input);
  1994. var addBtn = document.createElement('button');
  1995. addBtn.textContent = '+';
  1996. dialog.appendChild(addBtn);
  1997. var listEl = document.createElement('ul');
  1998. listEl.className = 'settings-container list';
  1999.  
  2000. function add2List(keyword)
  2001. {
  2002. var item = document.createElement('li');
  2003. item.innerHTML = "<span class=\"content\">" + keyword + "</span>";
  2004. var removeBtn = document.createElement('button');
  2005. removeBtn.textContent = '-';
  2006. win.$(removeBtn).button();
  2007. var remove = function ()
  2008. {
  2009. if (chat.removeKeyword(keyword))
  2010. {
  2011. listEl.removeChild(item);
  2012. removeBtn.removeEventListener('click', remove);
  2013. }
  2014. };
  2015. removeBtn.addEventListener('click', remove);
  2016. item.appendChild(removeBtn);
  2017. listEl.appendChild(item);
  2018. }
  2019. // add all keywords
  2020. chat.keywordList.forEach(function (keyword)
  2021. {
  2022. return add2List(keyword);
  2023. });
  2024. dialog.appendChild(listEl);
  2025. addBtn.addEventListener('click', function ()
  2026. {
  2027. var keyword = input.value;
  2028. if (chat.addKeyword(keyword))
  2029. {
  2030. add2List(keyword);
  2031. input.value = '';
  2032. }
  2033. });
  2034. document.body.appendChild(dialog);
  2035. var listItem = document.createElement('li');
  2036. listItem.classList.add('setting');
  2037. var dialogBtn = document.createElement('button');
  2038. dialogBtn.innerHTML = "Manage list of keywords";
  2039. dialogBtn.addEventListener('click', function ()
  2040. {
  2041. initJQueryDialog(dialog);
  2042. });
  2043. listItem.appendChild(dialogBtn);
  2044. settingsContainer.appendChild(listItem);
  2045. }
  2046.  
  2047. function initChatSettings()
  2048. {
  2049. var controlDiv = document.querySelector('#div-chat > div:first-child');
  2050. if (!controlDiv)
  2051. {
  2052. return;
  2053. }
  2054. var btn = document.createElement('button');
  2055. btn.textContent = 'Chat Settings';
  2056. controlDiv.appendChild(btn);
  2057. var dialog = document.createElement('div');
  2058. dialog.id = 'dialog-chat-settings';
  2059. dialog.style.display = 'none';
  2060. dialog.innerHTML = "<h2>Chat Settings</h2>";
  2061. var settingList = [KEY.useNewChat, KEY.colorizeChat, KEY.intelligentScrolling, KEY.showTimestamps, KEY.showIcons, KEY.showTags, KEY.enableSpamDetection];
  2062. var settingsContainer = createSettingsContainer(settingList);
  2063. initMuteDialog(settingsContainer);
  2064. initKeywordDialog(settingsContainer);
  2065. dialog.appendChild(settingsContainer);
  2066. document.body.appendChild(dialog);
  2067. btn.addEventListener('click', function ()
  2068. {
  2069. initJQueryDialog(dialog);
  2070. });
  2071. }
  2072.  
  2073. function init()
  2074. {
  2075. initProxies();
  2076. initSettingsStyle();
  2077. initCraftingSettings();
  2078. initChatSettings();
  2079. initSettingTable();
  2080. }
  2081. settings.init = init;
  2082. var _a;
  2083. })(settings || (settings = {}));
  2084. /**
  2085. * Code from https://github.com/davidmerfield/randomColor
  2086. */
  2087. var colorGenerator;
  2088. (function (colorGenerator)
  2089. {
  2090. // seed to get repeatable colors
  2091. var seed = null;
  2092. var COLOR_NOT_FOUND = {
  2093. hueRange: []
  2094. , lowerBounds: []
  2095. , saturationRange: []
  2096. , brightnessRange: []
  2097. };
  2098. var COLOR_BOUNDS = {
  2099. 'monochrome':
  2100. {
  2101. hueRange: []
  2102. , lowerBounds: [
  2103. [0, 0]
  2104. , [100, 0]
  2105. ]
  2106. }
  2107. , 'red':
  2108. {
  2109. hueRange: [-26, 18]
  2110. , lowerBounds: [
  2111. [20, 100]
  2112. , [30, 92]
  2113. , [40, 89]
  2114. , [50, 85]
  2115. , [60, 78]
  2116. , [70, 70]
  2117. , [80, 60]
  2118. , [90, 55]
  2119. , [100, 50]
  2120. ]
  2121. }
  2122. , 'orange':
  2123. {
  2124. hueRange: [19, 46]
  2125. , lowerBounds: [
  2126. [20, 100]
  2127. , [30, 93]
  2128. , [40, 88]
  2129. , [50, 86]
  2130. , [60, 85]
  2131. , [70, 70]
  2132. , [100, 70]
  2133. ]
  2134. }
  2135. , 'yellow':
  2136. {
  2137. hueRange: [47, 62]
  2138. , lowerBounds: [
  2139. [25, 100]
  2140. , [40, 94]
  2141. , [50, 89]
  2142. , [60, 86]
  2143. , [70, 84]
  2144. , [80, 82]
  2145. , [90, 80]
  2146. , [100, 75]
  2147. ]
  2148. }
  2149. , 'green':
  2150. {
  2151. hueRange: [63, 178]
  2152. , lowerBounds: [
  2153. [30, 100]
  2154. , [40, 90]
  2155. , [50, 85]
  2156. , [60, 81]
  2157. , [70, 74]
  2158. , [80, 64]
  2159. , [90, 50]
  2160. , [100, 40]
  2161. ]
  2162. }
  2163. , 'blue':
  2164. {
  2165. hueRange: [179, 257]
  2166. , lowerBounds: [
  2167. [20, 100]
  2168. , [30, 86]
  2169. , [40, 80]
  2170. , [50, 74]
  2171. , [60, 60]
  2172. , [70, 52]
  2173. , [80, 44]
  2174. , [90, 39]
  2175. , [100, 35]
  2176. ]
  2177. }
  2178. , 'purple':
  2179. {
  2180. hueRange: [258, 282]
  2181. , lowerBounds: [
  2182. [20, 100]
  2183. , [30, 87]
  2184. , [40, 79]
  2185. , [50, 70]
  2186. , [60, 65]
  2187. , [70, 59]
  2188. , [80, 52]
  2189. , [90, 45]
  2190. , [100, 42]
  2191. ]
  2192. }
  2193. , 'pink':
  2194. {
  2195. hueRange: [283, 334]
  2196. , lowerBounds: [
  2197. [20, 100]
  2198. , [30, 90]
  2199. , [40, 86]
  2200. , [60, 84]
  2201. , [80, 80]
  2202. , [90, 75]
  2203. , [100, 73]
  2204. ]
  2205. }
  2206. };
  2207. // shared color dictionary
  2208. var colorDictionary = {};
  2209.  
  2210. function defineColor(name, hueRange, lowerBounds)
  2211. {
  2212. var _a = lowerBounds[0]
  2213. , sMin = _a[0]
  2214. , bMax = _a[1];
  2215. var _b = lowerBounds[lowerBounds.length - 1]
  2216. , sMax = _b[0]
  2217. , bMin = _b[1];
  2218. colorDictionary[name] = {
  2219. hueRange: hueRange
  2220. , lowerBounds: lowerBounds
  2221. , saturationRange: [sMin, sMax]
  2222. , brightnessRange: [bMin, bMax]
  2223. };
  2224. }
  2225.  
  2226. function loadColorBounds()
  2227. {
  2228. for (var name_1 in COLOR_BOUNDS)
  2229. {
  2230. defineColor(name_1, COLOR_BOUNDS[name_1].hueRange, COLOR_BOUNDS[name_1].lowerBounds);
  2231. }
  2232. }
  2233.  
  2234. function randomWithin(min, max)
  2235. {
  2236. if (min === void 0)
  2237. {
  2238. min = 0;
  2239. }
  2240. if (max === void 0)
  2241. {
  2242. max = 0;
  2243. }
  2244. if (seed === null)
  2245. {
  2246. return Math.floor(min + Math.random() * (max + 1 - min));
  2247. }
  2248. else
  2249. {
  2250. // seeded random algorithm from http://indiegamr.com/generate-repeatable-random-numbers-in-js/
  2251. seed = (seed * 9301 + 49297) % 233280;
  2252. var rnd = seed / 233280.0;
  2253. return Math.floor(min + rnd * (max - min));
  2254. }
  2255. }
  2256.  
  2257. function getColorInfo(hue)
  2258. {
  2259. // maps red colors to make picking hue easier
  2260. if (hue >= 334 && hue <= 360)
  2261. {
  2262. hue -= 360;
  2263. }
  2264. for (var colorName in colorDictionary)
  2265. {
  2266. var color = colorDictionary[colorName];
  2267. if (color.hueRange.length > 0
  2268. && hue >= color.hueRange[0]
  2269. && hue <= color.hueRange[1])
  2270. {
  2271. return colorDictionary[colorName];
  2272. }
  2273. }
  2274. return COLOR_NOT_FOUND;
  2275. }
  2276.  
  2277. function getHueRange(colorInput)
  2278. {
  2279. var number = typeof colorInput === 'undefined' ? Number.NaN : colorInput;
  2280. if (typeof number === 'string')
  2281. {
  2282. number = parseInt(number, 10);
  2283. }
  2284. if (colorInput && isNaN(number) && colorDictionary.hasOwnProperty(colorInput))
  2285. {
  2286. var color = colorDictionary[colorInput];
  2287. if (color.hueRange.length > 0)
  2288. {
  2289. return color.hueRange;
  2290. }
  2291. }
  2292. else if (!isNaN(number) && number < 360 && number > 0)
  2293. {
  2294. return [number, number];
  2295. }
  2296. return [0, 360];
  2297. }
  2298.  
  2299. function pickHue(options)
  2300. {
  2301. var hueRange = getHueRange(options.hue);
  2302. var hue = randomWithin(hueRange[0], hueRange[1]);
  2303. // instead of storing red as two seperate ranges, we group them, using negative numbers
  2304. if (hue < 0)
  2305. {
  2306. return 360 + hue;
  2307. }
  2308. return hue;
  2309. }
  2310.  
  2311. function getSaturationRange(hue)
  2312. {
  2313. return getColorInfo(hue).saturationRange;
  2314. }
  2315.  
  2316. function pickSaturation(hue, options)
  2317. {
  2318. if (options.luminosity === 'random')
  2319. {
  2320. return randomWithin(0, 100);
  2321. }
  2322. if (options.hue === 'monochrome')
  2323. {
  2324. return 0;
  2325. }
  2326. var _a = getSaturationRange(hue)
  2327. , sMin = _a[0]
  2328. , sMax = _a[1];
  2329. switch (options.luminosity)
  2330. {
  2331. case 'bright':
  2332. sMin = 55;
  2333. break;
  2334. case 'dark':
  2335. sMin = sMax - 10;
  2336. break;
  2337. case 'light':
  2338. sMax = 55;
  2339. break;
  2340. }
  2341. return randomWithin(sMin, sMax);
  2342. }
  2343.  
  2344. function getMinimumBrightness(H, S)
  2345. {
  2346. var lowerBounds = getColorInfo(H).lowerBounds;
  2347. for (var i = 0; i < lowerBounds.length - 1; i++)
  2348. {
  2349. var _a = lowerBounds[i]
  2350. , s1 = _a[0]
  2351. , v1 = _a[1];
  2352. var _b = lowerBounds[i + 1]
  2353. , s2 = _b[0]
  2354. , v2 = _b[1];
  2355. if (S >= s1 && S <= s2)
  2356. {
  2357. var m = (v2 - v1) / (s2 - s1);
  2358. var b = v1 - m * s1;
  2359. return m * S + b;
  2360. }
  2361. }
  2362. return 0;
  2363. }
  2364.  
  2365. function pickBrightness(H, S, options)
  2366. {
  2367. var bMin = getMinimumBrightness(H, S);
  2368. var bMax = 100;
  2369. switch (options.luminosity)
  2370. {
  2371. case 'dark':
  2372. bMax = bMin + 20;
  2373. break;
  2374. case 'light':
  2375. bMin = (bMax + bMin) / 2;
  2376. break;
  2377. case 'random':
  2378. bMin = 0;
  2379. bMax = 100;
  2380. break;
  2381. }
  2382. return randomWithin(bMin, bMax);
  2383. }
  2384. var HSVColor = (function ()
  2385. {
  2386. function HSVColor(H, S, V)
  2387. {
  2388. this.H = H;
  2389. this.S = S;
  2390. this.V = V;
  2391. }
  2392. HSVColor.fromHSVArray = function (hsv)
  2393. {
  2394. return new HSVColor(hsv[0], hsv[1], hsv[2]);
  2395. };
  2396. HSVColor.prototype.toHex = function ()
  2397. {
  2398. var rgb = this.toRGB();
  2399. return '#' + this.componentToHex(rgb[0]) + this.componentToHex(rgb[1]) + this.componentToHex(rgb[2]);
  2400. };
  2401. HSVColor.prototype.toHSL = function ()
  2402. {
  2403. var h = this.H;
  2404. var s = this.S / 100;
  2405. var v = this.V / 100;
  2406. var k = (2 - s) * v;
  2407. return [
  2408. h
  2409. , Math.round(s * v / (k < 1 ? k : 2 - k) * 10e3) / 100
  2410. , k / 2 * 100
  2411. ];
  2412. };
  2413. HSVColor.prototype.toHSLString = function (alpha)
  2414. {
  2415. var hsl = this.toHSL();
  2416. if (alpha !== undefined)
  2417. {
  2418. return "hsla(" + hsl[0] + ", " + hsl[1] + "%, " + hsl[2] + "%, " + alpha + ")";
  2419. }
  2420. else
  2421. {
  2422. return "hsl(" + hsl[0] + ", " + hsl[1] + "%, " + hsl[2] + "%)";
  2423. }
  2424. };
  2425. HSVColor.prototype.toRGB = function ()
  2426. {
  2427. // this doesn't work for the values of 0 and 360 here's the hacky fix
  2428. var h = Math.min(Math.max(this.H, 1), 359);
  2429. // Rebase the h,s,v values
  2430. h = h / 360;
  2431. var s = this.S / 100;
  2432. var v = this.V / 100;
  2433. var h_i = Math.floor(h * 6);
  2434. var f = h * 6 - h_i;
  2435. var p = v * (1 - s);
  2436. var q = v * (1 - f * s);
  2437. var t = v * (1 - (1 - f) * s);
  2438. var r = 256;
  2439. var g = 256;
  2440. var b = 256;
  2441. switch (h_i)
  2442. {
  2443. case 0:
  2444. r = v;
  2445. g = t;
  2446. b = p;
  2447. break;
  2448. case 1:
  2449. r = q;
  2450. g = v;
  2451. b = p;
  2452. break;
  2453. case 2:
  2454. r = p;
  2455. g = v;
  2456. b = t;
  2457. break;
  2458. case 3:
  2459. r = p;
  2460. g = q;
  2461. b = v;
  2462. break;
  2463. case 4:
  2464. r = t;
  2465. g = p;
  2466. b = v;
  2467. break;
  2468. case 5:
  2469. r = v;
  2470. g = p;
  2471. b = q;
  2472. break;
  2473. }
  2474. return [Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)];
  2475. };
  2476. HSVColor.prototype.toRGBString = function (alpha)
  2477. {
  2478. var rgb = this.toRGB();
  2479. if (alpha !== undefined)
  2480. {
  2481. return "rgba(" + rgb.join(', ') + ", " + alpha + ")";
  2482. }
  2483. else
  2484. {
  2485. return "rgb(" + rgb.join(', ') + ")";
  2486. }
  2487. };
  2488. HSVColor.prototype.componentToHex = function (c)
  2489. {
  2490. var hex = c.toString(16);
  2491. return hex.length == 1 ? '0' + hex : hex;
  2492. };
  2493. return HSVColor;
  2494. }());
  2495. colorGenerator.HSVColor = HSVColor;
  2496.  
  2497. function setFormat(hsv, options)
  2498. {
  2499. var color = HSVColor.fromHSVArray(hsv);
  2500. switch (options.format)
  2501. {
  2502. case 'object':
  2503. return color;
  2504. case 'hsvArray':
  2505. return hsv;
  2506. case 'hslArray':
  2507. return color.toHSL();
  2508. case 'hsl':
  2509. return color.toHSLString();
  2510. case 'hsla':
  2511. return color.toHSLString(options.alpha || Math.random());
  2512. case 'rgbArray':
  2513. return color.toRGB();
  2514. case 'rgb':
  2515. return color.toRGBString();
  2516. case 'rgba':
  2517. return color.toRGBString(options.alpha || Math.random());
  2518. case 'hex':
  2519. default:
  2520. return color.toHex();
  2521. }
  2522. }
  2523.  
  2524. function generateColor(options)
  2525. {
  2526. // pick a hue (H)
  2527. var H = pickHue(options);
  2528. // use H to determine saturation (S)
  2529. var S = pickSaturation(H, options);
  2530. // use S and H to determine brightness (B)
  2531. var B = pickBrightness(H, S, options);
  2532. // return the HSB color in the desired format
  2533. return setFormat([H, S, B], options);
  2534. }
  2535.  
  2536. function getRandom(options)
  2537. {
  2538. options = options ||
  2539. {};
  2540. seed = options.seed == null ? null : options.seed;
  2541. // check if we need to generate multiple colors
  2542. if (options.count !== null && options.count !== undefined)
  2543. {
  2544. var colors = [];
  2545. while (options.count > colors.length)
  2546. {
  2547. // Since we're generating multiple colors, the seed has to be incrememented.
  2548. // Otherwise we'd just generate the same color each time...
  2549. if (seed !== null)
  2550. {
  2551. seed += 1;
  2552. }
  2553. colors.push(generateColor(options));
  2554. }
  2555. return colors;
  2556. }
  2557. return generateColor(options);
  2558. }
  2559. colorGenerator.getRandom = getRandom;
  2560. var ColorInterval = (function ()
  2561. {
  2562. function ColorInterval(start, end)
  2563. {
  2564. this.start = start;
  2565. this.end = end;
  2566. this.left = null;
  2567. this.right = null;
  2568. this.value = null;
  2569. }
  2570. ColorInterval.prototype.getNextValue = function ()
  2571. {
  2572. if (this.value == null)
  2573. {
  2574. this.value = (this.start + this.end) / 2;
  2575. return this.value;
  2576. }
  2577. if (this.left == null)
  2578. {
  2579. this.left = new ColorInterval(this.start, this.value);
  2580. return this.left.getNextValue();
  2581. }
  2582. if (this.right == null)
  2583. {
  2584. this.right = new ColorInterval(this.value, this.end);
  2585. return this.right.getNextValue();
  2586. }
  2587. if (this.left.getHeight() <= this.right.getHeight())
  2588. {
  2589. return this.left.getNextValue();
  2590. }
  2591. else
  2592. {
  2593. return this.right.getNextValue();
  2594. }
  2595. };
  2596. ColorInterval.prototype.getHeight = function ()
  2597. {
  2598. return 1
  2599. + (this.left == null ? 0 : this.left.getHeight())
  2600. + (this.right == null ? 0 : this.right.getHeight());
  2601. };
  2602. return ColorInterval;
  2603. }());
  2604. colorGenerator.ColorInterval = ColorInterval;
  2605. var defaultRootInterval = new ColorInterval(0, 360);
  2606.  
  2607. function getEquallyDistributed(rootInterval)
  2608. {
  2609. if (rootInterval === void 0)
  2610. {
  2611. rootInterval = defaultRootInterval;
  2612. }
  2613. return 'hsl(' + rootInterval.getNextValue() + ', 100%, 80%)';
  2614. }
  2615. colorGenerator.getEquallyDistributed = getEquallyDistributed;
  2616. var Color = (function ()
  2617. {
  2618. function Color(r, g, b)
  2619. {
  2620. this.r = r;
  2621. this.g = g;
  2622. this.b = b;
  2623. }
  2624. Color.fromHex = function (hex)
  2625. {
  2626. return new Color(parseInt(hex.substr(1, 2), 16), parseInt(hex.substr(3, 2), 16), parseInt(hex.substr(5, 2), 16));
  2627. };
  2628. Color.fromRgb = function (rgb)
  2629. {
  2630. var match = rgb.match(this.rgbRegex);
  2631. return new Color(parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3], 10));
  2632. };
  2633. Color.fromString = function (str)
  2634. {
  2635. if (this.hexRegex.test(str))
  2636. {
  2637. return this.fromHex(str);
  2638. }
  2639. else if (this.rgbRegex.test(str))
  2640. {
  2641. return this.fromRgb(str);
  2642. }
  2643. else
  2644. {
  2645. throw new Error('Unexpected color format: ' + str);
  2646. }
  2647. };
  2648. Color.prototype.toString = function (hex)
  2649. {
  2650. if (hex === void 0)
  2651. {
  2652. hex = true;
  2653. }
  2654. return '#' + this.toHex(this.r) + this.toHex(this.g) + this.toHex(this.b);
  2655. };
  2656. Color.prototype.toHex = function (x)
  2657. {
  2658. var xStr = x.toString(16);
  2659. return (xStr.length == 1 ? '0' : '') + xStr;
  2660. };
  2661. Color.hexRegex = /^#(?:[0-9a-f]{3}){1,2}$/i;
  2662. Color.rgbRegex = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i;
  2663. return Color;
  2664. }());
  2665.  
  2666. function ratioColor(color1, color2, ratio)
  2667. {
  2668. 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));
  2669. return color.toString();
  2670. }
  2671.  
  2672. function getColorTransition(value, colorStrings)
  2673. {
  2674. var smallerValue = -1;
  2675. var biggerValue = Number.MAX_SAFE_INTEGER;
  2676. var colors = {};
  2677. for (var v in colorStrings)
  2678. {
  2679. var vNum = Number(v);
  2680. if (vNum === value)
  2681. {
  2682. return colorStrings[v];
  2683. }
  2684. else if (vNum < value)
  2685. {
  2686. smallerValue = Math.max(smallerValue, vNum);
  2687. }
  2688. else
  2689. {
  2690. biggerValue = Math.min(biggerValue, vNum);
  2691. }
  2692. colors[v] = Color.fromString(colorStrings[v]);
  2693. }
  2694. if (smallerValue === -1)
  2695. {
  2696. return colorStrings[biggerValue];
  2697. }
  2698. if (biggerValue === Number.MAX_SAFE_INTEGER)
  2699. {
  2700. return colorStrings[smallerValue];
  2701. }
  2702. var ratio = (value - smallerValue) / (biggerValue - smallerValue);
  2703. return ratioColor(colors[smallerValue], colors[biggerValue], ratio);
  2704. }
  2705. colorGenerator.getColorTransition = getColorTransition;
  2706. // populate the color dictionary
  2707. loadColorBounds();
  2708. })(colorGenerator || (colorGenerator = {}));
  2709.  
  2710. /**
  2711. * provides icons
  2712. */
  2713. var icons;
  2714. (function (icons)
  2715. {
  2716. 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';
  2717. 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"/>';
  2718.  
  2719. function getSvgAsUrl(svg)
  2720. {
  2721. return "url('data:image/svg+xml;base64," + btoa(svg) + "')";
  2722. }
  2723. icons.getSvgAsUrl = getSvgAsUrl;
  2724.  
  2725. function wrapCodeWithSvg(code, viewBox, width, height)
  2726. {
  2727. return "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"" + width + "\" height=\"" + height + "\" viewBox=\"" + viewBox + "\">" + code + "</svg>";
  2728. }
  2729. icons.wrapCodeWithSvg = wrapCodeWithSvg;
  2730.  
  2731. function getMd(pathDots, color, width, height)
  2732. {
  2733. if (color === void 0)
  2734. {
  2735. color = 'black';
  2736. }
  2737. if (width === void 0)
  2738. {
  2739. width = '30';
  2740. }
  2741. if (height === void 0)
  2742. {
  2743. height = '30';
  2744. }
  2745. return getSvgAsUrl(wrapCodeWithSvg("<path fill=\"" + color + "\" d=\"" + pathDots + "\" />", '0 0 24 24', width, height));
  2746. }
  2747. icons.getMd = getMd;
  2748. })(icons || (icons = {}));
  2749.  
  2750. /**
  2751. * notifications
  2752. */
  2753. var notifications;
  2754. (function (notifications)
  2755. {
  2756. notifications.name = 'notifications';
  2757.  
  2758. function event(title, options)
  2759. {
  2760. if ((!options || options.whenActive !== true)
  2761. && !document.hidden && document.hasFocus()
  2762. && settings.getSub(settings.KEY.showNotifications, 'showType') !== 1)
  2763. {
  2764. return;
  2765. }
  2766. if (!settings.get(settings.KEY.showNotifications))
  2767. {
  2768. // notifications disabled: return stub notification
  2769. return Promise.resolve(
  2770. {
  2771. close: function () {}
  2772. });
  2773. }
  2774. if (!("Notification" in win))
  2775. {
  2776. return Promise.reject('Your browser does not support notifications.');
  2777. }
  2778. return Notification.requestPermission()
  2779. .then(function (permission)
  2780. {
  2781. if (permission === 'granted')
  2782. {
  2783. var n_1 = new Notification(title, options);
  2784. n_1.onclick = function (event)
  2785. {
  2786. if (options && options.autoFocus !== false)
  2787. {
  2788. win.focus();
  2789. }
  2790. if (options && options.autoClose !== false)
  2791. {
  2792. n_1.close();
  2793. }
  2794. if (options && options.onclick)
  2795. {
  2796. options.onclick(n_1, event);
  2797. }
  2798. };
  2799. return Promise.resolve(n_1);
  2800. }
  2801. else
  2802. {
  2803. return Promise.reject('Notification permission denied');
  2804. }
  2805. });
  2806. }
  2807. notifications.event = event;
  2808.  
  2809. function requestPermission()
  2810. {
  2811. if (settings.get(settings.KEY.showNotifications))
  2812. {
  2813. Notification.requestPermission();
  2814. }
  2815. }
  2816.  
  2817. function init()
  2818. {
  2819. requestPermission();
  2820. settings.observe(settings.KEY.showNotifications, function ()
  2821. {
  2822. return requestPermission();
  2823. });
  2824. }
  2825. notifications.init = init;
  2826. })(notifications || (notifications = {}));
  2827.  
  2828. /**
  2829. * process commands
  2830. */
  2831. var commands;
  2832. (function (commands)
  2833. {
  2834. var XP_GAIN_KEY = 'xpGain';
  2835. var MAX_XP_GAIN_HISTORY_LENGTH = 100;
  2836. var IMAGE2SKILL = {
  2837. // mining = #cc0000
  2838. 'icons/pickaxe': 'mining'
  2839. // crafting = #cc0000
  2840. , 'icons/anvil': 'crafting'
  2841. // woodcutting = cyan
  2842. , 'icons/woodcutting': 'woodcutting'
  2843. // farming = green
  2844. , 'icons/watering-can': 'farming'
  2845. // brewing = #800080
  2846. , 'vialOfWater': 'brewing'
  2847. , 'largeVialOfWater': 'brewing'
  2848. , 'hugeVialOfWater': 'brewing'
  2849. // combat = lime
  2850. , 'icons/combat': 'combat'
  2851. // magic = blue
  2852. , 'icons/wizardhat': 'magic'
  2853. // fishing = blue
  2854. , 'tuna': 'fishing'
  2855. // cooking = yellow
  2856. , 'icons/cooking': 'cooking'
  2857. };
  2858. var xpGainHistory = store.has(XP_GAIN_KEY) ? store.get(XP_GAIN_KEY) :
  2859. {};
  2860. addStyle("\n.scroller.xp\n{\n\tfont-size: 18pt;\n\tposition: absolute;\n\ttext-align: center;\n}\n\t");
  2861.  
  2862. function minutes2String(data)
  2863. {
  2864. return data.replace(/Your account has been running for: (\d+) minutes./, function (wholeMatch, minutes)
  2865. {
  2866. return 'Your account has been running for ' + format.min2Str(minutes) + '.';
  2867. });
  2868. }
  2869. var LOOT_MSG_PREFIX = 'SHOW_LOOT_DIAG=';
  2870.  
  2871. function processLoot(data)
  2872. {
  2873. if (!/^SM=Your boat found nothing\.$|^SHOW_LOOT_DIAG=/.test(data))
  2874. {
  2875. return false;
  2876. }
  2877. var loot = {
  2878. type: 'loot'
  2879. , title: ''
  2880. , itemList: []
  2881. };
  2882. if (data.startsWith('SM='))
  2883. {
  2884. loot.title = 'Boat';
  2885. loot.emptyText = 'Your boat found nothing.';
  2886. }
  2887. else if (data.startsWith(LOOT_MSG_PREFIX))
  2888. {
  2889. var split = data.substr(LOOT_MSG_PREFIX.length).split('~');
  2890. loot.title = split[0];
  2891. for (var i = 1; i < split.length; i += 2)
  2892. {
  2893. loot.itemList.push(
  2894. {
  2895. icon: split[i]
  2896. , text: split[i + 1]
  2897. });
  2898. }
  2899. }
  2900. log.add(loot);
  2901. return true;
  2902. }
  2903. var XP_GAIN_REGEX = /^ST=([^~]+)\.png~([^~]+)~\+(\d+)\s*xp(.*)$/;
  2904. var animationQueue = {};
  2905.  
  2906. function queueXpAnimation(skill, cell, color, xpAmount, extraXp)
  2907. {
  2908. if (!settings.get(settings.KEY.newXpAnimation))
  2909. {
  2910. return;
  2911. }
  2912. animationQueue[skill] = animationQueue[skill] || [];
  2913. animationQueue[skill].push(
  2914. {
  2915. cell: cell
  2916. , color: color
  2917. , xpAmount: xpAmount
  2918. , extraXp: extraXp
  2919. });
  2920. if (animationQueue[skill].length === 1)
  2921. {
  2922. nextAnimation(skill);
  2923. }
  2924. }
  2925.  
  2926. function nextAnimation(skill)
  2927. {
  2928. var entry = animationQueue[skill][0];
  2929. if (!entry || !settings.get(settings.KEY.newXpAnimation))
  2930. {
  2931. return;
  2932. }
  2933. var cell = entry.cell
  2934. , color = entry.color
  2935. , xpAmount = entry.xpAmount
  2936. , extraXp = entry.extraXp;
  2937. var rect = cell.getBoundingClientRect();
  2938. var extraXpStr = extraXp > 0 ? " (+" + extraXp + ")" : '';
  2939. 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>")
  2940. .appendTo('body');
  2941. // ensure the existence of $el, so the complete-function can be called instantly if the window is hidden
  2942. $el
  2943. .animate(
  2944. {
  2945. top: '-=15px'
  2946. }
  2947. , {
  2948. duration: 1500
  2949. , easing: 'easeOutQuad'
  2950. , complete: function ()
  2951. {
  2952. animationQueue[skill].shift();
  2953. nextAnimation(skill);
  2954. }
  2955. })
  2956. .fadeOut(
  2957. {
  2958. duration: 2500
  2959. , queue: false
  2960. , complete: function ()
  2961. {
  2962. return $el.remove();
  2963. }
  2964. });
  2965. }
  2966.  
  2967. function processXpGain(data)
  2968. {
  2969. var match = data.match(XP_GAIN_REGEX);
  2970. if (!match)
  2971. {
  2972. return false;
  2973. }
  2974. var icon = match[1];
  2975. var skill = IMAGE2SKILL[icon] || '';
  2976. var color = match[2];
  2977. var xpAmount = Number(match[3]);
  2978. var extra = match[4];
  2979. var cell = document.getElementById('top-bar-level-td-' + skill);
  2980. if (!cell)
  2981. {
  2982. console.debug('match (no cell found):', match);
  2983. return false;
  2984. }
  2985. var entry = {
  2986. time: now()
  2987. , amount: xpAmount
  2988. };
  2989. if (match[4])
  2990. {
  2991. entry.extra = match[4];
  2992. }
  2993. if (skill == 'fishing')
  2994. {
  2995. log.processFishingXpChange(xpAmount);
  2996. }
  2997. var extraXp = 0;
  2998. if (extra && settings.get(settings.KEY.newXpAnimation))
  2999. {
  3000. var extraMatch = extra.match(/^\s*\(<img[^>]+src=(['"])images\/([^']+)\.png\1[^>]+>\s*(.+)\)$/);
  3001. var extraXpMatch = extra.match(/^\s*\(\+(\d+)\s*xp\)\s*$/);
  3002. if (extraMatch)
  3003. {
  3004. var icon_1 = extraMatch[2];
  3005. var text = extraMatch[3];
  3006. if (icon_1 == 'brewingKit')
  3007. {
  3008. text = '+' + text;
  3009. }
  3010. win.scrollText(icon_1, color, text);
  3011. }
  3012. else if (extraXpMatch)
  3013. {
  3014. extraXp = Number(extraXpMatch[1]);
  3015. }
  3016. else
  3017. {
  3018. win.scrollText('none', color, extra);
  3019. }
  3020. }
  3021. // save the xp event
  3022. var list = xpGainHistory[skill] || [];
  3023. list.push(entry);
  3024. xpGainHistory[skill] = list.slice(-MAX_XP_GAIN_HISTORY_LENGTH);
  3025. store.set(XP_GAIN_KEY, xpGainHistory);
  3026. if (settings.get(settings.KEY.newXpAnimation))
  3027. {
  3028. queueXpAnimation(skill, cell, color, xpAmount, extraXp);
  3029. }
  3030. return true;
  3031. }
  3032.  
  3033. function processLevelUp(data)
  3034. {
  3035. if (!data.startsWith('LVL_UP='))
  3036. {
  3037. return false;
  3038. }
  3039. var skill = data.substr('LVL_UP='.length);
  3040. var xp = getGameValue(skill + 'Xp');
  3041. var oldLvl = win.getLevel(xp);
  3042. log.add(
  3043. {
  3044. type: 'lvlup'
  3045. , skill: skill
  3046. , newLevel: oldLvl + 1
  3047. });
  3048. return true;
  3049. }
  3050.  
  3051. function processCombat(data)
  3052. {
  3053. var match = data.match(/^STHS=([^~]+)~([^~]+)~([^~]+)~img-(.+)~(melee|heal)$/);
  3054. if (!match)
  3055. {
  3056. return false;
  3057. }
  3058. // keep track of different battles and add the data to the current battle
  3059. var number = match[3];
  3060. if (!/\D/.test(number))
  3061. {
  3062. number = Number(number);
  3063. }
  3064. log.add(
  3065. {
  3066. type: 'combat'
  3067. , what: match[5]
  3068. , who: match[4]
  3069. , text: number
  3070. });
  3071. return true;
  3072. }
  3073.  
  3074. function processEnergy(data)
  3075. {
  3076. var match = data.match(/^ST=steak\.png~orange~\+([\d',]+)$/);
  3077. if (!match)
  3078. {
  3079. return false;
  3080. }
  3081. log.add(
  3082. {
  3083. type: 'energy'
  3084. , energy: Number(match[1].replace(/\D/g, ''))
  3085. });
  3086. return true;
  3087. }
  3088.  
  3089. function processHeat(data)
  3090. {
  3091. var match = data.match(/^ST=icons\/fire\.png~red~\+([\d',]+)$/);
  3092. if (!match)
  3093. {
  3094. return false;
  3095. }
  3096. log.add(
  3097. {
  3098. type: 'heat'
  3099. , heat: Number(match[1].replace(/\D/g, ''))
  3100. });
  3101. return true;
  3102. }
  3103.  
  3104. function processMarket(data)
  3105. {
  3106. if (data === 'ST=icons/shop.png~orange~Item Purchased')
  3107. {
  3108. log.add(
  3109. {
  3110. type: 'market'
  3111. });
  3112. return true;
  3113. }
  3114. var match = data.match(/^ST=coins\.png~yellow~\+([\d',]+)$/);
  3115. if (!match)
  3116. {
  3117. return false;
  3118. }
  3119. var coins = Number(match[1].replace(/\D/g, ''));
  3120. log.add(
  3121. {
  3122. type: 'market'
  3123. , coins: coins
  3124. });
  3125. return true;
  3126. }
  3127.  
  3128. function processBonemeal(data)
  3129. {
  3130. var match = data.match(/^ST=filledBonemealBin\.png~white~\+([\d',]+)$/);
  3131. if (!match)
  3132. {
  3133. return false;
  3134. }
  3135. var bonemeal = Number(match[1].replace(/\D/g, ''));
  3136. log.add(
  3137. {
  3138. type: 'bonemeal'
  3139. , bonemeal: bonemeal
  3140. });
  3141. return true;
  3142. }
  3143.  
  3144. function processCrafting(data)
  3145. {
  3146. if (data === 'ST=none~#806600~Item Crafted')
  3147. {
  3148. log.add(
  3149. {
  3150. type: 'crafting'
  3151. });
  3152. return true;
  3153. }
  3154. return false;
  3155. }
  3156.  
  3157. function processStardust(data)
  3158. {
  3159. var match = data.match(/^ST=(?:icons\/)?stardust\.png~yellow~\+([\d',]+)$/);
  3160. if (!match)
  3161. {
  3162. return false;
  3163. }
  3164. var stardust = Number(match[1].replace(/\D/g, ''));
  3165. log.add(
  3166. {
  3167. type: 'stardust'
  3168. , stardust: stardust
  3169. });
  3170. return true;
  3171. }
  3172. var RUNNING_ACCOUNT_STR = 'Your account has been running for:';
  3173.  
  3174. function formatData(data)
  3175. {
  3176. if (data.startsWith('STHS=')
  3177. || data.startsWith('STE=')
  3178. || data.startsWith('SM=')
  3179. || data.startsWith('ST=')
  3180. || data.startsWith('SHOW_LOOT_DIAG='))
  3181. {
  3182. if (data.indexOf(RUNNING_ACCOUNT_STR) != -1)
  3183. {
  3184. data = minutes2String(data);
  3185. }
  3186. data = format.numbersInText(data);
  3187. }
  3188. return data;
  3189. }
  3190. commands.formatData = formatData;
  3191.  
  3192. function process(data)
  3193. {
  3194. // prepare for logging events in an activity log
  3195. if (processLoot(data))
  3196. {
  3197. return;
  3198. }
  3199. else if (processXpGain(data))
  3200. {
  3201. // return undefined to let the original function be called
  3202. return settings.get(settings.KEY.newXpAnimation) ? null : void 0;
  3203. }
  3204. else if (processLevelUp(data)
  3205. || processCombat(data)
  3206. || processEnergy(data)
  3207. || processHeat(data)
  3208. || processMarket(data)
  3209. || processBonemeal(data)
  3210. || processCrafting(data)
  3211. || processStardust(data))
  3212. {
  3213. return;
  3214. }
  3215. else if (data.startsWith('SM='))
  3216. {
  3217. log.add(
  3218. {
  3219. data: minutes2String(data.replace(/^[^=]+=/, ''))
  3220. });
  3221. }
  3222. else if (data.startsWith('STHS=') || data.startsWith('STE=') || data.startsWith('ST='))
  3223. {}
  3224. // notifications for this kind of message: "SM=An update has been scheduled for today."
  3225. if (data.startsWith('SM='))
  3226. {
  3227. if (settings.getSub(settings.KEY.showNotifications, 'serverMsg'))
  3228. {
  3229. var msg = data.substr(3)
  3230. .replace(/<br\s*\/?>/g, '\n')
  3231. .replace(/<img src='images\/(.+?)\.png'.+?\/?> (\d+)/g, function (wholeMatch, key, amount)
  3232. {
  3233. return format.number(amount) + ' ' + split2Words(key) + ', ';
  3234. })
  3235. .replace(/<.+?>/g, '')
  3236. .replace(/(\s)\1+/g, '$1')
  3237. .replace(/, $/, '');
  3238. notifications.event('Message from server'
  3239. , {
  3240. body: minutes2String(msg)
  3241. });
  3242. }
  3243. }
  3244. return;
  3245. }
  3246. commands.process = process;
  3247. })(commands || (commands = {}));
  3248.  
  3249. /**
  3250. * log activities and stuff
  3251. */
  3252. var log;
  3253. (function (log)
  3254. {
  3255. log.name = 'log';
  3256. var LOG_KEY = 'activityLog';
  3257. var MAX_LOG_SIZE = 100;
  3258. var logList = store.has(LOG_KEY) ? store.get(LOG_KEY) : [];
  3259. var currentCombat = null;
  3260. var currentCombatEl = null;
  3261. var LOG_FILTER = {
  3262. 'combat':
  3263. {
  3264. title: 'Combat'
  3265. , img: 'images/icons/combat.png'
  3266. }
  3267. , 'loot':
  3268. {
  3269. title: 'Loot'
  3270. , img: 'images/npcLoot0.png'
  3271. }
  3272. , 'fish':
  3273. {
  3274. title: 'Caught fish'
  3275. , img: 'images/tuna.png'
  3276. }
  3277. , 'skill':
  3278. {
  3279. title: 'Skill advance'
  3280. , img: 'images/icons/skills.png'
  3281. }
  3282. , 'other':
  3283. {
  3284. title: 'All other'
  3285. , label: 'Other'
  3286. }
  3287. };
  3288. var logEl;
  3289.  
  3290. function isFightStarted()
  3291. {
  3292. return win.fightMonsterId !== 0;
  3293. }
  3294.  
  3295. function saveLog()
  3296. {
  3297. store.set(LOG_KEY, logList);
  3298. }
  3299.  
  3300. function createLi(entry)
  3301. {
  3302. var entryEl = document.createElement('li');
  3303. entryEl.dataset.time = (new Date(entry.time || 0)).toLocaleString();
  3304. entryEl.dataset.type = entry.type;
  3305. return entryEl;
  3306. }
  3307.  
  3308. function appendLi(entryEl)
  3309. {
  3310. var filterEl = logEl.firstElementChild;
  3311. var next = filterEl && filterEl.nextElementSibling;
  3312. if (next)
  3313. {
  3314. logEl.insertBefore(entryEl, next);
  3315. }
  3316. else
  3317. {
  3318. logEl.appendChild(entryEl);
  3319. }
  3320. logEl.classList.remove('empty');
  3321. }
  3322.  
  3323. function setGenericEntry(entry, init)
  3324. {
  3325. var el = createLi(entry);
  3326. el.innerHTML = typeof entry.data === 'string' ? format.numbersInText(entry.data) : JSON.stringify(entry.data);
  3327. appendLi(el);
  3328. }
  3329. var chest = '';
  3330. function getChestType(){
  3331. $("#dialogue-chestmenu-open :input[type='image']").click(function(){
  3332. chest = 'Normal ';
  3333. });
  3334. $("#dialogue-promethiumChestmenu-open :input[type='image']").click(function(){
  3335. chest = 'Green ';
  3336. });
  3337. $("#dialogue-runiteChestmenu-open :input[type='image']").click(function(){
  3338. chest = 'Red ';
  3339. });
  3340. }
  3341. function setLootEntry(entry, init)
  3342. {
  3343. var el = createLi(entry);
  3344. var header = document.createElement('h1');
  3345. header.className = 'container-title';
  3346. header.textContent = entry.title;
  3347. el.appendChild(header);
  3348. var itemContainer = document.createElement('span');
  3349. if (entry.itemList.length === 0)
  3350. {
  3351. itemContainer.innerHTML = "<span class=\"dialogue-loot\">" + entry.emptyText + "</span>";
  3352. }
  3353. else
  3354. {
  3355. var update = false;
  3356. for (var _i = 0, _a = entry.itemList; _i < _a.length; _i++)
  3357. {
  3358. var item = _a[_i];
  3359. if (item.hasOwnProperty('key'))
  3360. {
  3361. item.icon = item.key;
  3362. delete item.key;
  3363. update = true;
  3364. }
  3365. if (item.hasOwnProperty('amount'))
  3366. {
  3367. item.text = (item.amount || Number.NaN).toString();
  3368. delete item.amount;
  3369. update = true;
  3370. }
  3371. var itemEl = document.createElement('span');
  3372. itemEl.className = 'dialogue-loot';
  3373. itemEl.innerHTML = "<img src=\"" + item.icon + "\" class=\"image-icon-50\"> " + format.numbersInText(item.text);
  3374. itemContainer.appendChild(itemEl);
  3375. itemContainer.appendChild(document.createTextNode(' '));
  3376. }
  3377. // Chest loot:
  3378. if (entry.title == "Chest loot:"){
  3379. header.textContent = chest + "Chest loot:";
  3380. }
  3381.  
  3382. if (update)
  3383. {
  3384. saveLog();
  3385. }
  3386. }
  3387. el.appendChild(itemContainer);
  3388. var valueContainer = document.createElement('div');
  3389. valueContainer.className = 'total-value';
  3390. valueContainer.appendChild(document.createTextNode('Total value: '));
  3391. var totalValue = document.createElement('span');
  3392. totalValue.style.cursor = 'pointer';
  3393. totalValue.textContent = 'Click to calculate';
  3394. valueContainer.appendChild(totalValue);
  3395. totalValue.addEventListener('click', function ()
  3396. {
  3397. var items = {};
  3398. for (var _i = 0, _a = entry.itemList; _i < _a.length; _i++)
  3399. {
  3400. var item = _a[_i];
  3401. if (item.text.indexOf('xp') === -1)
  3402. {
  3403. var key = item.icon.replace(/^.+\/([^\/]+)\.png$/, '$1');
  3404. var num = Number(item.text.replace(/\D/g, ''));
  3405. items[key] = (items[key] || 0) + num;
  3406. }
  3407. }
  3408. market.calcMarketValue(items)
  3409. .then(function (sum)
  3410. {
  3411. 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]);
  3412. });
  3413. });
  3414. el.appendChild(valueContainer);
  3415. appendLi(el);
  3416. }
  3417.  
  3418. function setFishEntry(entry, init)
  3419. {
  3420. var el = createLi(entry);
  3421. el.innerHTML = "You caught a " + key2Name(entry.fish, true) + ".";
  3422. appendLi(el);
  3423. }
  3424.  
  3425. function setEnergyEntry(entry, init)
  3426. {
  3427. var el = createLi(entry);
  3428. el.innerHTML = "Your hero gained " + format.number(entry.energy) + " energy.";
  3429. appendLi(el);
  3430. }
  3431.  
  3432. function setHeatEntry(entry, init)
  3433. {
  3434. var el = createLi(entry);
  3435. el.innerHTML = "You added " + format.number(entry.heat) + " heat to your oven.";
  3436. appendLi(el);
  3437. }
  3438.  
  3439. function setLevelUpEntry(entry, init)
  3440. {
  3441. var el = createLi(entry);
  3442. el.innerHTML = "You advanced your " + entry.skill + " skill to level " + entry.newLevel + ".";
  3443. appendLi(el);
  3444. }
  3445.  
  3446. function getCombatInfo(data, initHp, scaleX, width)
  3447. {
  3448. var points = [];
  3449. var startHp = -1;
  3450. var hp = initHp;
  3451. for (var tick in data)
  3452. {
  3453. hp = data[tick];
  3454. if (startHp === -1)
  3455. {
  3456. startHp = hp;
  3457. }
  3458. points.push((scaleX * Number(tick)) + ' ' + hp);
  3459. }
  3460. if (points.length === 0)
  3461. {
  3462. points.push('0 ' + initHp);
  3463. }
  3464. points.push(width + ' ' + hp, width + ' 0', '0 0');
  3465. return {
  3466. points: points
  3467. , startHp: startHp === -1 ? initHp : startHp
  3468. , endHp: hp
  3469. };
  3470. }
  3471.  
  3472. function getHTMLFromCombatInfo(info, name)
  3473. {
  3474. 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>";
  3475. }
  3476.  
  3477. function setCombatEntry(entry, init)
  3478. {
  3479. var created = init || currentCombatEl == null;
  3480. if (init || currentCombatEl == null)
  3481. {
  3482. currentCombatEl = createLi(entry);
  3483. }
  3484. var HTML = '';
  3485. // support old log format
  3486. if (!entry.hasOwnProperty('ticks'))
  3487. {
  3488. var info = {
  3489. hero:
  3490. {
  3491. heal: 0
  3492. , melee: 0
  3493. }
  3494. , monster:
  3495. {
  3496. heal: 0
  3497. , melee: 0
  3498. }
  3499. };
  3500. for (var i = 0; i < entry.parts.length; i++)
  3501. {
  3502. var part = entry.parts[i];
  3503. info[part.who][part.type] += part.number;
  3504. }
  3505. 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>";
  3506. }
  3507. else
  3508. {
  3509. var currentTick = Math.max(entry.ticks, 0);
  3510. var width = logEl.scrollWidth - 4 * 12.8 - 2;
  3511. var scaleX = currentTick === 0 ? 0 : width / currentTick;
  3512. var hero = getCombatInfo(entry.hero, win.heroHp, scaleX, width);
  3513. var monster = getCombatInfo(entry.monster, win.fightMonsterHp, scaleX, width);
  3514. // TODO: who won?
  3515. 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";
  3516. }
  3517. // map monster name and area name from monster id (the ids are starting at 1)
  3518. var isShiny = entry.monsterId > 1e3;
  3519. var mId = entry.monsterId - (isShiny ? 1001 : 1);
  3520. var monsterName = (isShiny ? 'Shiny ' : '') + (getMonsterName(mId) || '(' + (mId % 3 + 1) + ')');
  3521. var areaId = (mId == 105 || mId == 106) ? 34 : Math.floor(mId / 3);
  3522. var areaName = getAreaName(areaId) || '(' + (areaId + 1) + ')';
  3523. currentCombatEl.innerHTML = "<h2>Combat against " + monsterName + " in " + areaName + "</h2>\n\t\t" + HTML;
  3524. if (created)
  3525. {
  3526. appendLi(currentCombatEl);
  3527. }
  3528. if (!isFightStarted())
  3529. {
  3530. currentCombatEl = null;
  3531. }
  3532. }
  3533.  
  3534. function setMarketEntry(entry, init)
  3535. {
  3536. var el = createLi(entry);
  3537. if (entry.coins)
  3538. {
  3539. el.innerHTML = "You collected " + format.number(entry.coins) + " from market.";
  3540. }
  3541. else
  3542. {
  3543. el.innerHTML = "You purchased an item on market.";
  3544. }
  3545. appendLi(el);
  3546. }
  3547.  
  3548. function setBonemealEntry(entry, init)
  3549. {
  3550. var el = createLi(entry);
  3551. el.innerHTML = "You added " + format.number(entry.bonemeal) + " bonemeal to your bonemeal bin.";
  3552. appendLi(el);
  3553. }
  3554.  
  3555. function setCraftingEntry(entry, init)
  3556. {
  3557. var el = createLi(entry);
  3558. el.innerHTML = "You crafted an item.";
  3559. appendLi(el);
  3560. }
  3561.  
  3562. function setStardustEntry(entry, init)
  3563. {
  3564. var el = createLi(entry);
  3565. el.innerHTML = "You got " + format.number(entry.stardust) + " stardust.";
  3566. appendLi(el);
  3567. }
  3568. var entryType2Fn = {
  3569. 'loot': setLootEntry
  3570. , 'fish': setFishEntry
  3571. , 'energy': setEnergyEntry
  3572. , 'heat': setHeatEntry
  3573. , 'lvlup': setLevelUpEntry
  3574. , 'combat': setCombatEntry
  3575. , 'market': setMarketEntry
  3576. , 'bonemeal': setBonemealEntry
  3577. , 'crafting': setCraftingEntry
  3578. , 'stardust': setStardustEntry
  3579. };
  3580.  
  3581. function updateLog(entry, init)
  3582. {
  3583. if (init === void 0)
  3584. {
  3585. init = false;
  3586. }
  3587. if (!logEl)
  3588. {
  3589. return;
  3590. }
  3591. if (entry.type && entryType2Fn.hasOwnProperty(entry.type))
  3592. {
  3593. entryType2Fn[entry.type](entry, init);
  3594. }
  3595. else
  3596. {
  3597. setGenericEntry(entry, init);
  3598. }
  3599. }
  3600.  
  3601. function add2Log(entry)
  3602. {
  3603. logList.push(entry);
  3604. logList = logList.slice(-MAX_LOG_SIZE);
  3605. saveLog();
  3606. }
  3607. // 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
  3608. function findCurrentCombat()
  3609. {
  3610. for (var i = logList.length - 1; i >= 0; i--)
  3611. {
  3612. if (logList[i].type == 'combat')
  3613. {
  3614. var entry = logList[i];
  3615. if (entry.monsterId == win.fightMonsterId
  3616. && entry.hero[entry.ticks] !== 0
  3617. && entry.hero[entry.ticks] !== 0)
  3618. {
  3619. return entry;
  3620. }
  3621. break;
  3622. }
  3623. }
  3624. return null;
  3625. }
  3626.  
  3627. function add(entry)
  3628. {
  3629. if (!entry.time)
  3630. {
  3631. entry.time = now();
  3632. }
  3633. if (entry.type == 'combat')
  3634. {
  3635. currentCombat = currentCombat || findCurrentCombat();
  3636. if (!currentCombat)
  3637. {
  3638. return;
  3639. }
  3640. // skip entries without further information
  3641. if (typeof entry.text !== 'number' || entry.text === 0)
  3642. {
  3643. return;
  3644. }
  3645. var hp = entry.who == 'hero' ? win.heroHp : win.fightMonsterHp;
  3646. // the hp values are updated after this event, so I have to calculate the new value by myself
  3647. hp += (entry.what == 'heal' ? 1 : -1) * entry.text;
  3648. currentCombat[entry.who][currentCombat.ticks] = hp;
  3649. saveLog();
  3650. updateLog(currentCombat);
  3651. }
  3652. else
  3653. {
  3654. add2Log(entry);
  3655. updateLog(entry);
  3656. }
  3657. }
  3658. log.add = add;
  3659.  
  3660. function addLogEl()
  3661. {
  3662. 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");
  3663. // add new tab "Activity Log"
  3664. var checkboxId = 'show-activity-log';
  3665. var activityLogLabel = document.createElement('label');
  3666. activityLogLabel.id = 'activity-log-label';
  3667. activityLogLabel.htmlFor = checkboxId;
  3668. activityLogLabel.textContent = 'Activity Log';
  3669. newTopbar.addTabEntry(activityLogLabel);
  3670. var checkbox = document.createElement('input');
  3671. checkbox.id = checkboxId;
  3672. checkbox.type = 'checkbox';
  3673. checkbox.style.display = 'none';
  3674. document.body.insertBefore(checkbox, document.body.firstChild);
  3675. var label = document.createElement('label');
  3676. label.id = 'activity-log-overlay';
  3677. label.htmlFor = checkboxId;
  3678. document.body.appendChild(label);
  3679. logEl = document.createElement('ul');
  3680. logEl.id = 'activity-log';
  3681. var classList = [];
  3682. var html = '';
  3683. for (var key in LOG_FILTER)
  3684. {
  3685. // TODO: load saved filter
  3686. var checked = true;
  3687. classList.push(key);
  3688. 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' : '') + ">";
  3689. }
  3690. logEl.className = 'empty ' + classList.join(' ');
  3691. logEl.innerHTML = "<li class=\"filter\">\n\t\t\t" + html + "\n\t\t</li>";
  3692. document.body.appendChild(logEl);
  3693. var $checkboxes = win.$('li.filter > input[id^="log-filter-"]');
  3694. $checkboxes.checkboxradio(
  3695. {
  3696. icon: false
  3697. });
  3698. $checkboxes.change(function (event)
  3699. {
  3700. var id = event.target.id;
  3701. var key = id.replace('log-filter-', '');
  3702. var checked = document.getElementById(id).checked;
  3703. logEl.classList[checked ? 'add' : 'remove'](key);
  3704. // TODO: save current state
  3705. });
  3706. // add all stored elements
  3707. logList.forEach(function (e)
  3708. {
  3709. return updateLog(e, true);
  3710. });
  3711. }
  3712.  
  3713. function observeCombat()
  3714. {
  3715. observer.add('fightMonsterId', function (key, oldValue, newValue)
  3716. {
  3717. if (isFightStarted())
  3718. {
  3719. currentCombat = {
  3720. type: 'combat'
  3721. , time: now()
  3722. , monsterId: newValue
  3723. , ticks: -5
  3724. , hero:
  3725. {}
  3726. , monster:
  3727. {}
  3728. };
  3729. add2Log(currentCombat);
  3730. updateLog(currentCombat);
  3731. }
  3732. else
  3733. {
  3734. if (currentCombat)
  3735. {
  3736. currentCombat.ticks--;
  3737. saveLog();
  3738. }
  3739. currentCombat = null;
  3740. currentCombatEl = null;
  3741. }
  3742. });
  3743. observer.addTick(function ()
  3744. {
  3745. if (currentCombat !== null)
  3746. {
  3747. currentCombat.ticks++;
  3748. if (currentCombat.ticks === 0)
  3749. {
  3750. currentCombat.hero[0] = win.heroHp;
  3751. currentCombat.monster[0] = win.fightMonsterHp;
  3752. }
  3753. updateLog(currentCombat);
  3754. }
  3755. });
  3756. }
  3757. var possiblyCaughtFish;
  3758. var lastFishingXpChange = 0;
  3759.  
  3760. function fishObserver(key, oldValue, newValue)
  3761. {
  3762. if (oldValue < newValue && lastFishingXpChange >= now() - 5e3)
  3763. {
  3764. var idx = possiblyCaughtFish.indexOf(key);
  3765. if (idx !== -1)
  3766. {
  3767. add(
  3768. {
  3769. type: 'fish'
  3770. , fish: key
  3771. });
  3772. possiblyCaughtFish = [];
  3773. lastFishingXpChange = 0;
  3774. }
  3775. }
  3776. }
  3777.  
  3778. function processFishingXpChange(xp)
  3779. {
  3780. lastFishingXpChange = now();
  3781. possiblyCaughtFish = [];
  3782. for (var fish in FISH_XP)
  3783. {
  3784. if (FISH_XP[fish] == xp)
  3785. {
  3786. possiblyCaughtFish.push(fish);
  3787. }
  3788. }
  3789. }
  3790. log.processFishingXpChange = processFishingXpChange;
  3791.  
  3792. function observeFishing()
  3793. {
  3794. for (var fish in FISH_XP)
  3795. {
  3796. observer.add(fish, fishObserver);
  3797. }
  3798. }
  3799.  
  3800. function init()
  3801. {
  3802. getChestType();
  3803. addLogEl();
  3804. observeCombat();
  3805. observeFishing();
  3806. }
  3807. log.init = init;
  3808. })(log || (log = {}));
  3809.  
  3810. /**
  3811. * game events
  3812. */
  3813. var gameEvents;
  3814. (function (gameEvents)
  3815. {
  3816. gameEvents.name = 'gameEvents';
  3817. // min time difference between two notifications with the same title (10 seconds)
  3818. var MIN_TIME_DIFFERENCE = 10;
  3819. gameEvents.enabled = {
  3820. smelting: true
  3821. , chopping: true
  3822. , harvest: true
  3823. , boat: true
  3824. , battle: true
  3825. , brewing: true
  3826. , market: true
  3827. , map: true
  3828. //, essence: true
  3829. , rocket: true
  3830. , wind: true
  3831. , perk: true
  3832. };
  3833. var lastTimestamp = new Map();
  3834.  
  3835. function notifyTabClickable(title, body, icon, tabKey, whenActive)
  3836. {
  3837. if (whenActive === void 0)
  3838. {
  3839. whenActive = false;
  3840. }
  3841. var now = (new Date).getTime();
  3842. var timeDiff = now - (lastTimestamp.get(title) || 0);
  3843. if (timeDiff < MIN_TIME_DIFFERENCE * 1e3)
  3844. {
  3845. return;
  3846. }
  3847. var promise = notifications.event(title
  3848. , {
  3849. body: body
  3850. , icon: 'images/' + icon
  3851. , whenActive: whenActive
  3852. , onclick: function ()
  3853. {
  3854. var tabNames = tabKey.split('.');
  3855. win.openTab(tabNames[0]);
  3856. if (tabNames.length > 1)
  3857. {
  3858. win.openSubTab(tabNames[1]);
  3859. }
  3860. }
  3861. });
  3862. if (promise)
  3863. {
  3864. lastTimestamp.set(title, now);
  3865. }
  3866. }
  3867.  
  3868. function observeTimer(k, fn)
  3869. {
  3870. observer.add(k, function (key, oldValue, newValue)
  3871. {
  3872. if (oldValue > 0 && newValue == 0)
  3873. {
  3874. fn(key, oldValue, newValue);
  3875. }
  3876. });
  3877. }
  3878.  
  3879. function smelting()
  3880. {
  3881. observeTimer('smeltingPercD', function (key, oldValue, newValue)
  3882. {
  3883. if (!gameEvents.enabled.smelting || !settings.getSub(settings.KEY.showNotifications, 'smelting'))
  3884. {
  3885. return;
  3886. }
  3887. notifyTabClickable('Hot topic', 'Your smelting has finished.', getFurnaceLevelName() + 'Furnace.png', 'crafting');
  3888. });
  3889. }
  3890.  
  3891. function chopping()
  3892. {
  3893. observer.add([
  3894. 'treeStage1'
  3895. , 'treeStage2'
  3896. , 'treeStage3'
  3897. , 'treeStage4'
  3898. , 'treeStage5'
  3899. , 'treeStage6'
  3900. ], function (key, oldValue, newValue)
  3901. {
  3902. if (!gameEvents.enabled.chopping || !settings.getSub(settings.KEY.showNotifications, 'chopping'))
  3903. {
  3904. return;
  3905. }
  3906. if (newValue == 4)
  3907. {
  3908. notifyTabClickable('Wood you be mine?', 'One or more of your trees are fully grown and can be chopped.', 'icons/woodcutting.png', 'woodcutting');
  3909. }
  3910. });
  3911. }
  3912.  
  3913. function harvest()
  3914. {
  3915. observer.add([
  3916. 'farmingPatchStage1'
  3917. , 'farmingPatchStage2'
  3918. , 'farmingPatchStage3'
  3919. , 'farmingPatchStage4'
  3920. , 'farmingPatchStage5'
  3921. , 'farmingPatchStage6'
  3922. ], function (key, oldValue, newValue)
  3923. {
  3924. if (!gameEvents.enabled.harvest || !settings.getSub(settings.KEY.showNotifications, 'harvest'))
  3925. {
  3926. return;
  3927. }
  3928. if (newValue == 4)
  3929. {
  3930. notifyTabClickable('Green thumb', 'One or more of your crops is ready for harvest.', 'icons/watering-can.png', 'farming');
  3931. }
  3932. else if (newValue > 4)
  3933. {
  3934. notifyTabClickable('I didn\'t plant this', 'One or more of your crops died.', 'icons/watering-can.png', 'farming');
  3935. }
  3936. });
  3937. }
  3938.  
  3939. function boat()
  3940. {
  3941. var timerKeys = BOAT_LIST.map(function (boatKey)
  3942. {
  3943. return boatKey + 'Timer';
  3944. });
  3945. observeTimer(timerKeys, function (key, oldValue, newValue)
  3946. {
  3947. if (!gameEvents.enabled.boat || !settings.getSub(settings.KEY.showNotifications, 'boatReturned'))
  3948. {
  3949. return;
  3950. }
  3951. var boatKey = key.replace(/Timer$/, '');
  3952. notifyTabClickable('Fishy business', 'Your ' + split2Words(boatKey).toLowerCase() + ' returned from its trip.', boatKey + '.png',
  3953. (win.profileCookingTab)? 'cooking' : 'combat');
  3954. });
  3955. }
  3956.  
  3957. function battle()
  3958. {
  3959. observeTimer('combatGlobalCooldown', function (key, oldValue, newValue)
  3960. {
  3961. if (!gameEvents.enabled.battle || !settings.getSub(settings.KEY.showNotifications, 'heroReady'))
  3962. {
  3963. return;
  3964. }
  3965. notifyTabClickable('Ready to work', 'Your hero is eager to fight.', 'icons/combat.png', 'combat');
  3966. });
  3967. }
  3968.  
  3969. function brewing()
  3970. {
  3971. observeTimer([
  3972. 'barPotionTimer'
  3973. , 'seedPotionTimer'
  3974. , 'stardustPotionTimer'
  3975. , 'superStardustPotionTimer'
  3976. ], function (key, oldValue, newValue)
  3977. {
  3978. if (!gameEvents.enabled.brewing || !settings.getSub(settings.KEY.showNotifications, 'potionEffect'))
  3979. {
  3980. return;
  3981. }
  3982. var potionKey = key.replace(/Timer$/, '');
  3983. if (getGameValue(potionKey) > 0)
  3984. {
  3985. notifyTabClickable('Cheers!', 'You can drink another ' + split2Words(potionKey) + '.', key.replace(/Timer$/, '') + '.png', 'brewing');
  3986. }
  3987. });
  3988. }
  3989.  
  3990. function market()
  3991. {
  3992. var _refreshMarketSlot = win.refreshMarketSlot;
  3993. var lastCollectText = 0;
  3994. win.refreshMarketSlot = function (offerId, itemKey, amount, price, collectText, slotId, timeLeft)
  3995. {
  3996. var diff = collectText - lastCollectText;
  3997. lastCollectText = collectText;
  3998. if (gameEvents.enabled.market && settings.getSub(settings.KEY.showNotifications, 'itemsSold') && collectText > 0)
  3999. {
  4000. var soldAmount = diff / price;
  4001. var amountText = ['one (1)', 'two (2)', 'three (3)'][soldAmount - 1] || format.number(soldAmount);
  4002. var itemName = split2Words(itemKey).toLowerCase();
  4003. if (soldAmount > 1)
  4004. {
  4005. itemName = pluralize(itemName);
  4006. }
  4007. var textTemplate = function (itemText)
  4008. {
  4009. return "You've sold " + itemText + " to the market.";
  4010. };
  4011. if (amount > 0)
  4012. {
  4013. notifyTabClickable('Ka-ching', textTemplate(amountText + ' ' + itemName), 'icons/shop.png', 'playermarket');
  4014. }
  4015. else
  4016. {
  4017. notifyTabClickable('Sold out', textTemplate((soldAmount === 1 ? 'your' : 'all') + ' ' + amountText + ' ' + itemName), 'icons/shop.png', 'playermarket');
  4018. }
  4019. }
  4020. _refreshMarketSlot(offerId, itemKey, amount, price, collectText, slotId, timeLeft);
  4021. };
  4022. }
  4023.  
  4024. function gameValues()
  4025. {
  4026. observer.add('treasureMap', function (key, oldValue, newValue)
  4027. {
  4028. if (gameEvents.enabled.map && settings.getSub(settings.KEY.showNotifications, 'pirate') && oldValue < newValue)
  4029. {
  4030. notifyTabClickable('Arrrr!', 'Your pirate found a treasure map.', 'treasureMap.png', 'items');
  4031. }
  4032. });
  4033. observer.add('rocketMoonId', function (key, oldValue, newValue)
  4034. {
  4035. if (gameEvents.enabled.rocket && settings.getSub(settings.KEY.showNotifications, 'rocket'))
  4036. {
  4037. if (newValue > 0)
  4038. {
  4039. notifyTabClickable('One small step for a man...', 'Your rocket landed on the moon.', 'rocket.png', 'mining');
  4040. }
  4041. else if (oldValue < 0 && newValue === 0)
  4042. {
  4043. notifyTabClickable('Back home', 'Your rocket returned to earth.', 'rocket.png', 'mining');
  4044. }
  4045. }
  4046. });
  4047. var WIND_DESCRIPTION = [
  4048. 'The sea is sleeping like a baby'
  4049. , 'There is a slight breeze'
  4050. , 'A normal day on the sea'
  4051. , 'There is a storm coming'
  4052. , 'The sea is raging'
  4053. ];
  4054. var WIND_CATEGORY = ['none', 'low', 'medium', 'high', 'very high'];
  4055. var _setSailBoatWind = win.setSailBoatWind;
  4056. var oldValue = -1;
  4057. win.setSailBoatWind = function (windLevel)
  4058. {
  4059. _setSailBoatWind(windLevel);
  4060. var newValue = win.sailBoatWindGlobal;
  4061. if (oldValue !== -1
  4062. && oldValue !== newValue
  4063. && win.boundSailBoat > 0
  4064. && gameEvents.enabled.wind
  4065. && settings.getSub(settings.KEY.showNotifications, 'wind'))
  4066. {
  4067. var windText = (WIND_DESCRIPTION[win.sailBoatWindGlobal] || 'The wind is turning')
  4068. + ' (' + (WIND_CATEGORY[win.sailBoatWindGlobal] || 'level ' + win.sailBoatWindGlobal) + ' wind).';
  4069. notifyTabClickable('Wind of change', windText, 'sailBoat.png', 'combat');
  4070. }
  4071. oldValue = newValue;
  4072. };
  4073. // trigger getting the wind level once at page load
  4074. // so the script can distinguish between getting the wind initially and an actual wind change
  4075. win.processTab('combat');
  4076. // achievements (e.g. achBrewingEasyCompleted)
  4077. var achRegex = /^ach([A-Z][a-z]+)([A-Z][a-z]+)Completed$/;
  4078.  
  4079. function checkAchievement(key, oldValue, newValue)
  4080. {
  4081. if (gameEvents.enabled.perk && settings.getSub(settings.KEY.showNotifications, 'perk') && oldValue < newValue)
  4082. {
  4083. var match = key.match(/^ach([A-Z][a-z]+)([A-Z][a-z]+)Completed$/);
  4084. var skillName = match[1].toLowerCase();
  4085. var difficulty = match[2].toLowerCase();
  4086. notifyTabClickable('New perk unlocked', 'You completed the ' + difficulty + ' ' + skillName + ' achievement set.', 'achievementBook.png', 'achievements');
  4087. }
  4088. }
  4089. for (var _i = 0, _a = win.jsItemArray; _i < _a.length; _i++)
  4090. {
  4091. var key = _a[_i];
  4092. if (achRegex.test(key))
  4093. {
  4094. observer.add(key, checkAchievement);
  4095. }
  4096. }
  4097. var stardustEl = document.querySelector('span[data-item-display="stardust"]');
  4098. var parent = stardustEl && stardustEl.parentElement;
  4099. if (stardustEl && parent)
  4100. {
  4101. 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");
  4102. var changeEl_1 = document.createElement('span');
  4103. changeEl_1.className = 'hide';
  4104. changeEl_1.id = 'stardust-change';
  4105. parent.appendChild(changeEl_1);
  4106. var HIDE_AFTER_TICKS_1 = 5;
  4107. var ticksSinceSdChange_1 = HIDE_AFTER_TICKS_1;
  4108. var sdDiff_1 = 0;
  4109. observer.add('stardust', function (key, oldValue, newValue)
  4110. {
  4111. sdDiff_1 = Math.max(newValue - oldValue, 0);
  4112. if (sdDiff_1 > 0)
  4113. {
  4114. ticksSinceSdChange_1 = 0;
  4115. }
  4116. });
  4117. observer.addTick(function ()
  4118. {
  4119. var show = settings.get(settings.KEY.showSdChange) && ticksSinceSdChange_1 < HIDE_AFTER_TICKS_1;
  4120. changeEl_1.classList[show ? 'remove' : 'add']('hide');
  4121. ticksSinceSdChange_1++;
  4122. var diff = ticksSinceSdChange_1 > 1 ? 0 : sdDiff_1;
  4123. var sign = diff > 0 ? '+' : PLUS_MINUS_SIGN;
  4124. changeEl_1.textContent = '(' + sign + format.number(diff) + ')';
  4125. });
  4126. }
  4127. }
  4128.  
  4129. function init()
  4130. {
  4131. smelting();
  4132. chopping();
  4133. harvest();
  4134. boat();
  4135. battle();
  4136. brewing();
  4137. market();
  4138. gameValues();
  4139. }
  4140. gameEvents.init = init;
  4141. })(gameEvents || (gameEvents = {}));
  4142.  
  4143. /**
  4144. * hide crafting recipes of lower tiers or of maxed machines
  4145. */
  4146. var crafting;
  4147. (function (crafting)
  4148. {
  4149. crafting.name = 'crafting';
  4150. /**
  4151. * hide crafted recipes
  4152. */
  4153. function setRecipeVisibility(key, visible)
  4154. {
  4155. var recipeRow = document.getElementById('crafting-' + key);
  4156. if (recipeRow)
  4157. {
  4158. recipeRow.style.display = (!settings.get(settings.KEY.hideCraftingRecipes) || visible) ? '' : 'none';
  4159. }
  4160. }
  4161.  
  4162. function hideLeveledRecipes(max, getKey, init)
  4163. {
  4164. if (init === void 0)
  4165. {
  4166. init = false;
  4167. }
  4168. var keys2Observe = [];
  4169. var maxLevel = 0;
  4170. for (var i = max - 1; i >= 0; i--)
  4171. {
  4172. var level = i + 1;
  4173. var key = getKey(i);
  4174. var boundKey = getBoundKey(key);
  4175. keys2Observe.push(key);
  4176. keys2Observe.push(boundKey);
  4177. if (getGameValue(key) > 0 || getGameValue(boundKey) > 0)
  4178. {
  4179. maxLevel = Math.max(maxLevel, level);
  4180. }
  4181. setRecipeVisibility(key, level > maxLevel);
  4182. }
  4183. if (init)
  4184. {
  4185. observer.add(keys2Observe, function ()
  4186. {
  4187. return hideLeveledRecipes(max, getKey, false);
  4188. });
  4189. }
  4190. }
  4191.  
  4192. function hideToolRecipe(key, init)
  4193. {
  4194. if (init === void 0)
  4195. {
  4196. init = false;
  4197. }
  4198. var emptyKey = getTierKey(key, 0);
  4199. var keys2Observe = [emptyKey];
  4200. var hasTool = getGameValue(emptyKey) > 0;
  4201. for (var i = 0; i < TIER_LEVELS.length; i++)
  4202. {
  4203. var boundKey = getBoundKey(getTierKey(key, i));
  4204. hasTool = hasTool || getGameValue(boundKey) > 0;
  4205. keys2Observe.push(boundKey);
  4206. }
  4207. setRecipeVisibility(emptyKey, !hasTool);
  4208. if (init)
  4209. {
  4210. observer.add(keys2Observe, function ()
  4211. {
  4212. return hideToolRecipe(key, false);
  4213. });
  4214. }
  4215. }
  4216.  
  4217. function hideRecipe(key, init)
  4218. {
  4219. if (init === void 0)
  4220. {
  4221. init = false;
  4222. }
  4223. var info = RECIPE_MAX.crafting[key];
  4224. var maxValue = typeof info.max === 'function' ? info.max() : info.max;
  4225. var boundKey = getBoundKey(key);
  4226. var unbound = getGameValue(key);
  4227. var bound = getGameValue(boundKey);
  4228. var extra = (info.extraKeys || []).map(function (k)
  4229. {
  4230. return getGameValue(k);
  4231. }).reduce(function (p, c)
  4232. {
  4233. return p + c;
  4234. }, 0);
  4235. setRecipeVisibility(key, maxValue - (bound + unbound + extra) > 0);
  4236. if (init)
  4237. {
  4238. observer.add([key, boundKey], function ()
  4239. {
  4240. return hideRecipe(key, false);
  4241. });
  4242. }
  4243. }
  4244. /**
  4245. * hide useless items
  4246. */
  4247. function setItemVisibility(key, visible)
  4248. {
  4249. var itemBox = document.getElementById('item-box-' + key);
  4250. if (itemBox)
  4251. {
  4252. itemBox.style.display = getGameValue(key) > 0 && (!settings.get(settings.KEY.hideUselessItems) || visible) ? '' : 'none';
  4253. }
  4254. }
  4255.  
  4256. function hideLeveledItems(max, getKey, init)
  4257. {
  4258. if (init === void 0)
  4259. {
  4260. init = false;
  4261. }
  4262. var keys2Observe = [];
  4263. var maxLevel = 0;
  4264. for (var i = max - 1; i >= 0; i--)
  4265. {
  4266. var level = i + 1;
  4267. var key = getKey(i);
  4268. var boundKey = getBoundKey(key);
  4269. keys2Observe.push(key);
  4270. keys2Observe.push(boundKey);
  4271. if (getGameValue(boundKey) > 0)
  4272. {
  4273. maxLevel = Math.max(maxLevel, level);
  4274. }
  4275. setItemVisibility(key, level > maxLevel);
  4276. }
  4277. if (init)
  4278. {
  4279. observer.add(keys2Observe, function ()
  4280. {
  4281. return hideLeveledItems(max, getKey, false);
  4282. });
  4283. }
  4284. }
  4285.  
  4286. function hideItem(key, hideInfo, init)
  4287. {
  4288. if (init === void 0)
  4289. {
  4290. init = false;
  4291. }
  4292. var maxValue = typeof hideInfo.max === 'function' ? hideInfo.max() : hideInfo.max;
  4293. var boundKey = getBoundKey(key);
  4294. var bound = getGameValue(boundKey);
  4295. var extra = (hideInfo.extraKeys || []).map(function (k)
  4296. {
  4297. return getGameValue(k);
  4298. }).reduce(function (p, c)
  4299. {
  4300. return p + c;
  4301. }, 0);
  4302. setItemVisibility(key, (bound + extra) < maxValue);
  4303. if (init)
  4304. {
  4305. observer.add([key, boundKey], function ()
  4306. {
  4307. return hideItem(key, hideInfo, false);
  4308. });
  4309. }
  4310. }
  4311.  
  4312. function init()
  4313. {
  4314. function processRecipes(init)
  4315. {
  4316. if (init === void 0)
  4317. {
  4318. init = false;
  4319. }
  4320. // furnace
  4321. hideLeveledRecipes(FURNACE_LEVELS.length, function (i)
  4322. {
  4323. return FURNACE_LEVELS[i] + 'Furnace';
  4324. }, init);
  4325. // oil storage
  4326. hideLeveledRecipes(OIL_STORAGE_SIZES.length, function (i)
  4327. {
  4328. return 'oilStorage' + (i + 1);
  4329. }, init);
  4330. // oven recipes
  4331. hideLeveledRecipes(OVEN_LEVELS.length, function (i)
  4332. {
  4333. return OVEN_LEVELS[i] + 'Oven';
  4334. }, init);
  4335. // tools
  4336. for (var _i = 0, TIER_ITEMS_1 = TIER_ITEMS; _i < TIER_ITEMS_1.length; _i++)
  4337. {
  4338. var tool = TIER_ITEMS_1[_i];
  4339. hideToolRecipe(tool, init);
  4340. }
  4341. // other stuff
  4342. for (var key in RECIPE_MAX.crafting)
  4343. {
  4344. hideRecipe(key, init);
  4345. }
  4346. if (init)
  4347. {
  4348. settings.observe(settings.KEY.hideCraftingRecipes, function ()
  4349. {
  4350. return processRecipes(false);
  4351. });
  4352. }
  4353. }
  4354. processRecipes(true);
  4355. var _processCraftingTab = win.processCraftingTab;
  4356. win.processCraftingTab = function ()
  4357. {
  4358. var reinit = !!win.refreshLoadCraftingTable;
  4359. _processCraftingTab();
  4360. if (reinit)
  4361. {
  4362. processRecipes(false);
  4363. }
  4364. };
  4365.  
  4366. function processItems(init)
  4367. {
  4368. if (init === void 0)
  4369. {
  4370. init = false;
  4371. }
  4372. // furnace
  4373. hideLeveledItems(FURNACE_LEVELS.length, function (i)
  4374. {
  4375. return FURNACE_LEVELS[i] + 'Furnace';
  4376. }, init);
  4377. // oil storage
  4378. hideLeveledItems(OIL_STORAGE_SIZES.length, function (i)
  4379. {
  4380. return 'oilStorage' + (i + 1);
  4381. }, init);
  4382. // oven recipes
  4383. hideLeveledItems(OVEN_LEVELS.length, function (i)
  4384. {
  4385. return OVEN_LEVELS[i] + 'Oven';
  4386. }, init);
  4387. // other stuff
  4388. for (var key in RECIPE_MAX.crafting)
  4389. {
  4390. hideItem(key, RECIPE_MAX.crafting[key], init);
  4391. }
  4392. if (init)
  4393. {
  4394. settings.observe(settings.KEY.hideUselessItems, function ()
  4395. {
  4396. return processItems(false);
  4397. });
  4398. }
  4399. }
  4400. processItems(true);
  4401. }
  4402. crafting.init = init;
  4403. })(crafting || (crafting = {}));
  4404.  
  4405. /**
  4406. * improve item boxes
  4407. */
  4408. var itemBoxes;
  4409. (function (itemBoxes)
  4410. {
  4411. itemBoxes.name = 'itemBoxes';
  4412.  
  4413. function hideNumberInItemBox(key, setVisibility)
  4414. {
  4415. if (setVisibility === void 0)
  4416. {
  4417. setVisibility = false;
  4418. }
  4419. var itemBox = document.getElementById('item-box-' + key);
  4420. if (!itemBox)
  4421. {
  4422. return;
  4423. }
  4424. var numberElement = itemBox.querySelector('span[data-item-display]');
  4425. if (!numberElement)
  4426. {
  4427. return;
  4428. }
  4429. numberElement.classList.add('number-caption');
  4430. if (setVisibility)
  4431. {
  4432. numberElement.classList.remove('hide');
  4433. numberElement.classList.add('hidden');
  4434. }
  4435. else
  4436. {
  4437. numberElement.classList.remove('hidden');
  4438. numberElement.classList.add('hide');
  4439. }
  4440. }
  4441.  
  4442. function addSpan2ItemBox(key, replace, setVisibility)
  4443. {
  4444. if (replace === void 0)
  4445. {
  4446. replace = true;
  4447. }
  4448. if (setVisibility === void 0)
  4449. {
  4450. setVisibility = false;
  4451. }
  4452. if (replace)
  4453. {
  4454. hideNumberInItemBox(key, setVisibility);
  4455. }
  4456. var itemBox = document.getElementById('item-box-' + key);
  4457. if (!itemBox)
  4458. {
  4459. return;
  4460. }
  4461. var span = document.createElement('span');
  4462. span.className = 'caption';
  4463. itemBox.appendChild(span);
  4464. return span;
  4465. }
  4466.  
  4467. function addCaptionStyle()
  4468. {
  4469. var CLASS_NAME = 'show-captions';
  4470. 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");
  4471.  
  4472. function updateBodyClass()
  4473. {
  4474. var show = settings.get(settings.KEY.showCaptions);
  4475. document.body.classList[show ? 'add' : 'remove'](CLASS_NAME);
  4476. }
  4477. updateBodyClass();
  4478. settings.observe(settings.KEY.showCaptions, function ()
  4479. {
  4480. return updateBodyClass();
  4481. });
  4482. }
  4483.  
  4484. function setOilPerSecond(span, oil)
  4485. {
  4486. span.innerHTML = "+ " + format.number(oil) + " L/s <img src=\"images/oil.png\" class=\"image-icon-20\">";
  4487. }
  4488. // show capacity of furnace
  4489. function addFurnaceCaption()
  4490. {
  4491. for (var i = 0; i < FURNACE_LEVELS.length; i++)
  4492. {
  4493. var key = FURNACE_LEVELS[i] + 'Furnace';
  4494. var boundKey = getBoundKey(key);
  4495. var capacitySpan = addSpan2ItemBox(boundKey);
  4496. if (capacitySpan)
  4497. {
  4498. capacitySpan.classList.add('capacity');
  4499. capacitySpan.textContent = 'Capacity: ' + format.number(win.getFurnaceCapacity(boundKey), true);
  4500. }
  4501. }
  4502. // charcoal foundry
  4503. var foundryCapacitySpan = addSpan2ItemBox('charcoalFoundry');
  4504. if (foundryCapacitySpan)
  4505. {
  4506. foundryCapacitySpan.classList.add('capacity');
  4507. foundryCapacitySpan.textContent = 'Capacity: 100';
  4508. }
  4509. }
  4510. // show oil cap of oil storage
  4511. function addOilStorageCaption()
  4512. {
  4513. for (var i = 0; i < OIL_STORAGE_SIZES.length; i++)
  4514. {
  4515. var key = 'oilStorage' + (i + 1);
  4516. var capSpan = addSpan2ItemBox(getBoundKey(key));
  4517. if (capSpan)
  4518. {
  4519. capSpan.classList.add('oil-cap');
  4520. capSpan.textContent = 'Oil cap: ' + format.number(OIL_STORAGE_SIZES[i], true);
  4521. }
  4522. }
  4523. }
  4524. var oilPipeOrbKey = 'boundBlueOilPipeOrb';
  4525.  
  4526. function setOilPipeCaption(span)
  4527. {
  4528. setOilPerSecond(span, 50 + win.achMiningEasyCompleted * 50 + getGameValue(oilPipeOrbKey) * 100);
  4529. }
  4530. function setTombKeys(span, key)
  4531. {
  4532. span.style = 'color: #470058';
  4533. span.innerHTML = format.number(key);
  4534. }
  4535. function addTombKeyCaption()
  4536. {
  4537. addStyle("\n#item-box-faradoxsCrystalCharged,\n#item-box-darkFaradoxsCrystalCharged\n{\n\tposition: relative;\n}\nspan.caption.tombKey\n{\n\tfont-size: 19px;\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 80px;\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");
  4538. var tpl = document.createElement('templateWrapper');
  4539. 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";
  4540. var shadowDrop = tpl.firstElementChild;
  4541. document.body.appendChild(shadowDrop);
  4542. var crystalChargedSpan = addSpan2ItemBox('faradoxsCrystalCharged');
  4543. if (crystalChargedSpan)
  4544. {
  4545. crystalChargedSpan.classList.add('tombKey');
  4546. var totalKeys = win.tombKeyTotal;
  4547. setTombKeys(crystalChargedSpan, totalKeys);
  4548. observer.add(crystalChargedSpan, function ()
  4549. {
  4550. return setTombKeys(crystalChargedSpan, totalKeys);
  4551. });
  4552. }
  4553. var darkCrystalChargedSpan = addSpan2ItemBox('darkFaradoxsCrystalCharged');
  4554. if (darkCrystalChargedSpan)
  4555. {
  4556. darkCrystalChargedSpan.classList.add('tombKey');
  4557. var totalKeys = win.darkTombKeyTotal;
  4558. setTombKeys(darkCrystalChargedSpan, totalKeys);
  4559. observer.add(darkCrystalChargedSpan, function ()
  4560. {
  4561. return setTombKeys(darkCrystalChargedSpan, totalKeys);
  4562. });
  4563. }
  4564. }
  4565. // show oil per second
  4566. function addOilCaption()
  4567. {
  4568. addStyle("\n#item-box-boundCharcoalFactory,\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");
  4569. var tpl = document.createElement('templateWrapper');
  4570. 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";
  4571. var shadowDrop = tpl.firstElementChild;
  4572. document.body.appendChild(shadowDrop);
  4573. var handheldOilSpan = addSpan2ItemBox('handheldOilPump', true, true);
  4574. if (handheldOilSpan)
  4575. {
  4576. handheldOilSpan.classList.add('oil');
  4577. setOilPerSecond(handheldOilSpan, 1 * win.miner);
  4578. observer.add('miner', function ()
  4579. {
  4580. return setOilPerSecond(handheldOilSpan, 1 * win.miner);
  4581. });
  4582. }
  4583. var oilPipeSpan = addSpan2ItemBox('boundOilPipe', true, true);
  4584. if (oilPipeSpan)
  4585. {
  4586. oilPipeSpan.classList.add('oil');
  4587. setOilPipeCaption(oilPipeSpan);
  4588. observer.add(oilPipeOrbKey, function ()
  4589. {
  4590. return setOilPipeCaption(oilPipeSpan);
  4591. });
  4592. }
  4593. var charcoalFactorySpan = addSpan2ItemBox('boundCharcoalFactory');
  4594. var charcoalFactoryOilGain = (boundRedCharcoalFactoryOrb) ? 600 : 300;
  4595. if (charcoalFactorySpan)
  4596. {
  4597. charcoalFactorySpan.classList.add('oil');
  4598. setOilPerSecond(charcoalFactorySpan, charcoalFactoryOilGain);
  4599. observer.add(charcoalFactorySpan, function ()
  4600. {
  4601. return setOilPerSecond(charcoalFactorySpan, charcoalFactoryOilGain);
  4602. });
  4603. }
  4604. // add pump jack oil display
  4605. var pumpjackSpan = addSpan2ItemBox('boundPumpjacks', false);
  4606. var totalOilPumpjacks = win.boundPumpjacks * 10;
  4607. var pumpjackOilGain = (achMiningHardCompleted) ? (totalOilPumpjacks * 2) : totalOilPumpjacks;
  4608. if (pumpjackSpan)
  4609. {
  4610. pumpjackSpan.classList.add('oil');
  4611. var setCaption_1 = function ()
  4612. {
  4613. return setOilPerSecond(pumpjackSpan, pumpjackOilGain);
  4614. };
  4615. setCaption_1();
  4616. observer.add('boundPumpjacks', function ()
  4617. {
  4618. return setCaption_1();
  4619. });
  4620. }
  4621. // add number of workers as caption to oil factory
  4622. var workerSpan = addSpan2ItemBox('boundOilFactory');
  4623. if (workerSpan)
  4624. {
  4625. var setCaption_2 = function ()
  4626. {
  4627. return workerSpan.textContent = 'Workers: ' + format.number(win.oilFactoryCheapWorkers, true);
  4628. };
  4629. setCaption_2();
  4630. observer.add('oilFactoryCheapWorkers', function ()
  4631. {
  4632. return setCaption_2();
  4633. });
  4634. }
  4635. var factoryOilSpan = addSpan2ItemBox('boundOilFactory');
  4636. var factoryOilGain = (boundGreenOilFactoryOrb) ? win.oilFactoryCheapWorkers * 2 :win.oilFactoryCheapWorkers;
  4637. if (factoryOilSpan)
  4638. {
  4639. factoryOilSpan.classList.add('oil');
  4640. var setCaption_3 = function ()
  4641. {
  4642. return setOilPerSecond(factoryOilSpan, factoryOilGain);
  4643. };
  4644. setCaption_3();
  4645. observer.add('oilFactoryCheapWorkers', function ()
  4646. {
  4647. return setCaption_3();
  4648. });
  4649. }
  4650. }
  4651.  
  4652. function addWandCaption()
  4653. {
  4654. for (var i = 0; i < WAND_LEVELS.length; i++)
  4655. {
  4656. var level = WAND_LEVELS[i];
  4657. var key = level + 'Wand';
  4658. var wandSpan = addSpan2ItemBox(key);
  4659. if (wandSpan)
  4660. {
  4661. wandSpan.textContent = capitalize(level) + ' Wand';
  4662. }
  4663. }
  4664. }
  4665.  
  4666. function addVariousCaptions()
  4667. {
  4668. var key2Name = {
  4669. 'achievementBook': 'Achievements'
  4670. , 'emptyAnvil': 'Anvil'
  4671. , 'tap': 'Tree Tap'
  4672. , 'farmer': 'Farmer'
  4673. , 'spellScroll1': 'Spell Scroll 1'
  4674. , 'boundRuniteSpyglass': 'Spyglass'
  4675. , 'bobsUncle': "Bob's Uncle"
  4676. , 'boundBoatingDock': 'Boating Dock'
  4677. , 'lumberjack': 'Lumberjack'
  4678. , 'handheldOilPump': 'Oil Pump'
  4679. , 'boundCharcoalFactory': 'Ch.coal Factory'
  4680. , 'boundNeedle': 'Needle'
  4681. , 'vendor': 'Vendor'
  4682. , 'boundOilStorage1': 'Oil Storage 1'
  4683. , 'boundOilStorage2': 'Oil Storage 2'
  4684. , 'boundOilStorage3': 'Oil Storage 3'
  4685. , 'boundOilStorage4': 'Oil Storage 4'
  4686. , 'boundOilStorage5': 'Oil Storage 5'
  4687. , 'boundOilStorage6': 'Oil Storage 6'
  4688. , 'boundOilStorage7': 'Oil Storage 7'
  4689. , 'boundOilPipe': 'Oil Pipe'
  4690. , 'meditate1': 'Meditate level 1'
  4691. , 'meditate2': 'Meditate level 2'
  4692. , 'meditate3': 'Meditate level 3'
  4693. , 'meditate4': 'Meditate level 4'
  4694. , 'meditate5': 'Meditate level 5'
  4695. , 'meditate6': 'Meditate level 6'
  4696. , 'meditate7': 'Meditate level 7'
  4697. , 'meditate8': 'Meditate level 8'
  4698. , 'meditate9': 'Meditate level 9'
  4699. , 'gardener': 'Gardener'
  4700. , 'planter': 'Planter'
  4701. , 'boundBrewingKit': 'Brewing Kit'
  4702. , 'cooksBook': 'Cooks Book'
  4703. , 'cooksPage': 'Cooks Page'
  4704. , 'combatDropTable': 'Loot Table'
  4705. , 'magicBook': 'Spell Book'
  4706. , 'magicShop': 'Magic Shop'
  4707. , 'crackedSpinningWheel': 'Cracked Wheel'
  4708. , 'woodenSpinningWheel': 'Wooden Wheel'
  4709. , 'oakSpinningWheel': 'Oak Wheel'
  4710. , 'willowSpinningWheel': 'Willow Wheel'
  4711. , 'mapleSpinningWheel': 'Maple Wheel'
  4712. , 'stardustSpinningWheel': 'Stardust Wheel'
  4713. , 'strangeSpinningWheel': 'Strange Wheel'
  4714. , 'ancientSpinningWheel': 'Ancient Wheel'
  4715. };
  4716. for (var key in key2Name)
  4717. {
  4718. var span = addSpan2ItemBox(key);
  4719. if (span)
  4720. {
  4721. span.textContent = key2Name[key];
  4722. }
  4723. }
  4724. }
  4725. // show current tier
  4726. function addTierCaption()
  4727. {
  4728. 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");
  4729.  
  4730. function addOrbObserver(key, spanList)
  4731. {
  4732. var boundOrbKey = getBoundKey('Blue' + capitalize(key) + 'Orb');
  4733.  
  4734. function checkOrb()
  4735. {
  4736. var classAction = getGameValue(boundOrbKey) > 0 ? 'add' : 'remove';
  4737. for (var _i = 0, spanList_1 = spanList; _i < spanList_1.length; _i++)
  4738. {
  4739. var span = spanList_1[_i];
  4740. span.classList[classAction]('orb');
  4741. }
  4742. }
  4743. checkOrb();
  4744. observer.add(boundOrbKey, function ()
  4745. {
  4746. return checkOrb();
  4747. });
  4748. }
  4749. var remainingOrbItems = ORB_ITEMS;
  4750. for (var _i = 0, TIER_ITEMS_2 = TIER_ITEMS; _i < TIER_ITEMS_2.length; _i++)
  4751. {
  4752. var tierItem = TIER_ITEMS_2[_i];
  4753. var isBindable = TIER_ITEMS_NOT_BINDABLE.indexOf(tierItem) === -1;
  4754. var spanList = [];
  4755. for (var i = 0; i < TIER_LEVELS.length; i++)
  4756. {
  4757. var key = getTierKey(tierItem, i);
  4758. var toolKey = isBindable ? getBoundKey(key) : key;
  4759. var tierSpan = addSpan2ItemBox(toolKey);
  4760. if (tierSpan)
  4761. {
  4762. tierSpan.classList.add('tier');
  4763. tierSpan.textContent = TIER_NAMES[i];
  4764. spanList.push(tierSpan);
  4765. }
  4766. }
  4767. var orbIndex = remainingOrbItems.indexOf(tierItem);
  4768. if (orbIndex !== -1)
  4769. {
  4770. addOrbObserver(tierItem, spanList);
  4771. remainingOrbItems.splice(orbIndex, 1);
  4772. }
  4773. }
  4774. for (var _a = 0, remainingOrbItems_1 = remainingOrbItems; _a < remainingOrbItems_1.length; _a++)
  4775. {
  4776. var itemKey = remainingOrbItems_1[_a];
  4777. var captionSpan = document.querySelector('#item-box-' + getBoundKey(itemKey) + ' > span:last-of-type');
  4778. if (!captionSpan)
  4779. {
  4780. continue;
  4781. }
  4782. addOrbObserver(itemKey, [captionSpan]);
  4783. }
  4784. }
  4785. var boatTimerKeys = BOAT_LIST.map(function (boatKey)
  4786. {
  4787. return boatKey + 'Timer';
  4788. });
  4789.  
  4790. function checkBoat(span, timerKey, init)
  4791. {
  4792. if (init === void 0)
  4793. {
  4794. init = false;
  4795. }
  4796. var isInTransit = getGameValue(timerKey) > 0;
  4797. var otherInTransit = boatTimerKeys.some(function (k)
  4798. {
  4799. return k != timerKey && getGameValue(k) > 0 && !boundBoatingDock;
  4800. });
  4801. span.textContent = isInTransit ? 'In transit' : 'Ready';
  4802. span.style.visibility = otherInTransit ? 'hidden' : '';
  4803. var parent = span.parentElement;
  4804. parent.style.opacity = otherInTransit ? '.5' : '';
  4805. if (init)
  4806. {
  4807. observer.add(boatTimerKeys, function ()
  4808. {
  4809. return checkBoat(span, timerKey, false);
  4810. });
  4811. }
  4812. }
  4813. // show boat progress
  4814. function addBoatCaption()
  4815. {
  4816. addStyle("\n#item-box-boundSailBoat.item-box > span[data-item-display] + span + span\n{\n\tdisplay: none;\n}\n\t\t");
  4817. for (var i = 0; i < BOAT_LIST.length; i++)
  4818. {
  4819. var span = addSpan2ItemBox(getBoundKey(BOAT_LIST[i]));
  4820. if (span)
  4821. {
  4822. checkBoat(span, boatTimerKeys[i], true);
  4823. }
  4824. }
  4825. }
  4826. // show bonemeal
  4827. function addBonemealCaption()
  4828. {
  4829. var noBonemealSpan = addSpan2ItemBox('boundBonemealBin');
  4830. if (!noBonemealSpan)
  4831. {
  4832. return;
  4833. }
  4834. noBonemealSpan.textContent = 'Bonemeal: 0';
  4835. var bonemealSpan = addSpan2ItemBox('boundFilledBonemealBin');
  4836. if (!bonemealSpan)
  4837. {
  4838. return;
  4839. }
  4840. bonemealSpan.dataset.itemDisplay = 'bonemeal';
  4841. bonemealSpan.textContent = format.number(win.bonemeal);
  4842. var captionSpan = document.createElement('span');
  4843. captionSpan.className = 'caption';
  4844. captionSpan.textContent = 'Bonemeal: ';
  4845. bonemealSpan.parentElement.insertBefore(captionSpan, bonemealSpan);
  4846. }
  4847.  
  4848. function warningBeforeSellingGems()
  4849. {
  4850. var _sellNPCItemDialogue = win.sellNPCItemDialogue;
  4851. win.sellNPCItemDialogue = function (item, amount)
  4852. {
  4853. if (item == 'sapphire' || item == 'emerald' || item == 'ruby' || item == 'diamond' || item == 'bloodDiamond')
  4854. {
  4855. var itemName = key2Name(amount == 1 ? item : item.replace(/y$/, 'ie') + 's', true);
  4856. if (amount == 0
  4857. || !win.confirm('Gems are precious and rare. Please consider carefully:\nDo you really want to sell ' + amount + ' ' + itemName + '?'))
  4858. {
  4859. return;
  4860. }
  4861. }
  4862. else if (item == 'logs' || item == 'oakLogs' || item == 'willowLogs' || item == 'mapleLogs' || item == 'stardustLogs' || item == 'strangeLogs' || item == 'ancientLogs')
  4863. {
  4864. var itemName = key2Name(amount == 1 ? item.replace(/s$/, '') : item, true);
  4865. if (amount == 0
  4866. || !win.confirm('Logs are time consuming to collect. Please consider carefully:\nDo you really want to sell ' + amount + ' ' + itemName + '?'))
  4867. {
  4868. return;
  4869. }
  4870. }
  4871. _sellNPCItemDialogue(item, amount);
  4872. };
  4873. }
  4874.  
  4875. function addWikiaLinks()
  4876. {
  4877. var WIKIA_CLASS = 'wikia-links';
  4878. 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");
  4879.  
  4880. function setWikiaLinksVisibility(init)
  4881. {
  4882. if (init === void 0)
  4883. {
  4884. init = false;
  4885. }
  4886. var show = settings.get(settings.KEY.wikiaLinks);
  4887. document.body.classList[show ? 'add' : 'remove'](WIKIA_CLASS);
  4888. if (init)
  4889. {
  4890. settings.observe(settings.KEY.wikiaLinks, function ()
  4891. {
  4892. return setWikiaLinksVisibility();
  4893. });
  4894. }
  4895. }
  4896. setWikiaLinksVisibility(true);
  4897. var boxes = document.getElementsByClassName('item-box');
  4898.  
  4899. function disableClickPropagation(el)
  4900. {
  4901. el.addEventListener('click', function (event)
  4902. {
  4903. event.stopPropagation();
  4904. });
  4905. }
  4906. for (var i = 0; i < boxes.length; i++)
  4907. {
  4908. var box = boxes.item(i);
  4909. var key = box.id.replace(/^item-box-/, '');
  4910. var linkArea = document.createElement('a');
  4911. linkArea.className = 'wikia-link';
  4912. linkArea.href = getWikiaLink(key);
  4913. linkArea.target = '_blank';
  4914. disableClickPropagation(linkArea);
  4915. box.appendChild(linkArea);
  4916. var tooltipEl = ensureTooltip('wikiLink', linkArea);
  4917. if (tooltipEl.innerHTML === '')
  4918. {
  4919. tooltipEl.innerHTML = "Click to open the wikia page about this item.";
  4920. }
  4921. }
  4922. }
  4923.  
  4924. function init()
  4925. {
  4926. addCaptionStyle();
  4927. addFurnaceCaption();
  4928. //addOilStorageCaption();
  4929. addOilCaption();
  4930. addTombKeyCaption();
  4931. addWandCaption();
  4932. addVariousCaptions();
  4933. addTierCaption();
  4934. addBoatCaption();
  4935. addBonemealCaption();
  4936. warningBeforeSellingGems();
  4937. addWikiaLinks();
  4938. }
  4939. itemBoxes.init = init;
  4940. })(itemBoxes || (itemBoxes = {}));
  4941.  
  4942. /**
  4943. * add new chat
  4944. */
  4945. var chat;
  4946. (function (chat)
  4947. {
  4948. chat.name = 'chat';
  4949. // min time difference between repeated messages to not be considered as spam
  4950. var MIN_DIFF_REPEATED_MSG = 5e3;
  4951. var KEYWORD_LIST_KEY = 'keywordList';
  4952. chat.keywordList = store.has(KEYWORD_LIST_KEY) ? store.get(KEYWORD_LIST_KEY) : [];
  4953. var CHAT_HISTORY_KEY = 'chatHistory';
  4954. var MAX_CHAT_HISTORY_LENGTH = 100;
  4955. var PM_HISTORY_KEY = 'pmHistory';
  4956. var MAX_PM_HISTORY_LENGTH = 50;
  4957. var Type;
  4958. (function (Type)
  4959. {
  4960. Type[Type["reload"] = -1] = "reload";
  4961. Type[Type["normal"] = 0] = "normal";
  4962. Type[Type["pmReceived"] = 1] = "pmReceived";
  4963. Type[Type["pmSent"] = 2] = "pmSent";
  4964. Type[Type["serverMsg"] = 3] = "serverMsg";
  4965. })(Type || (Type = {}));;
  4966. var Tag;
  4967. (function (Tag)
  4968. {
  4969. Tag[Tag["none"] = 0] = "none";
  4970. Tag[Tag["donor"] = 1] = "donor";
  4971. Tag[Tag["contributor"] = 2] = "contributor";
  4972. Tag[Tag["mod"] = 3] = "mod";
  4973. Tag[Tag["dev"] = 4] = "dev";
  4974. Tag[Tag["server"] = 5] = "server";
  4975. })(Tag || (Tag = {}));;
  4976. /**
  4977. * The chunk hiding starts with at least 10 chunks.
  4978. * So there are at least
  4979. * (chunkHidingMinChunks-1) * msgChunkSize + 1 = 9 * 100 + 1 = 901
  4980. * messages before the chunk hiding mechanism starts.
  4981. */
  4982. var CHUNK_HIDING_MIN_CHUNKS = 10;
  4983. var MSG_CHUNK_SIZE = 100;
  4984. var RELOADED_CHAT_DATA = {
  4985. timestamp: 0
  4986. , username: ''
  4987. , userlevel: 0
  4988. , icon: 0
  4989. , tag: 0
  4990. , type: Type.reload
  4991. , msg: '[...]'
  4992. };
  4993. var CHAT_BOX_ID = 'div-chat';
  4994. var DEFAULT_CHAT_DIV_ID = 'div-chat-area';
  4995. var GENERAL_CHAT_DIV_ID = 'div-chat-general';
  4996. var PM_CHAT_TAB_PREFIX = 'tab-chat-pm-';
  4997. var PM_CHAT_DIV_PREFIX = 'div-chat-pm-';
  4998. var CHAT_TABS_ID = 'chat-tabs';
  4999. var CHAT_INPUT_ID = 'chat-input-text';
  5000. var CHAT_CLASS = 'div-chat-area';
  5001. var COLORIZE_CLASS = 'colorize';
  5002. var SpecialTab;
  5003. (function (SpecialTab)
  5004. {
  5005. SpecialTab[SpecialTab["default"] = 0] = "default";
  5006. SpecialTab[SpecialTab["general"] = 1] = "general";
  5007. SpecialTab[SpecialTab["filler"] = 2] = "filler";
  5008. })(SpecialTab || (SpecialTab = {}));;
  5009. var CHAT_SPECIAL_TAB_ID = (_a = {}
  5010. , _a[SpecialTab.default] = 'tab-chat-default'
  5011. , _a[SpecialTab.general] = 'tab-chat-general'
  5012. , _a[SpecialTab.filler] = 'tab-chat-filler'
  5013. , _a);
  5014. var CONTEXTMENU_ID = 'player-contextmenu';
  5015. var CHAT_ICONS = [
  5016. {
  5017. key: ''
  5018. , title: ''
  5019. }
  5020. , {
  5021. key: 'halloween2015'
  5022. , title: 'Halloween Gamer (2015)'
  5023. }
  5024. , {
  5025. key: 'christmas2015'
  5026. , title: 'Chirstmas Gamer (2015)'
  5027. }
  5028. , {
  5029. key: 'easter2016'
  5030. , title: 'Easter Gamer (2016)'
  5031. }
  5032. , {
  5033. key: 'halloween2016'
  5034. , title: 'Halloween Gamer (2016)'
  5035. }
  5036. , {
  5037. key: 'christmas2016'
  5038. , title: 'Chirstmas Gamer (2016)'
  5039. }
  5040. , {
  5041. key: 'dh1Max'
  5042. , title: 'DH1 Pro'
  5043. }
  5044. , {
  5045. key: 'hardcore'
  5046. , title: 'Hardcore Player'
  5047. }
  5048. , {
  5049. key: 'quest'
  5050. , title: 'Questmaster'
  5051. }
  5052. , {
  5053. key: 'maxMining'
  5054. , title: 'Mastery in mining'
  5055. }
  5056. , {
  5057. key: 'maxCrafting'
  5058. , title: 'Mastery in crafting'
  5059. }
  5060. , {
  5061. key: 'maxWC'
  5062. , title: 'Mastery in woodcutting'
  5063. }
  5064. , {
  5065. key: 'maxFarming'
  5066. , title: 'Mastery in farming'
  5067. }
  5068. , {
  5069. key: 'maxBrewing'
  5070. , title: 'Mastery in brewing'
  5071. }
  5072. , {
  5073. key: 'maxCombat'
  5074. , title: 'Mastery in combat'
  5075. }
  5076. , {
  5077. key: 'maxMagic'
  5078. , title: 'Mastery in magic'
  5079. }
  5080. , {
  5081. key: 'maxFishing'
  5082. , title: 'Mastery in fishing'
  5083. }
  5084. , {
  5085. key: 'maxCooking'
  5086. , title: 'Mastery in cooking'
  5087. }
  5088. , {
  5089. key: 'maxLevel'
  5090. , title: 'Mastery of all skills'
  5091. }
  5092. , {
  5093. key: 'birdcage'
  5094. , title: 'Stole a birdcage'
  5095. }
  5096. , {
  5097. key: 'achievement'
  5098. , title: 'Achievement Hunter'
  5099. }
  5100. , {
  5101. key: 'pinkPartyHat'
  5102. , title: 'Pink Party Hat'
  5103. }
  5104. , {
  5105. key: 'redPartyHat'
  5106. , title: 'Red Party Hat'
  5107. }
  5108. , {
  5109. key: 'greenPartyHat'
  5110. , title: 'Green Party Hat'
  5111. }
  5112. , {
  5113. key: 'yellowPartyHat'
  5114. , title: 'Yellow Party Hat'
  5115. }
  5116. , {
  5117. key: 'whitePartyHat'
  5118. , title: 'White Party Hat'
  5119. }
  5120. , {
  5121. key: 'bluePartyHat'
  5122. , title: 'Blue Party Hat'
  5123. }];
  5124. var getUnknownChatIcon = function (icon)
  5125. {
  5126. return {
  5127. key: 'unknown'
  5128. , title: ''
  5129. , img: '<img src="images/chat-icons/' + icon + '.png" class="image-icon-20" />'
  5130. };
  5131. };
  5132. var CHAT_TAGS = [
  5133. null
  5134. , {
  5135. key: 'donor'
  5136. , name: ''
  5137. }
  5138. , {
  5139. key: 'contributor'
  5140. , name: 'Contributor'
  5141. }
  5142. , {
  5143. key: 'mod'
  5144. , name: 'Moderator'
  5145. }
  5146. , {
  5147. key: 'dev'
  5148. , name: 'Dev'
  5149. }
  5150. , {
  5151. key: 'yell'
  5152. , name: 'Server Message'
  5153. }
  5154. ];
  5155. var LOCALE = 'en-US';
  5156. var LOCALE_OPTIONS = {
  5157. hour12: false
  5158. , year: 'numeric'
  5159. , month: 'long'
  5160. , day: 'numeric'
  5161. , hour: '2-digit'
  5162. , minute: '2-digit'
  5163. , second: '2-digit'
  5164. };
  5165. // game commands
  5166. var COMMANDS = [
  5167. 'pm'
  5168. , 'mute'
  5169. , 'clear'
  5170. , 'ipmute'
  5171. ];
  5172. var CLEAR_CMD = 'clear';
  5173. var TUTORIAL_CMD = 'tutorial';
  5174. // load chat history
  5175. var chatHistory = store.get(CHAT_HISTORY_KEY) || [];
  5176. var pmHistory = store.get(PM_HISTORY_KEY) || [];
  5177. // store chat colors for each user
  5178. var user2Color;
  5179. var usedColors;
  5180. // reserve color for special messages (e.g. server messages): white
  5181. var reservedColors = ['#ffffff'];
  5182. // message chunks
  5183. var msgChunkMap = new Map();
  5184. // for adding elements at startup
  5185. var chatboxFragments = new Map();
  5186. var chatInitialized = false;
  5187. // find index of last message which is not a pm
  5188. var isLastMsgNotReload = false;
  5189. for (var i = chatHistory.length - 1; i >= 0; i--)
  5190. {
  5191. if (!isDataPM(chatHistory[i]))
  5192. {
  5193. isLastMsgNotReload = chatHistory[i].type != Type.reload;
  5194. break;
  5195. }
  5196. }
  5197. // insert a placeholder for a reloaded chat
  5198. if (isLastMsgNotReload)
  5199. {
  5200. RELOADED_CHAT_DATA.timestamp = (new Date()).getTime();
  5201. chatHistory.push(RELOADED_CHAT_DATA);
  5202. }
  5203.  
  5204. function isMuted(user)
  5205. {
  5206. return user !== win.username
  5207. && win.mutedPeople.some(function (name)
  5208. {
  5209. return user.indexOf(name) > -1;
  5210. });
  5211. }
  5212.  
  5213. function isSpam(data)
  5214. {
  5215. // allow all own messages, messages from contributors, mods, devs and all server messages
  5216. if (data.username === win.username || data.tag != Tag.none)
  5217. {
  5218. return false;
  5219. }
  5220. /**
  5221. * get last message of current user
  5222. */
  5223. var historyIndex = chatHistory.indexOf(data);
  5224. if (historyIndex == -1)
  5225. {
  5226. historyIndex = chatHistory.length;
  5227. }
  5228. var lastData = null;
  5229. for (var i = historyIndex - 1; i >= 0 && (lastData === null); i--)
  5230. {
  5231. var dataBefore = chatHistory[i];
  5232. if (dataBefore.username === data.username)
  5233. {
  5234. lastData = dataBefore;
  5235. }
  5236. }
  5237. /**
  5238. * compare message and don't allow the same message twice
  5239. */
  5240. if (lastData
  5241. && lastData.msg === data.msg
  5242. && (data.timestamp - lastData.timestamp) < MIN_DIFF_REPEATED_MSG)
  5243. {
  5244. return true;
  5245. }
  5246. return false;
  5247. }
  5248.  
  5249. function saveKeywordList()
  5250. {
  5251. store.set(KEYWORD_LIST_KEY, chat.keywordList);
  5252. }
  5253.  
  5254. function addKeyword(keyword)
  5255. {
  5256. if (keyword !== '' && chat.keywordList.indexOf(keyword) === -1)
  5257. {
  5258. chat.keywordList.push(keyword);
  5259. saveKeywordList();
  5260. return true;
  5261. }
  5262. return false;
  5263. }
  5264. chat.addKeyword = addKeyword;
  5265.  
  5266. function removeKeyword(keyword)
  5267. {
  5268. var index = chat.keywordList.indexOf(keyword);
  5269. if (index !== -1)
  5270. {
  5271. chat.keywordList.splice(index, 1);
  5272. saveKeywordList();
  5273. return true;
  5274. }
  5275. return false;
  5276. }
  5277. chat.removeKeyword = removeKeyword;
  5278.  
  5279. function handleScrolling(chatbox)
  5280. {
  5281. if (win.isAutoScrolling)
  5282. {
  5283. setTimeout(function ()
  5284. {
  5285. return chatbox.scrollTop = chatbox.scrollHeight;
  5286. });
  5287. }
  5288. }
  5289. // for chat messages which arrive before DOMContentLoaded and can not be displayed since the DOM isn't ready
  5290. function processChatData(username, iconString, tagString, msg, isPM)
  5291. {
  5292. var tag = parseInt(tagString, 10);
  5293. var userlevel = 0;
  5294. var type = Type.normal;
  5295. if (isPM == 1)
  5296. {
  5297. var match = msg.match(/^\s*\[(PM from|Sent to) ([A-Za-z0-9_ ]+)\]: (.+?)\s*$/) || ['', '', username, msg];
  5298. type = match[1] == 'Sent to' ? Type.pmSent : Type.pmReceived;
  5299. username = match[2];
  5300. if (username !== 'sexy_squid')
  5301. {
  5302. username = username.replace(/_/g, ' ');
  5303. }
  5304. msg = match[3];
  5305. }
  5306. else if (tag == Tag.server)
  5307. {
  5308. type = Type.serverMsg;
  5309. }
  5310. else
  5311. {
  5312. var match = msg.match(/^\s*\((\d+)\): (.+?)\s*$/);
  5313. if (match)
  5314. {
  5315. userlevel = parseInt(match[1], 10);
  5316. msg = match[2];
  5317. }
  5318. else
  5319. {
  5320. userlevel = win.getGlobalLevel();
  5321. }
  5322. }
  5323. // unlinkify when using DH2QoL to store the plain message
  5324. if (win.addToChatBox.toString().includes('linkify(arguments[3])'))
  5325. {
  5326. msg = msg.replace(/<a href='([^']+)' target='_blank'>\1<\/a>/ig, '$1');
  5327. }
  5328. if (type == Type.pmSent)
  5329. {
  5330. // turn some critical characters into HTML entities
  5331. msg = msg.replace(/[<>]/g, function (char)
  5332. {
  5333. return '&#' + char.charCodeAt(0) + ';';
  5334. });
  5335. }
  5336. return {
  5337. timestamp: now()
  5338. , username: username
  5339. , userlevel: userlevel
  5340. , icon: parseInt(iconString, 10)
  5341. , tag: tag
  5342. , type: type
  5343. , msg: msg
  5344. };
  5345. }
  5346.  
  5347. function saveChatHistory()
  5348. {
  5349. store.set(CHAT_HISTORY_KEY, chatHistory);
  5350. }
  5351.  
  5352. function savePmHistory()
  5353. {
  5354. store.set(PM_HISTORY_KEY, pmHistory);
  5355. }
  5356.  
  5357. function add2ChatHistory(data)
  5358. {
  5359. if (data.type === Type.pmReceived
  5360. || data.type === Type.pmSent)
  5361. {
  5362. pmHistory.push(data);
  5363. pmHistory = pmHistory.slice(-MAX_PM_HISTORY_LENGTH);
  5364. savePmHistory();
  5365. }
  5366. else
  5367. {
  5368. chatHistory.push(data);
  5369. chatHistory = chatHistory.slice(-MAX_CHAT_HISTORY_LENGTH);
  5370. saveChatHistory();
  5371. }
  5372. }
  5373.  
  5374. function username2Id(username)
  5375. {
  5376. return username.replace(/ /g, '_');
  5377. }
  5378.  
  5379. function setNewCounter(tab, num, force)
  5380. {
  5381. if (force === void 0)
  5382. {
  5383. force = false;
  5384. }
  5385. var panel = getChatPanel(tab.dataset.username || '');
  5386. if (force
  5387. || !tab.classList.contains('selected')
  5388. || !win.isAutoScrolling && panel.scrollHeight > panel.scrollTop + panel.offsetHeight)
  5389. {
  5390. tab.dataset.new = num.toString();
  5391. }
  5392. }
  5393.  
  5394. function incrementNewCounter(tab)
  5395. {
  5396. setNewCounter(tab, parseInt(tab.dataset.new || '0', 10) + 1);
  5397. }
  5398.  
  5399. function getChatTab(username, specialTab)
  5400. {
  5401. var id = (specialTab != null)
  5402. ? CHAT_SPECIAL_TAB_ID[specialTab]
  5403. : PM_CHAT_TAB_PREFIX + username2Id(username);
  5404. var tab = document.getElementById(id);
  5405. if (!tab)
  5406. {
  5407. tab = document.createElement('div');
  5408. tab.className = 'chat-tab';
  5409. if (specialTab != null)
  5410. {
  5411. tab.classList.add(SpecialTab[specialTab]);
  5412. }
  5413. tab.id = id;
  5414. tab.dataset.username = username;
  5415. setNewCounter(tab, 0, true);
  5416. if (username.length > 0)
  5417. {
  5418. tab.textContent = username;
  5419. // thanks /u/Spino-Prime for pointing out this was missing
  5420. var closeSpan = document.createElement('span');
  5421. closeSpan.className = 'close';
  5422. tab.appendChild(closeSpan);
  5423. }
  5424. var chatTabs = document.getElementById(CHAT_TABS_ID);
  5425. var filler = chatTabs.querySelector('.filler');
  5426. if (filler)
  5427. {
  5428. chatTabs.insertBefore(tab, filler);
  5429. }
  5430. else
  5431. {
  5432. chatTabs.appendChild(tab);
  5433. }
  5434. }
  5435. return tab;
  5436. }
  5437.  
  5438. function getChatPanel(username)
  5439. {
  5440. var id = username == '' ? GENERAL_CHAT_DIV_ID : PM_CHAT_DIV_PREFIX + username2Id(username);
  5441. var panel = document.getElementById(id);
  5442. if (!panel)
  5443. {
  5444. panel = document.createElement('div');
  5445. panel.setAttribute('disabled', 'disabled');
  5446. panel.id = id;
  5447. panel.className = CHAT_CLASS;
  5448. var defaultChat = document.getElementById(DEFAULT_CHAT_DIV_ID);
  5449. var height = defaultChat.style.height;
  5450. panel.style.height = height;
  5451. var chatDiv = defaultChat.parentElement;
  5452. chatDiv.insertBefore(panel, defaultChat);
  5453. }
  5454. return panel;
  5455. }
  5456.  
  5457. function changeChatTab(oldTab, newTab)
  5458. {
  5459. if (oldTab)
  5460. {
  5461. oldTab.classList.remove('selected');
  5462. var oldChatPanel = void 0;
  5463. if (oldTab.classList.contains('default'))
  5464. {
  5465. oldChatPanel = document.getElementById(DEFAULT_CHAT_DIV_ID);
  5466. }
  5467. else
  5468. {
  5469. oldChatPanel = getChatPanel(oldTab.dataset.username || '');
  5470. }
  5471. oldChatPanel.classList.remove('selected');
  5472. }
  5473. newTab.classList.add('selected');
  5474. setNewCounter(newTab, 0, true);
  5475. var newChatPanel;
  5476. if (newTab.classList.contains('default'))
  5477. {
  5478. newChatPanel = document.getElementById(DEFAULT_CHAT_DIV_ID);
  5479. }
  5480. else
  5481. {
  5482. newChatPanel = getChatPanel(newTab.dataset.username || '');
  5483. }
  5484. newChatPanel.classList.add('selected');
  5485. var toUsername = newTab.dataset.username;
  5486. var newTextPlaceholder = toUsername == '' ? win.username + ':' : 'PM to ' + toUsername + ':';
  5487. document.getElementById(CHAT_INPUT_ID).placeholder = newTextPlaceholder;
  5488. handleScrolling(newChatPanel);
  5489. }
  5490.  
  5491. function clearChat(username)
  5492. {
  5493. if (username === '')
  5494. {
  5495. // clean server chat
  5496. chatHistory = [];
  5497. saveChatHistory();
  5498. }
  5499. else
  5500. {
  5501. // delete pms stored for that user
  5502. for (var i = 0; i < pmHistory.length; i++)
  5503. {
  5504. var data = pmHistory[i];
  5505. if (data.username == username)
  5506. {
  5507. pmHistory.splice(i, 1);
  5508. i--;
  5509. }
  5510. }
  5511. savePmHistory();
  5512. }
  5513. // clear pm-chat panel
  5514. var panel = getChatPanel(username);
  5515. while (panel.children.length > 0)
  5516. {
  5517. panel.removeChild(panel.children[0]);
  5518. }
  5519. msgChunkMap.delete(username);
  5520. return panel;
  5521. }
  5522.  
  5523. function closeChatTab(username)
  5524. {
  5525. // clear pm-chat panel and remove message-history
  5526. clearChat(username);
  5527. // remove pm-tab (and change tab if necessary)
  5528. var selectedTab = getSelectedTab();
  5529. var tab2Close = getChatTab(username, null);
  5530. if (selectedTab.dataset.username == username)
  5531. {
  5532. var generalTab = getChatTab('', SpecialTab.general);
  5533. changeChatTab(tab2Close, generalTab);
  5534. }
  5535. var tabContainer = tab2Close.parentElement;
  5536. tabContainer.removeChild(tab2Close);
  5537. }
  5538.  
  5539. function isDataPM(data)
  5540. {
  5541. return data.type === Type.pmSent || data.type === Type.pmReceived;
  5542. }
  5543.  
  5544. function colorizeMsg(username)
  5545. {
  5546. if (username == '')
  5547. {
  5548. return null;
  5549. }
  5550. if (!user2Color.has(username))
  5551. {
  5552. var color = void 0;
  5553. do {
  5554. var colorizer = settings.getSub(settings.KEY.colorizeChat, 'colorizer');
  5555. if (colorizer == 1)
  5556. {
  5557. color = colorGenerator.getRandom(
  5558. {
  5559. luminosity: 'light'
  5560. });
  5561. }
  5562. else if (colorizer == 2)
  5563. {
  5564. color = colorGenerator.getRandom(
  5565. {
  5566. luminosity: 'dark'
  5567. });
  5568. }
  5569. else
  5570. {
  5571. color = colorGenerator.getEquallyDistributed();
  5572. }
  5573. } while (usedColors.has(color));
  5574. user2Color.set(username, color);
  5575. usedColors.add(color);
  5576. addStyle("\n#" + CHAT_BOX_ID + "." + COLORIZE_CLASS + " .chat-msg[data-username=\"" + username + "\"]\n{\n\tbackground-color: " + color + ";\n}\n\t\t\t", 'name-color');
  5577. }
  5578. return user2Color.get(username);
  5579. }
  5580.  
  5581. function createMessageSegment(data)
  5582. {
  5583. var isThisPm = isDataPM(data);
  5584. var msgUsername = data.type === Type.pmSent ? win.username : data.username;
  5585. var history = isThisPm ? pmHistory : chatHistory;
  5586. var historyIndex = history.indexOf(data);
  5587. var isSameUser = null;
  5588. var isSameTime = null;
  5589. for (var i = historyIndex - 1; i >= 0 && (isSameUser === null || isSameTime === null); i--)
  5590. {
  5591. var dataBefore = history[i];
  5592. if (isThisPm === isDataPM(dataBefore))
  5593. {
  5594. if (isSameUser === null)
  5595. {
  5596. var beforeUsername = dataBefore.type == Type.pmSent ? win.username : dataBefore.username;
  5597. isSameUser = beforeUsername === msgUsername;
  5598. }
  5599. if (dataBefore.type != Type.reload)
  5600. {
  5601. isSameTime = Math.floor(data.timestamp / 1000 / 60) - Math.floor(dataBefore.timestamp / 1000 / 60) === 0;
  5602. }
  5603. }
  5604. }
  5605. var d = new Date(data.timestamp);
  5606. var hour = (d.getHours() < 10 ? '0' : '') + d.getHours();
  5607. var minute = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes();
  5608. var icon = CHAT_ICONS[data.icon] || getUnknownChatIcon(data.icon);
  5609. var tag = CHAT_TAGS[data.tag] ||
  5610. {
  5611. key: ''
  5612. , name: ''
  5613. };
  5614. var formattedMsg = data.msg
  5615. .replace(/<a href='(.+?)' target='_blank'>\1<\/a>/g, '$1')
  5616. .replace(/(https?:\/\/[^\s"<>]+)/g, '<a target="_blank" href="$1">$1</a>');
  5617. colorizeMsg(msgUsername);
  5618. var msgTitle = data.type == Type.reload ? 'Chat loaded on ' + d.toLocaleString(LOCALE, LOCALE_OPTIONS) : '';
  5619. var user = data.type === Type.serverMsg ? 'Server Message' : msgUsername;
  5620. var levelAppendix = data.type == Type.normal ? ' (' + data.userlevel + ')' : '';
  5621. var userTitle = data.tag != Tag.server ? tag.name : '';
  5622. return "<span class=\"chat-msg\" data-type=\"" + data.type + "\" data-tag=\"" + tag.key + "\" data-username=\"" + msgUsername + "\">"
  5623. + ("<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>")
  5624. + ("<span class=\"user\" data-name=\"" + msgUsername + "\" data-same-user=\"" + isSameUser + "\">")
  5625. + ("<span class=\"icon " + icon.key + "\" title=\"" + icon.title + "\"></span>")
  5626. + ("<span class=\"name chat-tag-" + tag.key + "\" title=\"" + userTitle + "\">" + user + levelAppendix + ":</span>")
  5627. + "</span>"
  5628. + ("<span class=\"msg\" title=\"" + msgTitle + "\">" + formattedMsg + "</span>")
  5629. + "</span>";
  5630. }
  5631.  
  5632. function add2Chat(data)
  5633. {
  5634. if (!chatInitialized)
  5635. {
  5636. return;
  5637. }
  5638. var isThisPm = isDataPM(data);
  5639. // don't mute pms (you can just ignore pm-tab if you like)
  5640. if (!isThisPm && isMuted(data.username))
  5641. {
  5642. return;
  5643. }
  5644. var userKey = isThisPm ? data.username : '';
  5645. if (isThisPm)
  5646. {
  5647. win.lastPMUser = data.username;
  5648. }
  5649. // username is 3-12 characters long
  5650. var chatbox = getChatPanel(userKey);
  5651. var msgChunk = msgChunkMap.get(userKey);
  5652. if (!msgChunk || msgChunk.children.length >= MSG_CHUNK_SIZE)
  5653. {
  5654. msgChunk = document.createElement('div');
  5655. msgChunk.className = 'msg-chunk';
  5656. msgChunkMap.set(userKey, msgChunk);
  5657. if (chatboxFragments != null)
  5658. {
  5659. if (!chatboxFragments.has(userKey))
  5660. {
  5661. chatboxFragments.set(userKey, document.createDocumentFragment());
  5662. }
  5663. chatboxFragments.get(userKey).appendChild(msgChunk);
  5664. }
  5665. else
  5666. {
  5667. chatbox.appendChild(msgChunk);
  5668. }
  5669. }
  5670. var tmp = document.createElement('templateWrapper');
  5671. tmp.innerHTML = createMessageSegment(data);
  5672. msgChunk.appendChild(tmp.children[0]);
  5673. handleScrolling(chatbox);
  5674. // add delay because handleScrolling is will set scrollTop delayed
  5675. setTimeout(function ()
  5676. {
  5677. var chatTab = getChatTab(userKey, isThisPm ? null : SpecialTab.general);
  5678. incrementNewCounter(chatTab);
  5679. });
  5680. }
  5681.  
  5682. function applyChatStyle()
  5683. {
  5684. 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.chat-msg .user .icon.pinkPartyHat::before\t{ background-image: url('images/chat-icons/21.png'); }\n.chat-msg .user .icon.redPartyHat::before\t{ background-image: url('images/chat-icons/22.png'); }\n.chat-msg .user .icon.greenPartyHat::before\t{ background-image: url('images/chat-icons/23.png'); }\n.chat-msg .user .icon.yellowPartyHat::before\t{ background-image: url('images/chat-icons/24.png'); }\n.chat-msg .user .icon.whitePartyHat::before\t{ background-image: url('images/chat-icons/25.png'); }\n.chat-msg .user .icon.bluePartyHat::before\t{ background-image: url('images/chat-icons/26.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");
  5685. }
  5686.  
  5687. function initColorizer(init)
  5688. {
  5689. if (init === void 0)
  5690. {
  5691. init = false;
  5692. }
  5693. var usernameList = user2Color && Array.from(user2Color.keys()) || [];
  5694. user2Color = new Map();
  5695. usedColors = new Set();
  5696. for (var _i = 0, reservedColors_1 = reservedColors; _i < reservedColors_1.length; _i++)
  5697. {
  5698. var color = reservedColors_1[_i];
  5699. usedColors.add(color);
  5700. }
  5701. var colorStyle = getStyle('name-color');
  5702. colorStyle.innerHTML = '';
  5703. for (var _a = 0, usernameList_1 = usernameList; _a < usernameList_1.length; _a++)
  5704. {
  5705. var username = usernameList_1[_a];
  5706. colorizeMsg(username);
  5707. }
  5708. if (init)
  5709. {
  5710. settings.observeSub(settings.KEY.colorizeChat, 'colorizer', function ()
  5711. {
  5712. return initColorizer();
  5713. });
  5714. }
  5715. }
  5716.  
  5717. function addIntelligentScrolling()
  5718. {
  5719. // add checkbox instead of button for toggling auto scrolling
  5720. var btn = document.querySelector('input[value="Toggle Autoscroll"]');
  5721. var btnParent = btn.parentElement;
  5722. var checkboxId = 'chat-toggle-autoscroll';
  5723. // create checkbox
  5724. var toggleCheckbox = document.createElement('input');
  5725. toggleCheckbox.type = 'checkbox';
  5726. toggleCheckbox.id = checkboxId;
  5727. toggleCheckbox.checked = true;
  5728. // create label
  5729. var toggleLabel = document.createElement('label');
  5730. toggleLabel.htmlFor = checkboxId;
  5731. toggleLabel.textContent = 'Autoscroll';
  5732. btnParent.insertBefore(toggleCheckbox, btn);
  5733. btnParent.insertBefore(toggleLabel, btn);
  5734. btn.style.display = 'none';
  5735. var chatArea = document.getElementById(GENERAL_CHAT_DIV_ID);
  5736. var showScrollTextTimeout = null;
  5737.  
  5738. function setAutoScrolling(value, full)
  5739. {
  5740. if (full === void 0)
  5741. {
  5742. full = false;
  5743. }
  5744. if (win.isAutoScrolling != value)
  5745. {
  5746. toggleCheckbox.checked = value;
  5747. win.isAutoScrolling = value;
  5748. var icon_2 = 'none';
  5749. var color_1 = value ? 'lime' : 'red';
  5750. var text_1 = (value ? 'En' : 'Dis') + 'abled' + (full ? ' Autoscroll' : '');
  5751. if (full)
  5752. {
  5753. if (showScrollTextTimeout)
  5754. {
  5755. win.clearTimeout(showScrollTextTimeout);
  5756. }
  5757. showScrollTextTimeout = win.setTimeout(function ()
  5758. {
  5759. return win.scrollText(icon_2, color_1, text_1);
  5760. }, 300);
  5761. }
  5762. else
  5763. {
  5764. win.scrollText(icon_2, color_1, text_1);
  5765. }
  5766. setNewCounter(getSelectedTab(), 0, true);
  5767. return true;
  5768. }
  5769. return false;
  5770. }
  5771. toggleCheckbox.addEventListener('change', function ()
  5772. {
  5773. setAutoScrolling(this.checked);
  5774. if (this.checked && settings.get(settings.KEY.intelligentScrolling))
  5775. {
  5776. chatArea.scrollTop = chatArea.scrollHeight - chatArea.clientHeight;
  5777. }
  5778. });
  5779. var placeholderTemplate = document.createElement('div');
  5780. placeholderTemplate.className = 'placeholder';
  5781. var childStore = new WeakMap();
  5782.  
  5783. function scrollHugeChat()
  5784. {
  5785. // # of children
  5786. var chunkNum = chatArea.children.length;
  5787. // start chunk hiding at a specific amount of chunks
  5788. if (chunkNum < CHUNK_HIDING_MIN_CHUNKS)
  5789. {
  5790. return;
  5791. }
  5792. var visibleTop = chatArea.scrollTop;
  5793. var visibleBottom = visibleTop + chatArea.clientHeight;
  5794. var referenceTop = visibleTop - win.innerHeight;
  5795. var referenceBottom = visibleBottom + win.innerHeight;
  5796. var top = 0;
  5797. // never hide the last element since its size may change at any time when a new message gets appended
  5798. for (var i = 0; i < chunkNum - 1; i++)
  5799. {
  5800. var child = chatArea.children[i];
  5801. var height = child.clientHeight;
  5802. var bottom = top + height;
  5803. var isVisible = top >= referenceTop && top <= referenceBottom
  5804. || bottom >= referenceTop && bottom <= referenceBottom
  5805. || top < referenceTop && bottom > referenceBottom;
  5806. var isPlaceholder = child.classList.contains('placeholder');
  5807. if (!isVisible && !isPlaceholder)
  5808. {
  5809. var newPlaceholder = placeholderTemplate.cloneNode(false);
  5810. newPlaceholder.style.height = height + 'px';
  5811. chatArea.replaceChild(newPlaceholder, child);
  5812. childStore.set(newPlaceholder, child);
  5813. }
  5814. else if (isVisible && isPlaceholder)
  5815. {
  5816. var oldChild = childStore.get(child);
  5817. chatArea.replaceChild(oldChild, child);
  5818. childStore.delete(child);
  5819. }
  5820. top = bottom;
  5821. }
  5822. }
  5823. var delayedScrollStart = null;
  5824. var delayedScrollTimeout = null;
  5825. // does not consider pm tabs; may be changed in a future version?
  5826. chatArea.addEventListener('scroll', function ()
  5827. {
  5828. if (settings.get(settings.KEY.intelligentScrolling))
  5829. {
  5830. var scrolled2Bottom = (chatArea.scrollTop + chatArea.clientHeight) >= chatArea.scrollHeight - 1;
  5831. setAutoScrolling(scrolled2Bottom, true);
  5832. }
  5833. var n = now();
  5834. if (delayedScrollStart == null)
  5835. {
  5836. delayedScrollStart = n;
  5837. }
  5838. if (delayedScrollStart + 300 > n)
  5839. {
  5840. if (delayedScrollTimeout)
  5841. {
  5842. win.clearTimeout(delayedScrollTimeout);
  5843. }
  5844. delayedScrollTimeout = win.setTimeout(function ()
  5845. {
  5846. delayedScrollStart = null;
  5847. delayedScrollTimeout = null;
  5848. scrollHugeChat();
  5849. }, 50);
  5850. }
  5851. });
  5852. }
  5853.  
  5854. function getSelectedTab()
  5855. {
  5856. return document.querySelector('#' + CHAT_TABS_ID + ' .chat-tab.selected');
  5857. }
  5858.  
  5859. function getSelectedTabUsername()
  5860. {
  5861. var selectedTab = getSelectedTab();
  5862. return selectedTab.dataset.username || '';
  5863. }
  5864.  
  5865. function clickChatTab(newTab)
  5866. {
  5867. var oldTab = getSelectedTab();
  5868. if (newTab == oldTab)
  5869. {
  5870. return;
  5871. }
  5872. changeChatTab(oldTab, newTab);
  5873. }
  5874.  
  5875. function clickCloseChatTab(tab)
  5876. {
  5877. var username = tab.dataset.username || '';
  5878. var chatPanel = getChatPanel(username);
  5879. if (chatPanel.children.length === 0
  5880. || confirm("Do you want to close the pm tab of \"" + username + "\"?"))
  5881. {
  5882. closeChatTab(username);
  5883. }
  5884. }
  5885.  
  5886. function checkSetting(init)
  5887. {
  5888. if (init === void 0)
  5889. {
  5890. init = false;
  5891. }
  5892. var enabled = settings.get(settings.KEY.useNewChat);
  5893. // dis-/enable chat tabs
  5894. var chatTabs = document.getElementById(CHAT_TABS_ID);
  5895. chatTabs.style.display = enabled ? '' : 'none';
  5896. // dis-/enable checkbox for intelligent scrolling
  5897. var intelScrollId = 'chat-toggle-intelligent-scroll';
  5898. var input = document.getElementById(intelScrollId);
  5899. if (input)
  5900. {
  5901. input.style.display = enabled ? '' : 'none';
  5902. }
  5903. var label = document.querySelector('label[for="' + intelScrollId + '"]');
  5904. if (label)
  5905. {
  5906. label.style.display = enabled ? '' : 'none';
  5907. }
  5908. // virtually click on a tab
  5909. var defaultTab = getChatTab('', SpecialTab.default);
  5910. var generalTab = getChatTab('', SpecialTab.general);
  5911. clickChatTab(enabled ? generalTab : defaultTab);
  5912. if (init)
  5913. {
  5914. settings.observe(settings.KEY.useNewChat, function ()
  5915. {
  5916. return checkSetting(false);
  5917. });
  5918. }
  5919. }
  5920.  
  5921. function addChatTabs()
  5922. {
  5923. var chatBoxArea = document.getElementById(CHAT_BOX_ID);
  5924. var chatTabs = document.createElement('div');
  5925. chatTabs.id = CHAT_TABS_ID;
  5926. chatTabs.addEventListener('click', function (event)
  5927. {
  5928. var newTab = event.target;
  5929. if (newTab.classList.contains('close'))
  5930. {
  5931. return clickCloseChatTab(newTab.parentElement);
  5932. }
  5933. if (!newTab.classList.contains('chat-tab') || newTab.classList.contains('filler'))
  5934. {
  5935. return;
  5936. }
  5937. clickChatTab(newTab);
  5938. });
  5939. chatBoxArea.appendChild(chatTabs);
  5940. // default tab (for disabled new chat)
  5941. getChatTab('', SpecialTab.default);
  5942. // general server chat
  5943. var generalTab = getChatTab('', SpecialTab.general);
  5944. generalTab.textContent = 'Server';
  5945. getChatPanel('');
  5946. getChatTab('', SpecialTab.filler);
  5947. var _sendChat = win.sendChat;
  5948. win.sendChat = function (inputEl)
  5949. {
  5950. var msg = inputEl.value;
  5951. var selectedTab = document.querySelector('.chat-tab.selected');
  5952. if (selectedTab.dataset.username != '' && msg[0] != '/')
  5953. {
  5954. inputEl.value = '/pm ' + (selectedTab.dataset.username || '').replace(/ /g, '_') + ' ' + msg;
  5955. }
  5956. _sendChat(inputEl);
  5957. };
  5958. }
  5959.  
  5960. function switch2PmTab(username)
  5961. {
  5962. if (settings.get(settings.KEY.useNewChat)){
  5963. var newTab = getChatTab(username, null);
  5964. clickChatTab(newTab);
  5965. }
  5966. }
  5967.  
  5968. function notifyPm(data)
  5969. {
  5970. notifications.event('Message from "' + data.username + '"'
  5971. , {
  5972. body: data.msg
  5973. , onclick: function ()
  5974. {
  5975. return switch2PmTab(data.username);
  5976. }
  5977. , whenActive: getSelectedTab().dataset.username != data.username
  5978. });
  5979. }
  5980.  
  5981. function checkMentionAndKeywords(data)
  5982. {
  5983. var lowerMsg = data.msg.toLowerCase();
  5984. var usernameRegex = new RegExp('\\b' + win.username + '\\b', 'i');
  5985. if (settings.getSub(settings.KEY.showNotifications, 'mention') && usernameRegex.test(lowerMsg))
  5986. // if (lowerMsg.indexOf(win.username) > -1)
  5987. {
  5988. notifications.event('You\'ve been mentioned'
  5989. , {
  5990. body: data.msg
  5991. });
  5992. }
  5993. var match = [];
  5994. for (var _i = 0, keywordList_1 = chat.keywordList; _i < keywordList_1.length; _i++)
  5995. {
  5996. var keyword = keywordList_1[_i];
  5997. var regex = new RegExp('\\b' + keyword + '\\b', 'i');
  5998. if (regex.test(lowerMsg))
  5999. // if (lowerMsg.indexOf(keyword) > -1)
  6000. {
  6001. match.push(keyword);
  6002. }
  6003. }
  6004. if (settings.getSub(settings.KEY.showNotifications, 'keyword') && match.length > 0)
  6005. {
  6006. notifications.event('Keyword: "' + match.join('", "') + '"'
  6007. , {
  6008. body: data.msg
  6009. });
  6010. }
  6011. }
  6012. var addToChatBox_ = null;
  6013.  
  6014. function newAddToChatBox(username, icon, tag, msg, isPM)
  6015. {
  6016. var data = processChatData(username, icon, tag, msg, isPM);
  6017. var isThisSpam = false;
  6018. if (isDataPM(data))
  6019. {
  6020. if (data.type == Type.pmSent)
  6021. {
  6022. switch2PmTab(data.username);
  6023. }
  6024. else
  6025. {
  6026. notifyPm(data);
  6027. }
  6028. }
  6029. else
  6030. {
  6031. isThisSpam = settings.get(settings.KEY.enableSpamDetection) && isSpam(data);
  6032. if (!isThisSpam && data.username != win.username)
  6033. {
  6034. // check mentioning and keywords only for non-pms and only for messages from other players
  6035. checkMentionAndKeywords(data);
  6036. }
  6037. }
  6038. if (isThisSpam)
  6039. {
  6040. console.info('detected spam:', data);
  6041. }
  6042. else
  6043. {
  6044. add2ChatHistory(data);
  6045. add2Chat(data);
  6046. }
  6047. var fn = addToChatBox_ == null ? win.addToChatBox : addToChatBox_;
  6048. fn(username, icon, tag, msg, isPM);
  6049. }
  6050. chat.newAddToChatBox = newAddToChatBox;
  6051.  
  6052. function openPmTab(username)
  6053. {
  6054. if (username == win.username || username == '')
  6055. {
  6056. return;
  6057. }
  6058. var userTab = getChatTab(username, null);
  6059. clickChatTab(userTab);
  6060. var input = document.getElementById(CHAT_INPUT_ID);
  6061. input.focus();
  6062. }
  6063.  
  6064. function newChat()
  6065. {
  6066. addChatTabs();
  6067. applyChatStyle();
  6068. initColorizer(true);
  6069. addToChatBox_ = win.addToChatBox;
  6070. win.addToChatBox = newAddToChatBox;
  6071. chatInitialized = true;
  6072. var chatbox = document.getElementById(CHAT_BOX_ID);
  6073. chatbox.addEventListener('click', function (event)
  6074. {
  6075. var target = event.target;
  6076. var userEl = target && target.parentElement;
  6077. if (!target || !userEl || !target.classList.contains('name') || !userEl.classList.contains('user'))
  6078. {
  6079. return;
  6080. }
  6081. if (userEl.dataset.sameUser != 'true')
  6082. {
  6083. openPmTab(userEl.dataset.name || '');
  6084. }
  6085. });
  6086. chatbox.addEventListener('mouseover', function (event)
  6087. {
  6088. var target = event.target;
  6089. if (!target.classList.contains('timestamp') || !target.dataset.timestamp)
  6090. {
  6091. return;
  6092. }
  6093. var timestamp = parseInt(target.dataset.timestamp || '0', 10);
  6094. target.dataset.fulltime = (new Date(timestamp)).toLocaleDateString(LOCALE, LOCALE_OPTIONS);
  6095. target.dataset.timestamp = '';
  6096. });
  6097. // add context menu
  6098. var contextmenu = document.createElement('ul');
  6099. contextmenu.id = CONTEXTMENU_ID;
  6100. contextmenu.style.display = 'none';
  6101. 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>";
  6102. document.body.appendChild(contextmenu);
  6103. win.$(contextmenu).menu(
  6104. {
  6105. items: '> :not(.ui-widget-header)'
  6106. });
  6107. var nameListEl = contextmenu.querySelector('.name');
  6108. var nameDivEl = nameListEl.firstElementChild;
  6109. var muteEl = contextmenu.querySelector('.mute');
  6110. var unmuteEl = contextmenu.querySelector('.unmute');
  6111. chatbox.addEventListener('contextmenu', function (event)
  6112. {
  6113. var target = event.target;
  6114. var userEl = target && target.parentElement;
  6115. if (!userEl || !userEl.classList.contains('user'))
  6116. {
  6117. return;
  6118. }
  6119. var username = userEl.dataset.name;
  6120. // ignore clicks on server messages or other special messages
  6121. if (!username || userEl.dataset.sameUser == 'true')
  6122. {
  6123. return;
  6124. }
  6125. contextmenu.style.left = event.clientX + 'px';
  6126. contextmenu.style.top = event.clientY + 'px';
  6127. contextmenu.style.display = '';
  6128. contextmenu.dataset.username = username;
  6129. nameDivEl.textContent = username;
  6130. var isMuted = win.mutedPeople.indexOf(username) !== -1;
  6131. muteEl.style.display = isMuted ? 'none' : '';
  6132. unmuteEl.style.display = isMuted ? '' : 'none';
  6133. event.stopPropagation();
  6134. event.preventDefault();
  6135. });
  6136. // add click listener for context menu and stop propagation
  6137. contextmenu.addEventListener('click', function (event)
  6138. {
  6139. var target = event.target;
  6140. event.stopPropagation();
  6141. while (target && target.id != CONTEXTMENU_ID && target.tagName != 'LI')
  6142. {
  6143. target = target.parentElement;
  6144. }
  6145. if (!target || target.id == CONTEXTMENU_ID)
  6146. {
  6147. return;
  6148. }
  6149. var username = contextmenu.dataset.username || '';
  6150. if (target.classList.contains('open-pm'))
  6151. {
  6152. openPmTab(username);
  6153. }
  6154. else if (target.classList.contains('stats'))
  6155. {
  6156. win.lookup(username);
  6157. }
  6158. else if (target.classList.contains('mute'))
  6159. {
  6160. if (username == '')
  6161. {
  6162. return;
  6163. }
  6164. win.mutedPeople.push(username);
  6165. win.scrollText('none', 'lime', '<em>' + username + '</em> muted');
  6166. }
  6167. else if (target.classList.contains('unmute'))
  6168. {
  6169. if (username == '')
  6170. {
  6171. return;
  6172. }
  6173. var index = win.mutedPeople.indexOf(username);
  6174. if (index !== -1)
  6175. {
  6176. win.mutedPeople.splice(index, 1);
  6177. }
  6178. win.scrollText('none', 'red', '<em>' + username + '</em> unmuted');
  6179. }
  6180. else
  6181. {
  6182. return;
  6183. }
  6184. contextmenu.style.display = 'none';
  6185. });
  6186. // add click listener to hide context menu
  6187. document.addEventListener('click', function (event)
  6188. {
  6189. if (contextmenu.style.display != 'none')
  6190. {
  6191. contextmenu.style.display = 'none';
  6192. }
  6193. });
  6194. win.addEventListener('contextmenu', function (event)
  6195. {
  6196. if (contextmenu.style.display != 'none')
  6197. {
  6198. contextmenu.style.display = 'none';
  6199. }
  6200. });
  6201. // handle settings
  6202. var showSettings = [settings.KEY.showTimestamps, settings.KEY.showIcons, settings.KEY.showTags];
  6203.  
  6204. function setShowSetting(key)
  6205. {
  6206. var enabled = settings.get(key);
  6207. chatbox.classList[enabled ? 'add' : 'remove'](settings.KEY[key]);
  6208. }
  6209. for (var _i = 0, showSettings_1 = showSettings; _i < showSettings_1.length; _i++)
  6210. {
  6211. var key = showSettings_1[_i];
  6212. setShowSetting(key);
  6213. settings.observe(key, function (k)
  6214. {
  6215. return setShowSetting(k);
  6216. });
  6217. }
  6218. }
  6219.  
  6220. function addCommandSuggester()
  6221. {
  6222. var input = document.getElementById(CHAT_INPUT_ID);
  6223. input.addEventListener('keyup', function (event)
  6224. {
  6225. if (event.key == 'Backspace' || event.key == 'Delete' || event.key == 'Enter' || event.key == 'Tab'
  6226. || input.selectionStart != input.selectionEnd
  6227. || input.selectionStart != input.value.length
  6228. || !input.value.startsWith('/'))
  6229. {
  6230. return;
  6231. }
  6232. var value = input.value.substr(1);
  6233. for (var _i = 0, COMMANDS_1 = COMMANDS; _i < COMMANDS_1.length; _i++)
  6234. {
  6235. var cmd = COMMANDS_1[_i];
  6236. if (cmd.startsWith(value))
  6237. {
  6238. input.value = '/' + cmd;
  6239. input.selectionStart = 1 + value.length;
  6240. input.selectionEnd = input.value.length;
  6241. break;
  6242. }
  6243. }
  6244. });
  6245. }
  6246.  
  6247. function addOwnCommands()
  6248. {
  6249. COMMANDS.push(TUTORIAL_CMD);
  6250.  
  6251. function processOwnCommands(value)
  6252. {
  6253. if (!value.startsWith('/'))
  6254. {
  6255. return value;
  6256. }
  6257. var msgPrefix = '/';
  6258. var msg = value.substr(1);
  6259. if (msg.startsWith('pm'))
  6260. {
  6261. var split = msg.split(' ');
  6262. msgPrefix = '/' + split.slice(0, 2).join(' ') + ' ';
  6263. msg = split.slice(2).join(' ');
  6264. }
  6265. if (msg.startsWith(CLEAR_CMD))
  6266. {
  6267. // clear current chat (pm chat, or general chat)
  6268. var username = getSelectedTabUsername();
  6269. clearChat(username);
  6270. }
  6271. else if (msg.startsWith(TUTORIAL_CMD))
  6272. {
  6273. // thanks aguyd (https://greasyfork.org/forum/profile/aguyd) for the idea
  6274. var name_2 = msg.substr(TUTORIAL_CMD.length).trim();
  6275. msgPrefix = '';
  6276. msg = 'https://www.reddit.com/r/DiamondHunt/comments/5vrufh/diamond_hunt_2_starter_faq/';
  6277. if (name_2.length != 0)
  6278. {
  6279. // maybe add '@' before the name?
  6280. msg = name_2 + ', ' + msg;
  6281. }
  6282. }
  6283. return msgPrefix + msg;
  6284. }
  6285. var _sendChat = win.sendChat;
  6286. win.sendChat = function (inputEl)
  6287. {
  6288. inputEl.value = processOwnCommands(inputEl.value);
  6289. _sendChat(inputEl);
  6290. };
  6291. }
  6292.  
  6293. function checkColorize(init)
  6294. {
  6295. if (init === void 0)
  6296. {
  6297. init = false;
  6298. }
  6299. var chatDiv = document.getElementById(CHAT_BOX_ID);
  6300. chatDiv.classList[settings.get(settings.KEY.colorizeChat) ? 'add' : 'remove'](COLORIZE_CLASS);
  6301. if (init)
  6302. {
  6303. settings.observe(settings.KEY.colorizeChat, function ()
  6304. {
  6305. return checkColorize(false);
  6306. });
  6307. }
  6308. }
  6309.  
  6310. function init()
  6311. {
  6312. newChat();
  6313. addIntelligentScrolling();
  6314. addCommandSuggester();
  6315. addOwnCommands();
  6316. checkColorize(true);
  6317. checkSetting(true);
  6318. var _enlargeChat = win.enlargeChat;
  6319. var chatBoxArea = document.getElementById(CHAT_BOX_ID);
  6320.  
  6321. function setChatBoxHeight(height)
  6322. {
  6323. var defaultChat = document.getElementById(DEFAULT_CHAT_DIV_ID);
  6324. defaultChat.style.height = height;
  6325. var generalChat = document.getElementById(GENERAL_CHAT_DIV_ID);
  6326. generalChat.style.height = height;
  6327. var chatDivs = chatBoxArea.querySelectorAll('div[id^="' + PM_CHAT_DIV_PREFIX + '"]');
  6328. for (var i = 0; i < chatDivs.length; i++)
  6329. {
  6330. chatDivs[i].style.height = height;
  6331. }
  6332. }
  6333. win.enlargeChat = function (enlargeB)
  6334. {
  6335. _enlargeChat(enlargeB);
  6336. var defaultChatDiv = document.getElementById(DEFAULT_CHAT_DIV_ID);
  6337. var height = defaultChatDiv.style.height;
  6338. store.set('chat.height', height);
  6339. setChatBoxHeight(height);
  6340. handleScrolling(defaultChatDiv);
  6341. };
  6342. setChatBoxHeight(store.get('chat.height'));
  6343. // add history to chat
  6344. // TEMP >>>
  6345. // move pm entries to pm history
  6346. var changed = false;
  6347. for (var i = 0; i < chatHistory.length; i++)
  6348. {
  6349. var data = chatHistory[i];
  6350. if (isDataPM(data))
  6351. {
  6352. chatHistory.splice(i, 1);
  6353. i--;
  6354. pmHistory.push(data);
  6355. changed = true;
  6356. }
  6357. }
  6358. if (changed)
  6359. {
  6360. saveChatHistory();
  6361. savePmHistory();
  6362. }
  6363. // TEMP <<<
  6364. chatHistory.forEach(function (d)
  6365. {
  6366. return add2Chat(d);
  6367. });
  6368. pmHistory.forEach(function (d)
  6369. {
  6370. return add2Chat(d);
  6371. });
  6372. if (chatboxFragments)
  6373. {
  6374. chatboxFragments.forEach(function (fragment, key)
  6375. {
  6376. var chatbox = getChatPanel(key);
  6377. chatbox.appendChild(fragment);
  6378. });
  6379. chatboxFragments = null;
  6380. }
  6381. // reset the new counter for all tabs
  6382. var tabs = document.querySelectorAll('.chat-tab');
  6383. for (var i = 0; i < tabs.length; i++)
  6384. {
  6385. setNewCounter(tabs[i], 0, true);
  6386. }
  6387. }
  6388. chat.init = init;
  6389. var _a;
  6390. })(chat || (chat = {}));
  6391.  
  6392. /**
  6393. * hopefully only temporary fixes
  6394. */
  6395. var temporaryFixes;
  6396. (function (temporaryFixes)
  6397. {
  6398. temporaryFixes.name = 'temporaryFixes';
  6399. function fixMagicShopButton(){
  6400. var getBackButton = $("#tab-container-magicShop span:first");
  6401. getBackButton.prop("class", "medium-button");
  6402. getBackButton.html(`<img class="image-icon-30" src="images/icons/back.png"> back`);
  6403. getBackButton.after("<br/><br/>");
  6404. }
  6405. function fixWrongURLs()
  6406. {
  6407. var image = document.querySelectorAll('.dialogue-loot .image-icon-50');
  6408. for (var i=0; i < image.length; i++){
  6409. var key = image[i];
  6410. var change = key.src = key.src.replace('/images/icons/darkTombKey.png','/images/darkTombKey.png');
  6411. }
  6412. }
  6413. // update spells being clickable in combat
  6414. function setSpellsClickable()
  6415. {
  6416. var spellbox = document.getElementById('fight-spellboox');
  6417. if (spellbox)
  6418. {
  6419. for (var i = 0; i < spellbox.children.length; i++)
  6420. {
  6421. var child = spellbox.children.item(i);
  6422. if (!win.isInCombat() && child.hasAttribute('onclick'))
  6423. {
  6424. child.dataset.onclick = child.getAttribute('onclick') || '';
  6425. child.removeAttribute('onclick');
  6426. }
  6427. else if (win.isInCombat() && !!child.dataset.onclick)
  6428. {
  6429. child.setAttribute('onclick', child.dataset.onclick || '');
  6430. child.dataset.onclick = '';
  6431. }
  6432. }
  6433. }
  6434. }
  6435. // warn before unloading/reloading the tab if combat is in progress
  6436. function combatWarnOnUnload()
  6437. {
  6438. if (!win.isInCombat())
  6439. {
  6440. win.onbeforeunload = null;
  6441. }
  6442. else
  6443. {
  6444. if (win.onbeforeunload == null)
  6445. {
  6446. win.onbeforeunload = function ()
  6447. {
  6448. return 'You are in a fight!';
  6449. };
  6450. }
  6451. }
  6452. }
  6453.  
  6454. function fixCombatCountdown()
  6455. {
  6456. var el = document.getElementById('combat-countdown');
  6457. if (!el)
  6458. {
  6459. return;
  6460. }
  6461. if (win.isInCombat())
  6462. {
  6463. el.style.display = '';
  6464. var visible = win.combatCommenceTimer != 0;
  6465. el.style.visibility = visible ? '' : 'hidden';
  6466. }
  6467. }
  6468. // fix exhaustion timer and updating brewing and cooking recipes
  6469. function fixExhaustionTimer()
  6470. {
  6471. if (document.getElementById('tab-container-combat').style.display != 'none')
  6472. {
  6473. win.combatNotFightingTick();
  6474. }
  6475. }
  6476.  
  6477. function fixClientGameLoop()
  6478. {
  6479. var _clientGameLoop = win.clientGameLoop;
  6480. win.clientGameLoop = function ()
  6481. {
  6482. _clientGameLoop();
  6483. //setSpellsClickable();
  6484. combatWarnOnUnload();
  6485. fixCombatCountdown();
  6486. fixExhaustionTimer();
  6487. };
  6488. }
  6489. // fix elements of scrollText (e.g. when joining the game and receiving xp at that moment)
  6490. function fixScroller()
  6491. {
  6492. var textEls = document.querySelectorAll('div.scroller');
  6493. for (var i = 0; i < textEls.length; i++)
  6494. {
  6495. var scroller = textEls[i];
  6496. if (scroller.style.position != 'absolute')
  6497. {
  6498. scroller.style.display = 'none';
  6499. }
  6500. }
  6501. }
  6502. // fix style of tooltips
  6503. function fixTooltipStyle()
  6504. {
  6505. addStyle("\nbody > div.tooltip > h2:first-child\n{\n\tmargin-top: 0;\n\tfont-size: 20pt;\n\tfont-weight: normal;\n}\n\t\t");
  6506. }
  6507. // fix buiulding magic table dynamically
  6508. function fixRefreshingMagicRecipes()
  6509. {
  6510. // define missing properties for checking the needed materials
  6511. win.enchantStargemPotionMagic = 0;
  6512. win.changeWeatherMagic = 0;
  6513. win.refreshLoadMagicTable = false;
  6514. var _processMagicTab = win.processMagicTab;
  6515. win.processMagicTab = function ()
  6516. {
  6517. var _refreshLoadCraftingTable = win.refreshLoadCraftingTable;
  6518. win.refreshLoadCraftingTable = win.refreshLoadMagicTable;
  6519. _processMagicTab();
  6520. win.refreshLoadCraftingTable = _refreshLoadCraftingTable;
  6521. if (win.magicPage3 == 1)
  6522. {
  6523. win.showMateriesNeededAndLevelLabelsMagic('enchantStargemPotion');
  6524. win.showMateriesNeededAndLevelLabelsMagic('beam');
  6525. win.showMateriesNeededAndLevelLabelsMagic('changeWeather');
  6526. }
  6527. };
  6528. }
  6529.  
  6530. function moveItemBox(itemKey, targetElId, color1, color2)
  6531. {
  6532. var itemBox = document.getElementById('item-box-' + itemKey);
  6533. var targetContainer = document.getElementById(targetElId);
  6534. targetContainer.appendChild(itemBox);
  6535. // remove event listeners before binding the tooltip to it
  6536. var $itemBox = win.$(itemBox);
  6537. $itemBox.off('mouseover').off('mouseleave');
  6538. itemBox.title = '';
  6539. // bind tooltip to item box
  6540. ensureTooltip('ingredient-secondary', itemBox);
  6541. // change color
  6542. itemBox.style.background = 'linear-gradient(' + color1 + ', ' + color2 + ')';
  6543. $itemBox
  6544. .mouseover(function ()
  6545. {
  6546. itemBox.style.background = 'none';
  6547. itemBox.style.backgroundColor = color2;
  6548. })
  6549. .mouseleave(function ()
  6550. {
  6551. itemBox.style.background = 'linear-gradient(' + color1 + ', ' + color2 + ')';
  6552. });
  6553. }
  6554. // move the strange leaf to brewing tab (thanks lasse_brus for this idea)
  6555. function moveStrangeLeafs()
  6556. {
  6557. //moveItemBox('strangeBlueLeaf', 'tab-sub-container-brewing', '#800080', '#990099');
  6558. //moveItemBox('strangePinkLeaf', 'tab-sub-container-brewing', '#800080', '#990099');
  6559. }
  6560. // fix height of map item
  6561. function fixTreasureMap()
  6562. {
  6563. var mapBox = document.getElementById('item-box-treasureMap');
  6564. var numSpan = mapBox.lastElementChild;
  6565. numSpan.style.display = '';
  6566. numSpan.style.visibility = 'hidden';
  6567. }
  6568. // fix wobbling tree places on hover (in wood cutting)
  6569. function fixWoodcutting()
  6570. {
  6571. addStyle("\nimg.woodcutting-tree-img\n{\n\tborder: 1px solid transparent;\n}\n\t\t");
  6572. }
  6573. // fix wobbling quest rows on hover (in quest book)
  6574. function fixQuestBook()
  6575. {
  6576. addStyle("\n#table-quest-list tr\n{\n\tborder: 1px solid transparent;\n}\n\t\t");
  6577. }
  6578.  
  6579. function fixScrollImages()
  6580. {
  6581. function fixIcon(icon)
  6582. {
  6583. return icon + (icon != 'none' && !/\..{3,4}$/.test(icon) ? '.png' : '');
  6584. }
  6585. var _scrollTextHitSplat = win.scrollTextHitSplat;
  6586. win.scrollTextHitSplat = function (icon, color, text, elId, cbType)
  6587. {
  6588. _scrollTextHitSplat(fixIcon(icon), color, text, elId, cbType);
  6589. };
  6590. var _scrollText = win.scrollText;
  6591. win.scrollText = function (icon, color, text)
  6592. {
  6593. _scrollText(fixIcon(icon), color, text);
  6594. };
  6595. }
  6596.  
  6597. function fixQuest8BraveryRecipe()
  6598. {
  6599. observer.add([
  6600. 'quest8'
  6601. , 'braveryPotion'
  6602. ], function ()
  6603. {
  6604. var show = win.quest8 > 0 && win.braveryPotion == 0;
  6605. var recipe = document.getElementById('brewing-braveryPotion');
  6606. if (recipe)
  6607. {
  6608. recipe.style.display = show ? '' : 'none';
  6609. }
  6610. });
  6611. }
  6612.  
  6613. function fixHitText()
  6614. {
  6615. win.scrollTextHitSplat = function (icon, color, text, elId, cbType)
  6616. {
  6617. var imgTag = icon != 'none' ? "<img src=\"images/" + icon + "\" class=\"image-icon-50\" />" : '';
  6618. var elementChosen = document.getElementById(elId);
  6619. if (!elementChosen)
  6620. {
  6621. return;
  6622. }
  6623. var rect = elementChosen.getBoundingClientRect();
  6624. var xCoord = (rect.left + rect.right) / 2;
  6625. var yCoord = (rect.bottom + rect.top) / 2;
  6626. var extraStyle = '';
  6627. if (cbType == 'melee')
  6628. {
  6629. extraStyle = 'border: 1px solid red; background-color: #4d0000;';
  6630. }
  6631. else if (cbType == 'heal')
  6632. {
  6633. extraStyle = 'border: 1px solid green; background-color: lime;';
  6634. }
  6635. var $elementToAppend = win.$("<div class=\"scroller\" style=\"" + extraStyle + " color: " + color + "; position: fixed;\">" + imgTag + text + "</div>").appendTo('body');
  6636. if (xCoord == 0 && yCoord == 0)
  6637. {
  6638. var tab = document.getElementById('tab-container-bar-combat');
  6639. var tabRect = tab.getBoundingClientRect();
  6640. var boxRect = $elementToAppend.get(0).getBoundingClientRect();
  6641. xCoord = elId == 'img-hero' ? (tabRect.left - boxRect.width) : tabRect.right;
  6642. yCoord = tabRect.top;
  6643. }
  6644. $elementToAppend
  6645. .css(
  6646. {
  6647. left: xCoord
  6648. , top: yCoord
  6649. })
  6650. .animate(
  6651. {
  6652. top: '-=50px'
  6653. }, function ()
  6654. {
  6655. return $elementToAppend.fadeOut(1000, function ()
  6656. {
  6657. return $elementToAppend.remove();
  6658. });
  6659. });
  6660. };
  6661. }
  6662.  
  6663. function fixBoatTooltips()
  6664. {
  6665. var boatBox = document.getElementById('item-box-boundRowBoat');
  6666. var boatTooltip = boatBox && document.getElementById(boatBox.dataset.tooltipId || '');
  6667. var tooltipParent = boatTooltip && boatTooltip.parentElement;
  6668. if (!boatBox || !boatTooltip || !tooltipParent)
  6669. {
  6670. return;
  6671. }
  6672.  
  6673. function setTripDuration(durationEl, boatKey)
  6674. {
  6675. var durationStr = TRIP_DURATION.hasOwnProperty(boatKey) ? TRIP_DURATION[boatKey].toString(10) : '?';
  6676. durationEl.innerHTML = "<strong>Trip duration:</strong> " + durationStr + " hours";
  6677. }
  6678. boatTooltip.id = boatBox.dataset.tooltipId = 'tooltip-boundRowBoat';
  6679. boatTooltip.appendChild(document.createElement('br'));
  6680. var boatDuration = document.createElement('span');
  6681. boatDuration.className = 'trip-duration';
  6682. setTripDuration(boatDuration, 'rowBoat');
  6683. boatTooltip.appendChild(boatDuration);
  6684. for (var _i = 0, BOAT_LIST_1 = BOAT_LIST; _i < BOAT_LIST_1.length; _i++)
  6685. {
  6686. var boatKey = BOAT_LIST_1[_i];
  6687. var boundKey = getBoundKey(boatKey);
  6688. var itemBox = document.getElementById('item-box-' + boundKey);
  6689. if (!itemBox)
  6690. {
  6691. continue;
  6692. }
  6693. var tooltip = document.getElementById('tooltip-' + boundKey);
  6694. if (!tooltip)
  6695. {
  6696. tooltip = boatTooltip.cloneNode(true);
  6697. tooltip.id = 'tooltip-' + boundKey;
  6698. var header = tooltip.firstElementChild;
  6699. header.textContent = capitalize(split2Words(boatKey));
  6700. tooltipParent.appendChild(tooltip);
  6701. itemBox.dataset.tooltipId = 'tooltip-' + boundKey;
  6702. }
  6703. var durationEl = tooltip.getElementsByClassName('trip-duration').item(0);
  6704. if (durationEl)
  6705. {
  6706. setTripDuration(durationEl, boatKey);
  6707. }
  6708. }
  6709. }
  6710.  
  6711. function fixAlignments()
  6712. {
  6713. 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");
  6714. }
  6715. function fixFontSize11Tabs()
  6716. {
  6717. var tabKey = ['items', 'skills', 'mining', 'crafting', 'woodcutting', 'farming', 'brewing', 'combat', 'magic', 'cooking', 'shop'];
  6718. for (var i = 0; i < tabKey.length; i++)
  6719. {
  6720. var tab = document.getElementById('tab-container-bar-'+ tabKey[i] +'-label');
  6721. tab.style.fontSize = "15px";
  6722. }
  6723. }
  6724. function addSpellTooltips()
  6725. {
  6726. var heal = document.querySelector('[data-spell-name="heal"]');
  6727. heal.title = 'Mana: 2';
  6728. win.$(heal).tooltip();
  6729. var pound = document.querySelector('[data-spell-name="pound"]');
  6730. pound.title = 'Mana: 2';
  6731. win.$(pound).tooltip();
  6732. var teleport = document.querySelector('[data-spell-name="teleport"]');
  6733. teleport.title = 'Mana: 10';
  6734. win.$(teleport).tooltip();
  6735. var gust = document.querySelector('[data-spell-name="gust"]');
  6736. gust.title = 'Mana: 3';
  6737. win.$(gust).tooltip();
  6738. var bubble = document.querySelector('[data-spell-name="bubble"]');
  6739. bubble.title = 'Mana: 10';
  6740. win.$(bubble).tooltip();
  6741. var sandstorm = document.querySelector('[data-spell-name="sandstorm"]');
  6742. sandstorm.title = 'Mana: 20';
  6743. win.$(sandstorm).tooltip();
  6744. var ghostScan = document.querySelector('[data-spell-name="ghostScan"]');
  6745. ghostScan.title = 'Mana: 20';
  6746. win.$(ghostScan).tooltip();
  6747. var beam = document.querySelector('[data-spell-name="beam"]');
  6748. beam.title = 'Mana: 15';
  6749. win.$(beam).tooltip();
  6750. var reflect = document.querySelector('[data-spell-name="reflect"]');
  6751. reflect.title = 'Mana: 20';
  6752. win.$(reflect).tooltip();
  6753. var superHeal = document.querySelector('[data-spell-name="superHeal"]');
  6754. superHeal.title = 'Mana: 8';
  6755. win.$(superHeal).tooltip();
  6756. var barrier = document.querySelector('[data-spell-name="barrier"]');
  6757. barrier.title = 'Mana: 25';
  6758. win.$(barrier).tooltip();
  6759. var healSteal = document.querySelector('[data-spell-name="healSteal"]');
  6760. healSteal.title = 'Mana: 25';
  6761. win.$(healSteal).tooltip();
  6762. var poison = document.querySelector('[data-spell-name="poison"]');
  6763. poison.title = 'Mana: 30';
  6764. win.$(poison).tooltip();
  6765. }
  6766. function modifySpellImages()
  6767. {
  6768. var spell = document.querySelectorAll('.fight-spell');
  6769. for (var i = 0; i < 15; i++){
  6770. spell[i].style.width = '43px';
  6771. spell[i].style.height = '43px';
  6772. }
  6773. var img= [];
  6774. for (var i = 0; i < 15; i++){
  6775. img[i] = spell[i].getElementsByTagName('img')[0];
  6776. img[i].style.width = '43px';
  6777. }
  6778. }
  6779. function addHeroStatTooltips()
  6780. {
  6781. var table = document.querySelector('#hero-area table.table-hero-stats');
  6782. if (!table)
  6783. {
  6784. return;
  6785. }
  6786. var statRow = table.rows.item(0);
  6787. var attackCell = statRow.cells.item(0);
  6788. attackCell.title = 'Attack Damage';
  6789. win.$(attackCell).tooltip();
  6790. var accuracyCell = statRow.cells.item(1);
  6791. accuracyCell.title = 'Attack Accuracy';
  6792. win.$(accuracyCell).tooltip();
  6793. var speedCell = statRow.cells.item(2);
  6794. speedCell.title = 'Attack Speed';
  6795. win.$(speedCell).tooltip();
  6796. var defenseCell = statRow.cells.item(3);
  6797. defenseCell.title = 'Defense';
  6798. win.$(defenseCell).tooltip();
  6799. var magicCell = statRow.cells.item(4);
  6800. magicCell.title = 'Magic Bonus';
  6801. win.$(magicCell).tooltip();
  6802. // energy, cooldown, HP and mana
  6803. var energyRow = table.rows.item(1);
  6804. var energy = energyRow.cells.item(0);
  6805. energy.title = 'Energy';
  6806. var cdRow = table.rows.item(2);
  6807. var cd = cdRow.cells.item(0);
  6808. cd.title = 'Combat Cooldown';
  6809. var getHPbar = document.querySelectorAll('.inner-hp-bar-label');
  6810. getHPbar[0].title = 'Health Points';
  6811. var getManabar = document.querySelectorAll('.inner-mana-bar-label');
  6812. getManabar[0].title = 'Mana Points';
  6813. }
  6814.  
  6815. function unifyTooltips()
  6816. {
  6817. function getLastNonEmptyChild(parent)
  6818. {
  6819. for (var i = parent.childNodes.length - 1; i >= 0; i--)
  6820. {
  6821. var child = parent.childNodes.item(i);
  6822. if (child.nodeType === Node.TEXT_NODE
  6823. && (child.textContent || '').trim() !== '')
  6824. {
  6825. return null;
  6826. }
  6827. else if (child.nodeType === Node.ELEMENT_NODE)
  6828. {
  6829. return child;
  6830. }
  6831. }
  6832. return null;
  6833. }
  6834. // clean unnecessary br-tags in tooltips
  6835. var tooltips = document.querySelectorAll('#tooltip-list > div[id^="tooltip-"]');
  6836. for (var i = 0; i < tooltips.length; i++)
  6837. {
  6838. var tooltip = tooltips[i];
  6839. var lneChild = void 0;
  6840. while ((lneChild = getLastNonEmptyChild(tooltip)) && lneChild.tagName == 'BR')
  6841. {
  6842. tooltip.removeChild(lneChild);
  6843. }
  6844. }
  6845.  
  6846. function getTooltip(item)
  6847. {
  6848. return document.getElementById('tooltip-' + item);
  6849. }
  6850. var boldify = [
  6851. 'oilBarrel'
  6852. , 'boundEmptyPickaxe'
  6853. , 'boundEmptyShovel'
  6854. , 'boundRocket'
  6855. , 'ashes'
  6856. , 'iceBones'
  6857. ];
  6858. var lastDotRegex = /\.\s*$/;
  6859. for (var _i = 0, boldify_1 = boldify; _i < boldify_1.length; _i++)
  6860. {
  6861. var item = boldify_1[_i];
  6862. var tooltip = getTooltip(item);
  6863. if (!tooltip)
  6864. {
  6865. continue;
  6866. }
  6867. var textNode = tooltip.lastChild;
  6868. while (textNode && (textNode.nodeType != Node.TEXT_NODE || (textNode.textContent || '').trim() === ''))
  6869. {
  6870. if (textNode.nodeName === 'SPAN')
  6871. {
  6872. textNode = textNode.lastChild;
  6873. }
  6874. else
  6875. {
  6876. textNode = textNode.previousSibling;
  6877. }
  6878. }
  6879. if (!textNode)
  6880. {
  6881. continue;
  6882. }
  6883. var text = textNode.textContent || '';
  6884. var split = text.split(/\.(?=\s*\S+)/);
  6885. var clickText = split[split.length - 1];
  6886. textNode.textContent = text.replace(clickText, '');
  6887. if (split.length > 1)
  6888. {
  6889. tooltip.appendChild(document.createElement('br'));
  6890. tooltip.appendChild(document.createElement('br'));
  6891. }
  6892. var boldText = document.createElement('b');
  6893. boldText.textContent = clickText;
  6894. tooltip.appendChild(boldText);
  6895. }
  6896.  
  6897. function prepareTooltip(item, editText, createOnMissing)
  6898. {
  6899. if (createOnMissing === void 0)
  6900. {
  6901. createOnMissing = false;
  6902. }
  6903. var tooltip = getTooltip(item);
  6904. if (!tooltip)
  6905. {
  6906. return;
  6907. }
  6908. // try to find the b-node:
  6909. var bNode = getLastNonEmptyChild(tooltip);
  6910. if (bNode && bNode.tagName === 'SPAN')
  6911. {
  6912. bNode = getLastNonEmptyChild(bNode);
  6913. }
  6914. if (!bNode || bNode.tagName !== 'B')
  6915. {
  6916. if (!createOnMissing)
  6917. {
  6918. bNode = null;
  6919. }
  6920. else
  6921. {
  6922. tooltip.appendChild(document.createElement('br'));
  6923. tooltip.appendChild(document.createElement('br'));
  6924. bNode = document.createElement('b');
  6925. tooltip.appendChild(bNode);
  6926. }
  6927. }
  6928. if (bNode)
  6929. {
  6930. bNode.textContent = editText(bNode);
  6931. }
  6932. }
  6933. // remove dots
  6934. for (var i = 0; i < tooltips.length; i++)
  6935. {
  6936. var item = tooltips.item(i).id.replace(/^tooltip-/, '');
  6937. prepareTooltip(item, function (bNode)
  6938. {
  6939. var text = bNode.textContent || '';
  6940. if (/Click to /.test(text))
  6941. {
  6942. return text.replace(lastDotRegex, '');
  6943. }
  6944. return text;
  6945. });
  6946. }
  6947. // add click texts
  6948. function setText(item, text)
  6949. {
  6950. prepareTooltip(item, function ()
  6951. {
  6952. return text;
  6953. }, true);
  6954. }
  6955. for (var _a = 0, FURNACE_LEVELS_1 = FURNACE_LEVELS; _a < FURNACE_LEVELS_1.length; _a++)
  6956. {
  6957. var furnaceLevel = FURNACE_LEVELS_1[_a];
  6958. var furnaceItem = getBoundKey(furnaceLevel + 'Furnace');
  6959. setText(furnaceItem, 'Click to operate');
  6960. var ovenItem = getBoundKey(furnaceLevel + 'Oven');
  6961. setText(ovenItem, 'Click to operate');
  6962. }
  6963. // fix tooltip of quests-book
  6964. var questBookTooltip = getTooltip('quests-book');
  6965. if (questBookTooltip)
  6966. {
  6967. var childNodes = questBookTooltip.childNodes;
  6968. for (var i = 0; i < childNodes.length; i++)
  6969. {
  6970. var node = childNodes[i];
  6971. if (node.nodeType === Node.TEXT_NODE
  6972. && (node.textContent || '').indexOf('Click to see a list of quests.') > -1)
  6973. {
  6974. var next = node.nextSibling;
  6975. if (next)
  6976. {
  6977. questBookTooltip.removeChild(next);
  6978. }
  6979. questBookTooltip.removeChild(node);
  6980. }
  6981. }
  6982. }
  6983. // fix tooltip of axe
  6984. var axeTooltip = getTooltip('boundEmptyAxe');
  6985. if (axeTooltip)
  6986. {
  6987. axeTooltip.insertBefore(document.createElement('br'), axeTooltip.lastElementChild);
  6988. }
  6989. var texts = {
  6990. 'quests-book': 'Click to see the list of quests'
  6991. , 'achievementBook': 'Click to see the list of achievements'
  6992. , 'boundEmptyChisel': 'Click to use'
  6993. , 'rake': 'Click to upgrade your rake'
  6994. , 'boundBoat': 'Click to send boat'
  6995. };
  6996. for (var item in texts)
  6997. {
  6998. setText(item, texts[item]);
  6999. }
  7000. for (var _b = 0, BOAT_LIST_2 = BOAT_LIST; _b < BOAT_LIST_2.length; _b++)
  7001. {
  7002. var boatKey = BOAT_LIST_2[_b];
  7003. setText(getBoundKey(boatKey), 'Click to send boat');
  7004. }
  7005. }
  7006. var cached = {
  7007. scrollWidth: 0
  7008. , scrollHeight: 0
  7009. };
  7010.  
  7011. function changeTooltipPosition(event)
  7012. {
  7013. var tooltipX = event.pageX - 8;
  7014. var tooltipY = event.pageY + 8;
  7015. var el = document.querySelector('body > div.tooltip');
  7016. if (!el)
  7017. {
  7018. return;
  7019. }
  7020. if (!this)
  7021. {
  7022. // init
  7023. cached.scrollWidth = document.body.scrollWidth;
  7024. cached.scrollHeight = document.body.scrollHeight;
  7025. }
  7026. var rect = el.getBoundingClientRect();
  7027. var css = {
  7028. left: tooltipX
  7029. , top: tooltipY
  7030. , width: ''
  7031. , height: ''
  7032. , maxWidth: cached.scrollWidth
  7033. , maxHeight: cached.scrollHeight
  7034. };
  7035. var diffX = cached.scrollWidth - 20 - tooltipX - rect.width;
  7036. if (diffX < 0)
  7037. {
  7038. css.left += diffX;
  7039. css.width = rect.width - 42;
  7040. }
  7041. var diffY = cached.scrollHeight - 20 - tooltipY - rect.height;
  7042. if (diffY < 0)
  7043. {
  7044. css.top += diffY;
  7045. css.height = rect.height - 22;
  7046. }
  7047. win.$(el).css(css);
  7048. }
  7049.  
  7050. function fixTooltipPositioning()
  7051. {
  7052. win.changeTooltipPosition = changeTooltipPosition;
  7053. win.loadTooltips();
  7054. }
  7055.  
  7056. function fixCombatNavigation()
  7057. {
  7058. var backBtns = document.querySelectorAll('span.medium-button[onclick*="openTab(\'combat\')"]');
  7059. for (var i = 0; i < backBtns.length; i++)
  7060. {
  7061. var btn = backBtns.item(i);
  7062. var img = btn.firstElementChild;
  7063. var textNode = btn.lastChild;
  7064. if (!img || img.tagName != 'IMG' || !textNode)
  7065. {
  7066. continue;
  7067. }
  7068. img.className = img.className.replace(/(-\d+)-b/, '$1');
  7069. textNode.textContent = ' back';
  7070. }
  7071. }
  7072.  
  7073. function fixPromethiumSmeltingTime()
  7074. {
  7075. var _getTimerPerBar = win.getTimerPerBar;
  7076. win.getTimerPerBar = function (bar)
  7077. {
  7078. if (bar == 'promethiumBar')
  7079. {
  7080. return 80;
  7081. }
  7082. return _getTimerPerBar(bar);
  7083. };
  7084. }
  7085.  
  7086. function fixImage()
  7087. {
  7088. var oxygenEl = document.querySelector('img[src="images/oxygenPotion"]');
  7089. if (oxygenEl)
  7090. {
  7091. oxygenEl.src += '.png';
  7092. }
  7093. }
  7094.  
  7095. function init()
  7096. {
  7097. fixMagicShopButton();
  7098. fixWrongURLs();
  7099. fixClientGameLoop();
  7100. fixScroller();
  7101. fixTooltipStyle();
  7102. //fixRefreshingMagicRecipes();
  7103. moveStrangeLeafs();
  7104. fixTreasureMap();
  7105. fixWoodcutting();
  7106. fixQuestBook();
  7107. // apply fix for scroll images later to fix images in this code too
  7108. fixHitText();
  7109. fixScrollImages();
  7110. fixQuest8BraveryRecipe();
  7111. fixBoatTooltips();
  7112. fixAlignments();
  7113. addHeroStatTooltips();
  7114. fixFontSize11Tabs();
  7115. //addSpellTooltips();
  7116. modifySpellImages();
  7117. unifyTooltips();
  7118. fixTooltipPositioning();
  7119. fixCombatNavigation();
  7120. fixPromethiumSmeltingTime();
  7121. fixImage();
  7122. }
  7123. temporaryFixes.init = init;
  7124. })(temporaryFixes || (temporaryFixes = {}));
  7125.  
  7126. /**
  7127. * improve timer
  7128. */
  7129. var timer;
  7130. (function (timer)
  7131. {
  7132. timer.name = 'timer';
  7133. var IMPROVED_CLASS = 'improved';
  7134. var NOTIFICATION_AREA_ID = 'notifaction-area';
  7135. var PERCENT_CLASS = 'percent';
  7136. var REMAINING_CLASS = 'remaining';
  7137. var TIMER_CLASS = 'timer';
  7138.  
  7139. function bindNewFormatter()
  7140. {
  7141. function doBind()
  7142. {
  7143. win.formatTime = win.formatTimeShort = win.formatTimeShort2 = function (seconds)
  7144. {
  7145. return format.timer(seconds);
  7146. };
  7147. }
  7148. win.addEventListener('load', function ()
  7149. {
  7150. return setTimeout(function ()
  7151. {
  7152. return doBind();
  7153. }, 100);
  7154. });
  7155. doBind();
  7156. setTimeout(function ()
  7157. {
  7158. return doBind();
  7159. }, 100);
  7160. }
  7161.  
  7162. function applyStyle()
  7163. {
  7164. 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");
  7165. }
  7166.  
  7167. function improveSmeltingTimer()
  7168. {
  7169. var el = document.getElementById('notif-smelting');
  7170. if (!el)
  7171. {
  7172. return;
  7173. }
  7174. var smeltingNotifBox = el;
  7175. smeltingNotifBox.classList.add(IMPROVED_CLASS);
  7176. var smeltingTimerEl = document.createElement('span');
  7177. smeltingTimerEl.className = TIMER_CLASS;
  7178. smeltingNotifBox.appendChild(smeltingTimerEl);
  7179. var remainingBarsEl = document.createElement('span');
  7180. remainingBarsEl.className = REMAINING_CLASS;
  7181. smeltingNotifBox.appendChild(remainingBarsEl);
  7182. var delta = 0;
  7183.  
  7184. function updatePercValues(init)
  7185. {
  7186. if (init === void 0)
  7187. {
  7188. init = false;
  7189. }
  7190. updateSmeltingTimer(delta = 0);
  7191. if (init)
  7192. {
  7193. observer.add('smeltingPercD', function ()
  7194. {
  7195. return updatePercValues();
  7196. });
  7197. observer.add('smeltingPerc', function ()
  7198. {
  7199. return updatePercValues();
  7200. });
  7201. }
  7202. }
  7203.  
  7204. function updateSmeltingTimer(delta)
  7205. {
  7206. if (delta === void 0)
  7207. {
  7208. delta = 0;
  7209. }
  7210. var totalTime = win.smeltingPercD;
  7211. // thanks at /u/marcus898 for your bug report
  7212. var elapsedTime = Math.round(win.smeltingPerc * totalTime / 100) + delta;
  7213. smeltingTimerEl.textContent = format.timer(Math.max(totalTime - elapsedTime, 0));
  7214. remainingBarsEl.textContent = (win.smeltingTotalAmount - win.smeltingAmount).toString();
  7215. }
  7216. observer.addTick(function ()
  7217. {
  7218. return updateSmeltingTimer(delta++);
  7219. });
  7220. updatePercValues(true);
  7221. }
  7222.  
  7223. function improveTimer(cssRulePrefix, textColor, timerColor, infoIdPrefx, containerPrefix, updateFn)
  7224. {
  7225. 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");
  7226. let iteration = cssRulePrefix == '.woodcutting-tree' ? 6 : 7;
  7227. for (var i = 0; i < iteration; i++)
  7228. {
  7229. var num = i + 1;
  7230. var infoId = infoIdPrefx + num;
  7231. var container = document.getElementById(containerPrefix + num);
  7232. container.style.position = 'relative';
  7233. var infoEl = document.createElement('div');
  7234. infoEl.className = 'info';
  7235. infoEl.id = infoId;
  7236. infoEl.innerHTML = "<div class=\"name\"></div><div class=\"timer\"></div>";
  7237. container.appendChild(infoEl);
  7238. updateFn(num, infoId, true);
  7239. }
  7240. }
  7241.  
  7242. function updateTreeInfo(placeId, infoElId, init)
  7243. {
  7244. if (init === void 0)
  7245. {
  7246. init = false;
  7247. }
  7248. var infoEl = document.getElementById(infoElId);
  7249. var nameEl = infoEl.firstElementChild;
  7250. var timerEl = infoEl.lastElementChild;
  7251. var idKey = 'treeId' + placeId;
  7252. var growTimerKey = 'treeGrowTimer' + placeId;
  7253. var lockedKey = 'treeUnlocked' + placeId;
  7254. var treeId = getGameValue(idKey);
  7255. if (treeId == 0)
  7256. {
  7257. var isLocked = (placeId == 5 || placeId == 6) && win.donorWoodcuttingPatch < win.currentTimeMillis;
  7258. nameEl.textContent = isLocked ? 'Locked' : 'Empty';
  7259. timerEl.textContent = '';
  7260. }
  7261. else
  7262. {
  7263. nameEl.textContent = key2Name(win.getTreeName(treeId)) || 'Unknown Tree';
  7264. var remainingTime = win.TREE_GROW_TIME[treeId - 1] - getGameValue(growTimerKey);
  7265. timerEl.textContent = remainingTime > 0 ? '(' + format.timer(remainingTime) + ')' : 'Fully grown';
  7266. }
  7267. if (init)
  7268. {
  7269. observer.add([idKey, growTimerKey, lockedKey], function ()
  7270. {
  7271. return updateTreeInfo(placeId, infoElId, false);
  7272. });
  7273. }
  7274. }
  7275. // add tree grow timer
  7276. function improveTreeGrowTimer()
  7277. {
  7278. improveTimer('.woodcutting-tree', 'white', 'yellow', 'wc-tree-info-', 'wc-div-tree-', updateTreeInfo);
  7279. }
  7280.  
  7281. function updatePatchInfo(patchId, infoElId, init)
  7282. {
  7283. if (init === void 0)
  7284. {
  7285. init = false;
  7286. }
  7287. var infoEl = document.getElementById(infoElId);
  7288. var nameEl = infoEl.querySelector('.name');
  7289. var timerEl = infoEl.querySelector('.timer');
  7290. var idKey = 'farmingPatchSeed' + patchId;
  7291. var growTimeKey = 'farmingPatchGrowTime' + patchId;
  7292. var timerKey = 'farmingPatchTimer' + patchId;
  7293. var stageKey = 'farmingPatchStage' + patchId;
  7294. var stage = getGameValue(stageKey);
  7295. var seedName = PLANT_NAME[getGameValue(idKey)] || 'Unkown Plant';
  7296. if (stage == 0)
  7297. {
  7298. var isLocked = (patchId == 5 || patchId == 6) && win.donorFarmingPatch < win.currentTimeMillis;
  7299. nameEl.textContent = isLocked ? 'Locked' : 'Click to grow';
  7300. timerEl.textContent = '';
  7301. }
  7302. else if (stage >= 4)
  7303. {
  7304. nameEl.textContent = stage > 4 ? 'Dead Plant' : seedName;
  7305. timerEl.textContent = stage > 4 ? 'Click to remove' : 'Click to harvest';
  7306. }
  7307. else
  7308. {
  7309. nameEl.textContent = seedName;
  7310. var remainingTime = getGameValue(growTimeKey) - getGameValue(timerKey);
  7311. timerEl.textContent = '(' + format.timer(remainingTime) + ')';
  7312. }
  7313. if (init)
  7314. {
  7315. observer.add([idKey, timerKey, stageKey, 'donorFarmingPatch'], function ()
  7316. {
  7317. return updatePatchInfo(patchId, infoElId, false);
  7318. });
  7319. }
  7320. }
  7321. // add seed name and change color of timer
  7322. function getSoonestTreeTimer()
  7323. {
  7324. if (win.treeStage1 == 4
  7325. || win.treeStage2 == 4
  7326. || win.treeStage3 == 4
  7327. || win.treeStage4 == 4
  7328. || win.treeStage5 == 4
  7329. || win.treeStage6 == 4)
  7330. {
  7331. return -1;
  7332. }
  7333. var minTimer = null;
  7334. for (var i = 1; i <= 6; i++)
  7335. {
  7336. var treeId = getGameValue('treeId' + i);
  7337. var unlocked = getGameValue('treeUnlocked' + i) == 1;
  7338. var timerValue = getGameValue('treeGrowTimer' + i);
  7339. if (unlocked && treeId !== 0 && timerValue > 0)
  7340. {
  7341. var remainingTime = win.TREE_GROW_TIME[treeId - 1] - timerValue;
  7342. minTimer = minTimer === null ? remainingTime : Math.min(minTimer, remainingTime);
  7343. }
  7344. }
  7345. return minTimer || 0;
  7346. }
  7347.  
  7348. function getSoonestFarmingTimer()
  7349. {
  7350. if (win.farmingPatchStage1 == 0 || win.farmingPatchStage1 == 4
  7351. || win.farmingPatchStage2 == 0 || win.farmingPatchStage2 == 4
  7352. || win.farmingPatchStage3 == 0 || win.farmingPatchStage3 == 4
  7353. || win.farmingPatchStage4 == 0 || win.farmingPatchStage4 == 4
  7354. || win.donorFarmingPatch > win.currentTimeMillis && (win.farmingPatchStage5 == 0 || win.farmingPatchStage5 == 4
  7355. || win.farmingPatchStage6 == 0 || win.farmingPatchStage6 == 4))
  7356. {
  7357. return -1;
  7358. }
  7359. var minTimer = null;
  7360. for (var i = 1; i <= ((win.donorFarmingPatch > win.currentTimeMillis) ? 6 : 4); i++)
  7361. {
  7362. var remainingTimer = getGameValue('farmingPatchGrowTime' + i) - getGameValue('farmingPatchTimer' + i);
  7363. minTimer = minTimer === null ? remainingTimer : Math.min(minTimer, remainingTimer);
  7364. }
  7365. return minTimer || 0;
  7366. }
  7367.  
  7368. function improveSeedGrowTimer()
  7369. {
  7370. improveTimer('div[id^="farming-patch-area"]', 'black', 'blue', 'farming-patch-info-', 'farming-patch-area-', updatePatchInfo);
  7371. }
  7372.  
  7373. function addTabTimer()
  7374. {
  7375. var TAB_TIMER_KEY = 'tabTimer';
  7376. 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");
  7377.  
  7378. function getTabEl(key)
  7379. {
  7380. return document.getElementById('tab-container-bar-' + key);
  7381. }
  7382.  
  7383. function addInfoDiv(key)
  7384. {
  7385. var infoDiv = document.createElement('div');
  7386. infoDiv.className = 'info';
  7387. var tab = getTabEl(key);
  7388. if (tab)
  7389. {
  7390. tab.appendChild(infoDiv);
  7391. }
  7392. return infoDiv;
  7393. }
  7394.  
  7395. function createTabTimer(key, timerFn)
  7396. {
  7397. var tab = getTabEl(key);
  7398. var timerDiv = addInfoDiv(key);
  7399. if (!tab || !timerDiv)
  7400. {
  7401. return;
  7402. }
  7403. timerDiv.classList.add('timer');
  7404.  
  7405. function updateTimer()
  7406. {
  7407. var minTimer = timerFn();
  7408. if (tab)
  7409. {
  7410. tab.classList[minTimer == -1 ? 'add' : 'remove']('ready');
  7411. }
  7412. timerDiv.textContent = minTimer <= 0 ? '' : format.timer(minTimer);
  7413. }
  7414. updateTimer();
  7415. observer.addTick(function ()
  7416. {
  7417. return updateTimer();
  7418. });
  7419. }
  7420. createTabTimer('woodcutting', getSoonestTreeTimer);
  7421. createTabTimer('farming', getSoonestFarmingTimer);
  7422. createTabTimer('combat', function ()
  7423. {
  7424. return win.combatGlobalCooldown;
  7425. });
  7426. var energyDiv = addInfoDiv('combat');
  7427. energyDiv.classList.add('extra');
  7428.  
  7429. function updateEnergy()
  7430. {
  7431. energyDiv.innerHTML = '<img src="images/steak.png" class="image-icon-15"> ' + format.number(win.energy);
  7432. }
  7433. updateEnergy();
  7434. observer.add('energy', function ()
  7435. {
  7436. return updateEnergy();
  7437. });
  7438. // add highlight for stardust potions
  7439. var potionDiv = addInfoDiv('brewing');
  7440. potionDiv.classList.add('extra');
  7441. var potionList = ['stardustPotion', 'superStardustPotion'];
  7442. var potionImageList = [];
  7443.  
  7444. function updatePotion(key, img, init)
  7445. {
  7446. if (init === void 0)
  7447. {
  7448. init = false;
  7449. }
  7450. var timerKey = key + 'Timer';
  7451. var show = getGameValue(key) > 0 && getGameValue(timerKey) === 0;
  7452. img.style.display = show ? '' : 'none';
  7453. if (init)
  7454. {
  7455. observer.add(key, function ()
  7456. {
  7457. return updatePotion(key, img);
  7458. });
  7459. observer.add(timerKey, function ()
  7460. {
  7461. return updatePotion(key, img);
  7462. });
  7463. }
  7464. }
  7465. for (var i = 0; i < potionList.length; i++)
  7466. {
  7467. var key = potionList[i];
  7468. var img = document.createElement('img');
  7469. img.src = 'images/' + key + '.png';
  7470. img.className = 'image-icon-15';
  7471. potionImageList[i] = img;
  7472. potionDiv.appendChild(img);
  7473. updatePotion(key, img, true);
  7474. }
  7475.  
  7476. function updateVisibility()
  7477. {
  7478. document.body.classList[settings.get(settings.KEY.showTabTimer) ? 'add' : 'remove'](TAB_TIMER_KEY);
  7479. }
  7480. updateVisibility();
  7481. settings.observe(settings.KEY.showTabTimer, function ()
  7482. {
  7483. return updateVisibility();
  7484. });
  7485. observer.add('profileShortTabs', function ()
  7486. {
  7487. var short = !!win.profileShortTabs;
  7488. document.body.classList[short ? 'add' : 'remove']('short-tabs');
  7489. });
  7490. }
  7491.  
  7492. function addOilInfo()
  7493. {
  7494. var NULL_TYPE = 'null';
  7495. var PLUS_TYPE = 'plus';
  7496. var MINUS_TYPE = 'minus';
  7497. 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");
  7498. var oilFlow = document.getElementById('oil-flow-values');
  7499. var parent = oilFlow && oilFlow.parentElement;
  7500. if (!oilFlow || !parent)
  7501. {
  7502. return;
  7503. }
  7504. var container = document.createElement('div');
  7505. container.id = 'oil-filling-level';
  7506. var fillingLevel = document.createElement('div');
  7507. container.appendChild(fillingLevel);
  7508. var first = parent.firstElementChild;
  7509. if (first)
  7510. {
  7511. parent.insertBefore(container, first);
  7512. }
  7513. else
  7514. {
  7515. parent.appendChild(container);
  7516. }
  7517. parent.style.position = 'relative';
  7518. var netFlow = document.createElement('span');
  7519. netFlow.id = 'oil-flow-net';
  7520. parent.insertBefore(netFlow, oilFlow);
  7521. var next = oilFlow.nextElementSibling;
  7522. var netTimer = document.createElement('span');
  7523. netTimer.id = 'oil-flow-net-timer';
  7524. if (next)
  7525. {
  7526. parent.insertBefore(netTimer, next);
  7527. }
  7528. else
  7529. {
  7530. parent.appendChild(netTimer);
  7531. }
  7532. var oilNet;
  7533. var oilNetType;
  7534.  
  7535. function updateNetFlow(init)
  7536. {
  7537. if (init === void 0)
  7538. {
  7539. init = false;
  7540. }
  7541. oilNet = win.oilIn - win.oilOut;
  7542. oilNetType = oilNet === 0 ? NULL_TYPE : (oilNet > 0 ? PLUS_TYPE : MINUS_TYPE);
  7543. netFlow.dataset.type = oilNetType;
  7544. var sign = oilNet === 0 ? PLUS_MINUS_SIGN : (oilNet > 0 ? '+' : '');
  7545. netFlow.textContent = sign + oilNet;
  7546. if (init)
  7547. {
  7548. observer.add('oilIn', function ()
  7549. {
  7550. return updateNetFlow();
  7551. });
  7552. observer.add('oilOut', function ()
  7553. {
  7554. return updateNetFlow();
  7555. });
  7556. }
  7557. updateFullTimer(init);
  7558. }
  7559. var hour2Color = (_a = {}
  7560. , // 30min
  7561. _a[.5 * 60 * 60] = 'rgb(255, 0, 0)'
  7562. , _a[5 * 60 * 60] = 'rgb(255, 255, 0)'
  7563. , _a[8 * 60 * 60] = 'rgb(255, 255, 255)'
  7564. , _a);
  7565.  
  7566. function updateFullTimer(init)
  7567. {
  7568. if (init === void 0)
  7569. {
  7570. init = false;
  7571. }
  7572. netTimer.dataset.type = oilNetType;
  7573. var time = 0;
  7574. if (oilNet > 0)
  7575. {
  7576. netTimer.title = 'full in...';
  7577. var diff = win.maxOil - win.oil;
  7578. time = diff / oilNet;
  7579. }
  7580. else if (oilNet < 0)
  7581. {
  7582. netTimer.title = 'empty in...';
  7583. time = win.oil / Math.abs(oilNet);
  7584. }
  7585. netTimer.textContent = '(' + format.timer(Math.ceil(time)) + ')';
  7586. var filledPercent = win.oil / win.maxOil * 100;
  7587. fillingLevel.style.height = (100 - filledPercent) + '%';
  7588. /**
  7589. * colorize filling level according to the time it needs to be full/empty:
  7590. * - red iff oil storage full/empty in 30min
  7591. * - yellow iff oil storage full/empty in 5h
  7592. * - white iff oil storage full/empty in 8h or more
  7593. */
  7594. var color = oilNet === 0 ? '#ffffff' : colorGenerator.getColorTransition(time, hour2Color);
  7595. container.style.borderColor = color;
  7596. if (init)
  7597. {
  7598. observer.add('maxOil', function ()
  7599. {
  7600. return updateFullTimer();
  7601. });
  7602. observer.add('oil', function ()
  7603. {
  7604. return updateFullTimer();
  7605. });
  7606. observer.addTick(function ()
  7607. {
  7608. return updateFullTimer();
  7609. });
  7610. }
  7611. }
  7612. updateNetFlow(true);
  7613. var _a;
  7614. }
  7615.  
  7616. function addRocketTimer()
  7617. {
  7618. var notifArea = document.getElementById(NOTIFICATION_AREA_ID);
  7619. if (!notifArea)
  7620. {
  7621. return;
  7622. }
  7623. var notifBox = document.createElement('span');
  7624. notifBox.className = 'notif-box ' + IMPROVED_CLASS;
  7625. notifBox.id = 'notif-rocket';
  7626. notifBox.style.display = 'none';
  7627. 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>";
  7628. var AVG_KM_PER_SEC = rocketDestination == 1 ? 15 : 392;
  7629. notifBox.title = 'This value is only an estimation based on an average speed of '+AVG_KM_PER_SEC+'km per second.';
  7630. notifArea.appendChild(notifBox);
  7631. var img = notifBox.getElementsByTagName('img').item(0);
  7632. var timerEl = notifBox.getElementsByClassName(TIMER_CLASS).item(0);
  7633. var percentEl = notifBox.getElementsByClassName(PERCENT_CLASS).item(0);
  7634. var smoothedTime = 0;
  7635.  
  7636. function updateRocketKm()
  7637. {
  7638. if(AVG_KM_PER_SEC != (rocketDestination == 1 ? 15 : 392))
  7639. {
  7640. AVG_KM_PER_SEC = rocketDestination == 1 ? 15 : 392;
  7641. notifBox.title = 'This value is only an estimation based on an average speed of '+AVG_KM_PER_SEC+'km per second.';
  7642. }
  7643. var hideStatic = win.rocketKm < (rocketDestination == 1 ? MAX_ROCKET_MOON_KM : MAX_ROCKET_MARS_KM);
  7644. var hideTimer = win.rocketKm <= 0 || !hideStatic;
  7645. notifBox.style.display = hideTimer ? 'none' : '';
  7646. var percent = win.rocketKm / (rocketDestination == 1 ? MAX_ROCKET_MOON_KM : MAX_ROCKET_MARS_KM);
  7647. var diff = (rocketDestination == 1 ? MAX_ROCKET_MOON_KM : MAX_ROCKET_MARS_KM) - win.rocketKm;
  7648. if (win.rocketMoonId < 0)
  7649. {
  7650. percent = 1 - percent;
  7651. diff = win.rocketKm;
  7652. }
  7653. var avgRemainingTime = Math.round(diff / AVG_KM_PER_SEC);
  7654. // be more accurate in the last few seconds (may be the last 2 up to 16 seconds)
  7655. var threshold = smoothedTime < 10 ? 1 : 8;
  7656. if (Math.abs(smoothedTime - avgRemainingTime) >= threshold)
  7657. {
  7658. smoothedTime = avgRemainingTime + 1;
  7659. }
  7660. percentEl.textContent = Math.floor(percent * 100).toString();
  7661. }
  7662.  
  7663. function tickRocketTimer()
  7664. {
  7665. if (smoothedTime > 0)
  7666. {
  7667. smoothedTime = Math.max(smoothedTime - 1, 0);
  7668. timerEl.textContent = format.timer(smoothedTime);
  7669. }
  7670. }
  7671. updateRocketKm();
  7672. observer.add('rocketKm', function (key, oldValue, newValue)
  7673. {
  7674. return updateRocketKm();
  7675. });
  7676. observer.addTick(function ()
  7677. {
  7678. return tickRocketTimer();
  7679. });
  7680.  
  7681. function updateRocketDirection()
  7682. {
  7683. // alternatively: `transform: rotateZ(180deg) rotateY(180deg)`
  7684. var transform = win.rocketMoonId >= 0 ? '' : 'rotate(90deg)';
  7685. img.style.transform = transform;
  7686. var itemBox = document.getElementById('default-item-img-tag-boundRocket');
  7687. if (itemBox)
  7688. {
  7689. itemBox.style.transform = transform;
  7690. }
  7691. }
  7692. updateRocketDirection();
  7693. observer.add('rocketMoonId', function ()
  7694. {
  7695. return updateRocketDirection();
  7696. });
  7697. }
  7698. function addVendorRefreshTimer()
  7699. {
  7700. var notifArea = document.getElementById(NOTIFICATION_AREA_ID);
  7701. if (!notifArea)
  7702. {
  7703. return;
  7704. }
  7705. var notifBox = document.createElement('span');
  7706. notifBox.className = 'notif-box ' + IMPROVED_CLASS;
  7707. notifBox.id = 'notif-vendorRefresh';
  7708. notifBox.style.display = 'none';
  7709. notifBox.innerHTML = "<img src=\"images/vendor.png\" class=\"image-icon-50\" id=\"notif-vendorRefresh-img\" style=\"margin-right: 10px;\"><span class=\"timer\" data-item-display=\"vendorRefreshTimer\"></span>";
  7710. notifArea.appendChild(notifBox);
  7711. var img = notifBox.getElementsByTagName('img').item(0);
  7712. var timerEl = notifBox.getElementsByClassName(TIMER_CLASS).item(0);
  7713.  
  7714. function updateVendorRefreshTimer()
  7715. {
  7716. var hideTimer = win.vendorNotification == 1;
  7717. notifBox.style.display = hideTimer ? 'none' : '';
  7718. var timeLeft = Math.floor( (12*60*60) - (Date.now()-vendorLastChanged)/1000 );
  7719. timerEl.textContent = format.timer(timeLeft);
  7720. }
  7721. updateVendorRefreshTimer();
  7722. observer.addTick(function ()
  7723. {
  7724. return updateVendorRefreshTimer();
  7725. });
  7726. }
  7727. function addBobsUncleTimer()
  7728. {
  7729. var notifArea = document.getElementById(NOTIFICATION_AREA_ID);
  7730. if (!notifArea)
  7731. {
  7732. return;
  7733. }
  7734. var notifBox = document.createElement('span');
  7735. notifBox.className = 'notif-box ' + IMPROVED_CLASS;
  7736. notifBox.id = 'notif-bobsUncle';
  7737. notifBox.style.display = 'none';
  7738. notifBox.innerHTML = "<img src=\"images/bobsUncle.png\" class=\"image-icon-50\" id=\"notif-bobsUncle-img\" style=\"margin-right: 10px;\"><span class=\"timer\" data-item-display=\"bobsUncleTimer\"></span>";
  7739. notifArea.appendChild(notifBox);
  7740. var img = notifBox.getElementsByTagName('img').item(0);
  7741. var timerEl = notifBox.getElementsByClassName(TIMER_CLASS).item(0);
  7742.  
  7743. function updateBobsUncleTimer()
  7744. {
  7745. var hideTimer = win.farmingPatchStage7 == 0 || win.farmingPatchStage7 == 4;
  7746. notifBox.style.display = hideTimer ? 'none' : '';
  7747. var timeLeft = getGameValue('farmingPatchGrowTime7') - getGameValue('farmingPatchTimer7');
  7748. timerEl.textContent = format.timer(timeLeft);
  7749. }
  7750. updateBobsUncleTimer();
  7751. observer.addTick(function ()
  7752. {
  7753. return updateBobsUncleTimer();
  7754. });
  7755. }
  7756. function addCharcoalFactoryTimer()
  7757. {
  7758. var notifArea = document.getElementById(NOTIFICATION_AREA_ID);
  7759. if (!notifArea)
  7760. {
  7761. return;
  7762. }
  7763. var notifBox = document.createElement('span');
  7764. notifBox.className = 'notif-box ' + IMPROVED_CLASS;
  7765. notifBox.id = 'notif-charcoalFactory';
  7766. notifBox.style.display = 'none';
  7767. var consumeTime = (boundRedCharcoalFactoryOrb) ? 492: 112;
  7768. notifBox.title = 'This value is only an estimation based on an average consumption rate of one charcoal every '+consumeTime+' seconds.';
  7769. notifBox.innerHTML = "<img src=\"images/charcoalFactory.png\" class=\"image-icon-50\" id=\"notif-charcoalFactory-img\" style=\"margin-right: 10px;\"><span class=\"timer\" data-item-display=\"charcoalFactoryTimer\"></span>";
  7770. notifArea.appendChild(notifBox);
  7771. var img = notifBox.getElementsByTagName('img').item(0);
  7772. var timerEl = notifBox.getElementsByClassName(TIMER_CLASS).item(0);
  7773. var now = Math.floor(Date.now()/1000);
  7774. function updateCharcoalFactoryTimer()
  7775. {
  7776. var hideTimer = win.boundCharcoalFactory == 0 || win.charcoalFactoryCharcoal == 0;
  7777. notifBox.style.display = hideTimer ? 'none' : '';
  7778. var averageTimeLeft = getGameValue('charcoalFactoryCharcoal') * consumeTime;
  7779. var smoothedTime = averageTimeLeft + now - Math.floor(Date.now()/1000);
  7780. timerEl.textContent = format.timer(smoothedTime);
  7781. }
  7782. updateCharcoalFactoryTimer();
  7783. observer.addTick(function (){
  7784. return updateCharcoalFactoryTimer();
  7785. });
  7786. }
  7787. function getLogTypeList()
  7788. {
  7789. var list = [];
  7790. var els = document.querySelectorAll('input[id^="input-charcoalFoundry-"]');
  7791. for (var i = 0; i < els.length; i++)
  7792. {
  7793. list.push(els[i].id.replace(/^input-charcoalFoundry-/i, ''));
  7794. }
  7795. return list;
  7796. }
  7797.  
  7798. function improveFoundryTimer()
  7799. {
  7800. var el = document.getElementById('notif-charcoalFoundry');
  7801. if (!el)
  7802. {
  7803. return;
  7804. }
  7805. var notifBox = el;
  7806. notifBox.classList.add(IMPROVED_CLASS);
  7807. var timerEl = document.createElement('span');
  7808. timerEl.className = TIMER_CLASS;
  7809. notifBox.appendChild(timerEl);
  7810. var remainingEl = document.createElement('span');
  7811. remainingEl.className = REMAINING_CLASS;
  7812. notifBox.appendChild(remainingEl);
  7813. var logTypeList = null;
  7814. observer.add('charcoalFoundryN', function (key, oldValue, newValue)
  7815. {
  7816. timerEl.textContent = format.timer(win.charcoalFoundryD - win.charcoalFoundryN);
  7817. // init log type list when needed
  7818. if (!logTypeList)
  7819. {
  7820. logTypeList = getLogTypeList();
  7821. }
  7822. var woodAmount = win.charcoalFoundryTotal - win.charcoalFoundryCurrent;
  7823. var coalPerLog = win.getCharcoalPerLog(logTypeList[win.charcoalFoundryLogId - 1]);
  7824. var remainingCoal = woodAmount * (isNaN(coalPerLog) ? 1 : coalPerLog);
  7825. remainingEl.textContent = remainingCoal.toString();
  7826. });
  7827. }
  7828. function improveCharcoalFactoryTimer()
  7829. {
  7830. var el = document.getElementById('notif-charcoalFactory');
  7831. if (!el)
  7832. {
  7833. return;
  7834. }
  7835. var notifBox = el;
  7836. notifBox.classList.add(IMPROVED_CLASS);
  7837. var remainingEl = document.createElement('span');
  7838. remainingEl.className = REMAINING_CLASS;
  7839. notifBox.appendChild(remainingEl);
  7840. observer.add('charcoalFactoryCharcoal', function (key, oldValue, newValue)
  7841. {
  7842. var remainingCoal = win.charcoalFactoryCharcoal;
  7843. remainingEl.textContent = remainingCoal.toString();
  7844. });
  7845. }
  7846.  
  7847. function init()
  7848. {
  7849. bindNewFormatter();
  7850. applyStyle();
  7851. improveSmeltingTimer();
  7852. improveTreeGrowTimer();
  7853. improveSeedGrowTimer();
  7854. addTabTimer();
  7855. addOilInfo();
  7856. addRocketTimer();
  7857. improveFoundryTimer();
  7858. addVendorRefreshTimer();
  7859. addBobsUncleTimer();
  7860. addCharcoalFactoryTimer();
  7861. //improveCharcoalFactoryTimer();
  7862. }
  7863. timer.init = init;
  7864. })(timer || (timer = {}));
  7865.  
  7866. /**
  7867. * improve smelting dialog
  7868. */
  7869. var smelting;
  7870. (function (smelting)
  7871. {
  7872. smelting.name = 'smelting';
  7873. var TIME_NEEDED_ID = 'smelting-time-needed';
  7874. var LAST_SMELTING_AMOUNT_KEY = 'lastSmeltingAmount';
  7875. var LAST_SMELTING_BAR_KEY = 'lastSmeltingBar';
  7876. var smeltingValue = null;
  7877. var amountInput;
  7878.  
  7879. function prepareAmountInput()
  7880. {
  7881. amountInput = document.getElementById('input-smelt-bars-amount');
  7882. amountInput.type = 'number';
  7883. amountInput.min = '0';
  7884. amountInput.step = '5';
  7885.  
  7886. function onValueChange()
  7887. {
  7888. smeltingValue = null;
  7889. win.selectBar('', null, amountInput, document.getElementById('smelting-furnace-capacity').value);
  7890. }
  7891. amountInput.addEventListener('mouseup', onValueChange);
  7892. amountInput.addEventListener('keyup', onValueChange);
  7893. amountInput.setAttribute('onkeyup', '');
  7894. }
  7895.  
  7896. function setBarCap(bar, capacity)
  7897. {
  7898. if (bar == '')
  7899. {
  7900. bar = win.selectedBar;
  7901. }
  7902. var requirements = SMELTING_REQUIREMENTS[bar];
  7903. var maxAmount = parseInt(capacity, 10);
  7904. for (var key in requirements)
  7905. {
  7906. var req = requirements[key];
  7907. maxAmount = Math.min(Math.floor(getGameValue(key) / req), maxAmount);
  7908. }
  7909. var value = parseInt(amountInput.value, 10);
  7910. if (value > maxAmount)
  7911. {
  7912. smeltingValue = value;
  7913. amountInput.value = maxAmount.toString();
  7914. }
  7915. else if (smeltingValue != null)
  7916. {
  7917. amountInput.value = Math.min(smeltingValue, maxAmount).toString();
  7918. if (smeltingValue <= maxAmount)
  7919. {
  7920. smeltingValue = null;
  7921. }
  7922. }
  7923. }
  7924.  
  7925. function prepareTimeNeeded()
  7926. {
  7927. var neededMatsEl = document.getElementById('dialogue-furnace-mats-needed');
  7928. var parent = neededMatsEl && neededMatsEl.parentElement;
  7929. if (!neededMatsEl || !parent)
  7930. {
  7931. return;
  7932. }
  7933. var br = document.createElement('br');
  7934. var timeBox = document.createElement('div');
  7935. timeBox.className = 'basic-smallbox';
  7936. timeBox.innerHTML = "<img src=\"images/icons/hourglass.png\" class=\"image-icon-30\">\n\t\tDuration: <span id=\"" + TIME_NEEDED_ID + "\"></span>";
  7937. var next = neededMatsEl.nextElementSibling;
  7938. parent.insertBefore(br, next);
  7939. parent.insertBefore(timeBox, next);
  7940. }
  7941.  
  7942. function updateTimeNeeded(value)
  7943. {
  7944. var timeEl = document.getElementById(TIME_NEEDED_ID);
  7945. if (!timeEl)
  7946. {
  7947. return;
  7948. }
  7949. var num = parseInt(value, 10);
  7950. var timePerBar = win.getTimerPerBar(win.selectedBar);
  7951. timeEl.textContent = format.timer(timePerBar * num);
  7952. }
  7953.  
  7954. function init()
  7955. {
  7956. prepareAmountInput();
  7957. prepareTimeNeeded();
  7958. var _selectBar = win.selectBar;
  7959. var updateSmeltingRequirements = function (bar, inputElement, inputBarsAmountEl, capacity)
  7960. {
  7961. _selectBar(bar, inputElement, inputBarsAmountEl, capacity);
  7962. var matsArea = document.getElementById('dialogue-furnace-mats-needed');
  7963. if (matsArea)
  7964. {
  7965. matsArea.innerHTML = format.numbersInText(matsArea.innerHTML);
  7966. }
  7967. updateTimeNeeded(inputBarsAmountEl.value);
  7968. };
  7969. win.selectBar = function (bar, inputElement, inputBarsAmountEl, capacity)
  7970. {
  7971. setBarCap(bar, capacity);
  7972. // save selected bar
  7973. if (bar != '')
  7974. {
  7975. store.set(LAST_SMELTING_BAR_KEY, bar);
  7976. }
  7977. // save amount
  7978. store.set(LAST_SMELTING_AMOUNT_KEY, inputBarsAmountEl.value);
  7979. updateSmeltingRequirements(bar, inputElement, inputBarsAmountEl, capacity);
  7980. };
  7981. var lastBar = store.get(LAST_SMELTING_BAR_KEY);
  7982. var lastAmount = store.get(LAST_SMELTING_AMOUNT_KEY);
  7983. var _openFurnaceDialogue = win.openFurnaceDialogue;
  7984. win.openFurnaceDialogue = function (furnace)
  7985. {
  7986. var capacity = win.getFurnaceCapacity(furnace);
  7987. if (win.smeltingBarType == 0)
  7988. {
  7989. amountInput.max = capacity.toString();
  7990. }
  7991. // restore amount
  7992. var inputBarsAmountEl = document.getElementById('input-smelt-bars-amount');
  7993. if (inputBarsAmountEl && inputBarsAmountEl.value == '-1' && lastAmount != null)
  7994. {
  7995. inputBarsAmountEl.value = lastAmount;
  7996. }
  7997. _openFurnaceDialogue(furnace);
  7998. // restore selected bar
  7999. if ((!win.selectedBar || win.selectedBar == 'none') && lastBar != null)
  8000. {
  8001. win.selectedBar = lastBar;
  8002. }
  8003. // update whether requirements are fulfilled
  8004. var barInputId = 'input-furnace-' + split2Words(win.selectedBar, '-').toLowerCase();
  8005. var inputElement = document.getElementById(barInputId);
  8006. if (inputElement && inputBarsAmountEl)
  8007. {
  8008. updateSmeltingRequirements(win.selectedBar, inputElement, inputBarsAmountEl, capacity.toString());
  8009. }
  8010. };
  8011. }
  8012. smelting.init = init;
  8013. })(smelting || (smelting = {}));
  8014.  
  8015. /**
  8016. * add chance to time calculator
  8017. */
  8018. var fishingInfo;
  8019. (function (fishingInfo)
  8020. {
  8021. fishingInfo.name = 'fishingInfo';
  8022. /**
  8023. * calculates the number of seconds until the event with the given chance happened at least once with the given
  8024. * probability p (in percent)
  8025. */
  8026. function calcSecondsTillP(chancePerSecond, p)
  8027. {
  8028. return Math.round(Math.log(1 - p / 100) / Math.log(1 - chancePerSecond));
  8029. }
  8030.  
  8031. function addChanceTooltip(headline, chancePerSecond, elId, targetEl)
  8032. {
  8033. // ensure tooltip exists and is correctly binded
  8034. var tooltipEl = ensureTooltip('chance-' + elId, targetEl);
  8035. // set elements content
  8036. var percValues = [1, 10, 20, 50, 80, 90, 99];
  8037. var percRows = '';
  8038. for (var _i = 0, percValues_1 = percValues; _i < percValues_1.length; _i++)
  8039. {
  8040. var p = percValues_1[_i];
  8041. 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>";
  8042. }
  8043. 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";
  8044. }
  8045.  
  8046. function addChanceStyle()
  8047. {
  8048. 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");
  8049. }
  8050.  
  8051. function addXp()
  8052. {
  8053. var table = document.querySelector('#dialogue-id-fishingRod table');
  8054. if (!table)
  8055. {
  8056. return;
  8057. }
  8058. var rows = table.rows;
  8059. for (var i = 0; i < rows.length; i++)
  8060. {
  8061. var row = rows.item(i);
  8062. if (row.classList.contains('xp-added'))
  8063. {
  8064. continue;
  8065. }
  8066. if (i == 0)
  8067. {
  8068. var xpCell = document.createElement('th');
  8069. xpCell.textContent = 'XP';
  8070. row.appendChild(xpCell);
  8071. }
  8072. else
  8073. {
  8074. var cell = row.insertCell(-1);
  8075. var rawFish = row.id.replace('dialogue-fishing-rod-tr-', '');
  8076. var xp = FISH_XP[rawFish];
  8077. cell.textContent = xp == null ? '?' : format.number(xp);
  8078. }
  8079. row.classList.add('xp-added');
  8080. }
  8081. }
  8082.  
  8083. function chance2TimeCalculator()
  8084. {
  8085. var table = document.querySelector('#dialogue-id-fishingRod table');
  8086. if (!table)
  8087. {
  8088. return;
  8089. }
  8090. var rows = table.rows;
  8091. for (var i = 1; i < rows.length; i++)
  8092. {
  8093. var row = rows.item(i);
  8094. var rawFish = row.id.replace('dialogue-fishing-rod-tr-', '');
  8095. var fish = rawFish.replace('raw', '').toLowerCase();
  8096. if (!rawFish || !fish)
  8097. {
  8098. continue;
  8099. }
  8100. var chanceCell = row.cells.item(row.cells.length - 2);
  8101. var chance = (chanceCell.textContent || '')
  8102. .replace(/[^\d\/]/g, '')
  8103. .split('/')
  8104. .reduce(function (p, c)
  8105. {
  8106. return p / parseInt(c, 10);
  8107. }, 1);
  8108. addChanceTooltip("One raw " + fish + " at least every:", chance, rawFish, row);
  8109. }
  8110. }
  8111.  
  8112. function init()
  8113. {
  8114. addChanceStyle();
  8115. var _clicksShovel = win.clicksShovel;
  8116. win.clicksShovel = function ()
  8117. {
  8118. _clicksShovel();
  8119. var shovelChance = document.getElementById('dialogue-shovel-chance');
  8120. var titleEl = shovelChance.parentElement;
  8121. var chance = 1 / win.getChanceOfDiggingSand();
  8122. addChanceTooltip('One sand at least every:', chance, 'shovel', titleEl);
  8123. };
  8124. // depends on fishingXp
  8125. var _clicksFishingRod = win.clicksFishingRod;
  8126. win.clicksFishingRod = function ()
  8127. {
  8128. _clicksFishingRod();
  8129. addXp();
  8130. chance2TimeCalculator();
  8131. };
  8132. }
  8133. fishingInfo.init = init;
  8134. })(fishingInfo || (fishingInfo = {}));
  8135.  
  8136. /**
  8137. * add tooltips for recipes
  8138. */
  8139. var recipeTooltips;
  8140. (function (recipeTooltips)
  8141. {
  8142. recipeTooltips.name = 'recipeTooltips';
  8143.  
  8144. function updateRecipeTooltips(recipeKey, recipes)
  8145. {
  8146. var table = document.getElementById('table-' + recipeKey + '-recipe');
  8147. var rows = table.rows;
  8148.  
  8149. function recipe2Title(recipe)
  8150. {
  8151. return recipe.recipe
  8152. .map(function (name, i)
  8153. {
  8154. return format.number(recipe.recipeCost[i]) + String.fromCharCode(160)
  8155. + split2Words(name).toLowerCase();
  8156. })
  8157. .join(' + ');
  8158. };
  8159. for (var i = 1; i < rows.length; i++)
  8160. {
  8161. var row = rows.item(i);
  8162. var key = row.id.replace(recipeKey + '-', '');
  8163. var recipe = recipes[key];
  8164. var requirementCell = row.cells.item(3);
  8165. requirementCell.title = recipe2Title(recipe);
  8166. win.$(requirementCell).tooltip();
  8167. }
  8168. }
  8169.  
  8170. function updateTooltipsOnReinitRecipes(key)
  8171. {
  8172. var capitalKey = capitalize(key);
  8173. var processKey = 'process' + capitalKey + 'Tab';
  8174. var _processTab = win[processKey];
  8175. win[processKey] = function ()
  8176. {
  8177. var reinit = !!getGameValue('refreshLoad' + capitalKey + 'Table');
  8178. _processTab();
  8179. if (reinit)
  8180. {
  8181. updateRecipeTooltips(key, getGameValue(key + 'Recipes'));
  8182. }
  8183. };
  8184. }
  8185.  
  8186. function init()
  8187. {
  8188. updateTooltipsOnReinitRecipes('crafting');
  8189. updateTooltipsOnReinitRecipes('brewing');
  8190. updateTooltipsOnReinitRecipes('magic');
  8191. updateTooltipsOnReinitRecipes('cooksBook');
  8192. }
  8193. recipeTooltips.init = init;
  8194. })(recipeTooltips || (recipeTooltips = {}));
  8195.  
  8196. /**
  8197. * fix formatting of numbers
  8198. */
  8199. var fixNumbers;
  8200. (function (fixNumbers)
  8201. {
  8202. fixNumbers.name = 'fixNumbers';
  8203.  
  8204. function prepareRecipeForTable(recipe)
  8205. {
  8206. // create a copy of the recipe to prevent requirement check from failing
  8207. var newRecipe = JSON.parse(JSON.stringify(recipe));
  8208. newRecipe.recipeCost = recipe.recipeCost.map(function (cost)
  8209. {
  8210. return format.number(cost);
  8211. });
  8212. newRecipe.description = format.numbersInText(newRecipe.description);
  8213. newRecipe.xp = format.number(recipe.xp);
  8214. return newRecipe;
  8215. }
  8216.  
  8217. function init()
  8218. {
  8219. var _addRecipeToBrewingTable = win.addRecipeToBrewingTable;
  8220. win.addRecipeToBrewingTable = function (brewingRecipe)
  8221. {
  8222. _addRecipeToBrewingTable(prepareRecipeForTable(brewingRecipe));
  8223. };
  8224. var _addRecipeToMagicTable = win.addRecipeToMagicTable;
  8225. win.addRecipeToMagicTable = function (magicRecipe)
  8226. {
  8227. _addRecipeToMagicTable(prepareRecipeForTable(magicRecipe));
  8228. };
  8229. var _addRecipeToCooksBookTable = win.addRecipeToCooksBookTable;
  8230. win.addRecipeToCooksBookTable = function (cooksBookRecipe)
  8231. {
  8232. _addRecipeToCooksBookTable(prepareRecipeForTable(cooksBookRecipe));
  8233. };
  8234. var tooltipList = document.querySelectorAll('#tooltip-list div[id^="tooltip-"][id$="Seeds"]');
  8235. for (var i = 0; i < tooltipList.length; i++)
  8236. {
  8237. var tooltip = tooltipList[i];
  8238. tooltip.innerHTML = format.numbersInText(tooltip.innerHTML);
  8239. }
  8240. var fightEnergyCells = document.querySelectorAll('#dialogue-fight tr > td:nth-child(4)');
  8241. for (var i = 0; i < fightEnergyCells.length; i++)
  8242. {
  8243. var cell = fightEnergyCells[i];
  8244. cell.innerHTML = format.numbersInText(cell.innerHTML);
  8245. }
  8246. var _rocketTick = win.rocketTick;
  8247. win.rocketTick = function ()
  8248. {
  8249. _rocketTick();
  8250. var rocketBox = document.getElementById('itembox-rocket');
  8251. if (rocketBox && /^\d+\s*Km$/i.test(rocketBox.textContent || ''))
  8252. {
  8253. rocketBox.innerHTML = format.numbersInText(rocketBox.innerHTML).replace('Km', 'km');
  8254. }
  8255. };
  8256. }
  8257. fixNumbers.init = init;
  8258. })(fixNumbers || (fixNumbers = {}));
  8259.  
  8260. /**
  8261. * add slider for machines
  8262. */
  8263. var machineDialog;
  8264. (function (machineDialog)
  8265. {
  8266. machineDialog.name = 'machineDialog';
  8267. var $slider;
  8268.  
  8269. function createSlider()
  8270. {
  8271. var br = document.querySelector('#dialogue-machinery-current-total ~ br');
  8272. var parent = br && br.parentElement;
  8273. if (!br || !parent)
  8274. {
  8275. return;
  8276. }
  8277. 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");
  8278. var slider = document.createElement('div');
  8279. parent.insertBefore(slider, br);
  8280. $slider = win.$(slider)
  8281. .slider(
  8282. {
  8283. range: 'max'
  8284. , min: 0
  8285. , max: 10
  8286. , value: 0
  8287. , slide: function (event, ui)
  8288. {
  8289. return updateValue(ui.value);
  8290. }
  8291. });
  8292. // hide br and up/down arrows
  8293. br.style.display = 'none';
  8294. var arrows = document.querySelectorAll('input[onclick^="turnOn("]');
  8295. for (var i = 0; i < arrows.length; i++)
  8296. {
  8297. arrows[i].style.display = 'none';
  8298. }
  8299. var els = document.querySelectorAll('[onclick*="openMachineryDialogue("]');
  8300. var boundMachineKeyList = [];
  8301. for (var i = 0; i < els.length; i++)
  8302. {
  8303. var match = els[i].id.match(/openMachineryDialogue\('(.+?)'\)/);
  8304. if (match)
  8305. {
  8306. boundMachineKeyList.push(getBoundKey(match[1]));
  8307. }
  8308. }
  8309. observer.add(boundMachineKeyList, function ()
  8310. {
  8311. return updateMax();
  8312. });
  8313. }
  8314.  
  8315. function updateMax()
  8316. {
  8317. var machineEl = document.getElementById('dialogue-machinery-chosen');
  8318. if (machineEl && machineEl.value != '')
  8319. {
  8320. var boundMachineKey = getBoundKey(machineEl.value);
  8321. var ownedNum = getGameValue(boundMachineKey);
  8322. $slider.slider('option', 'max', ownedNum);
  8323. $slider.get(0).dataset.owned = ownedNum.toString();
  8324. }
  8325. }
  8326.  
  8327. function updateValue(value)
  8328. {
  8329. var typeEl = document.getElementById('dialogue-machinery-chosen');
  8330. var numEl = document.getElementById('dialogue-machinery-current-on');
  8331. if (numEl && typeEl)
  8332. {
  8333. var valueBefore = parseInt(numEl.textContent || '0', 10);
  8334. var machine = typeEl.value;
  8335. var increment = valueBefore < value;
  8336. var diff = Math.abs(valueBefore - value);
  8337. for (var i = 0; i < diff; i++)
  8338. {
  8339. win.turnOn(machine, increment);
  8340. }
  8341. }
  8342. }
  8343.  
  8344. function init()
  8345. {
  8346. if (!settings.get(settings.KEY.changeMachineDialog))
  8347. {
  8348. return;
  8349. }
  8350. createSlider();
  8351. var _openMachineryDialogue = win.openMachineryDialogue;
  8352. win.openMachineryDialogue = function (machineType)
  8353. {
  8354. _openMachineryDialogue(machineType);
  8355. updateMax();
  8356. $slider.slider('value', getGameValue(machineType + 'On'));
  8357. };
  8358. }
  8359. machineDialog.init = init;
  8360. })(machineDialog || (machineDialog = {}));
  8361.  
  8362. /**
  8363. * improve behaviour of amount inputs
  8364. */
  8365. var amountInputs;
  8366. (function (amountInputs)
  8367. {
  8368. amountInputs.name = 'amountInputs';
  8369.  
  8370. function getVialType(recipe)
  8371. {
  8372. return recipe.levelReq < 35 ? 'vialOfWater' : (recipe.levelReq < 65 ? 'largeVialOfWater' : 'hugeVialOfWater');
  8373. }
  8374.  
  8375. function getSimpleMax(recipe)
  8376. {
  8377. var max = Number.MAX_SAFE_INTEGER;
  8378. for (var i = 0; i < recipe.recipe.length; i++)
  8379. {
  8380. max = Math.min(max, Math.floor(getGameValue(recipe.recipe[i]) / recipe.recipeCost[i]));
  8381. }
  8382. return max;
  8383. }
  8384.  
  8385. function getMax(recipe)
  8386. {
  8387. var max = getSimpleMax(recipe);
  8388. if (/Potion$/.test(recipe.itemName))
  8389. {
  8390. var vialType = getVialType(recipe);
  8391. max = Math.min(max, getGameValue(vialType));
  8392. }
  8393. return max;
  8394. }
  8395.  
  8396. function ensureNumberInput(idOrEl)
  8397. {
  8398. var numInput = typeof idOrEl === 'string' ? document.getElementById(idOrEl) : idOrEl;
  8399. if (numInput)
  8400. {
  8401. if (numInput.type != 'number' && settings.get(settings.KEY.makeNumberInputs))
  8402. {
  8403. var width = numInput.clientWidth;
  8404. if (width !== 0)
  8405. {
  8406. numInput.style.width = width + 'px';
  8407. }
  8408. numInput.type = 'number';
  8409. numInput.min = '0';
  8410. var onkeyup_1 = numInput.getAttribute('onkeyup');
  8411. if (onkeyup_1)
  8412. {
  8413. numInput.setAttribute('onmouseup', onkeyup_1);
  8414. }
  8415. }
  8416. else if (numInput.type == 'number' && !settings.get(settings.KEY.makeNumberInputs))
  8417. {
  8418. numInput.style.width = '';
  8419. numInput.type = '';
  8420. numInput.removeAttribute('onmouseup');
  8421. }
  8422. }
  8423. return numInput;
  8424. }
  8425.  
  8426. function getCurrentMax(keyId, recipeCollection)
  8427. {
  8428. var keyEl = document.getElementById(keyId);
  8429. if (!keyEl)
  8430. {
  8431. return 0;
  8432. }
  8433. var key = keyEl.value;
  8434. return getMax(recipeCollection[key]);
  8435. };
  8436.  
  8437. function ensureMaxBtn(keyId, inputId, recipeCollection, key)
  8438. {
  8439. var recipe = recipeCollection[key];
  8440. var numInput = ensureNumberInput(inputId);
  8441. var next = numInput && numInput.nextElementSibling;
  8442. var parent = numInput && numInput.parentElement;
  8443. if (numInput && parent)
  8444. {
  8445. if ((!next || next.nodeName !== 'BUTTON') && settings.get(settings.KEY.addMaxBtn))
  8446. {
  8447. var btn = document.createElement('button');
  8448. btn.textContent = 'Max';
  8449. btn.addEventListener('click', function ()
  8450. {
  8451. numInput.value = getCurrentMax(keyId, recipeCollection).toString();
  8452. });
  8453. parent.appendChild(btn);
  8454. }
  8455. else if (next && next.nodeName === 'BUTTON' && !settings.get(settings.KEY.addMaxBtn))
  8456. {
  8457. parent.removeChild(next);
  8458. }
  8459. numInput.value = Math.min(1, getMax(recipe)).toString();
  8460. numInput.select();
  8461. }
  8462. }
  8463.  
  8464. function watchKeepInput(event)
  8465. {
  8466. var itemInput = document.getElementById('npc-sell-item-chosen');
  8467. var numInput = ensureNumberInput('dialogue-input-cmd');
  8468. if (!itemInput || !numInput)
  8469. {
  8470. return;
  8471. }
  8472. var item = itemInput.value;
  8473. var newValue = Math.max(getGameValue(item) - Number(this.value), 0);
  8474. numInput.value = newValue.toString();
  8475. }
  8476.  
  8477. function updateKeepMaxValue(keepInput, init)
  8478. {
  8479. if (init === void 0)
  8480. {
  8481. init = false;
  8482. }
  8483. var itemInput = document.getElementById('npc-sell-item-chosen');
  8484. if (!itemInput)
  8485. {
  8486. return;
  8487. }
  8488. var item = itemInput.value;
  8489. var max = getGameValue(item);
  8490. keepInput.max = max.toString();
  8491. if (init)
  8492. {
  8493. observer.addTick(function ()
  8494. {
  8495. return updateKeepMaxValue(keepInput);
  8496. });
  8497. }
  8498. }
  8499.  
  8500. function ensureKeepInput(item)
  8501. {
  8502. var numInput = ensureNumberInput('dialogue-input-cmd');
  8503. var parent = numInput && numInput.parentElement;
  8504. var next = numInput && numInput.nextElementSibling;
  8505. var nextNext = next && next.nextElementSibling;
  8506. if (next && nextNext && parent)
  8507. {
  8508. if (nextNext.nodeName === 'BR' && settings.get(settings.KEY.addKeepInput))
  8509. {
  8510. var div = document.createElement('div');
  8511. var text = document.createTextNode('Keep: ');
  8512. div.appendChild(text);
  8513. var keepInput = document.createElement('input');
  8514. keepInput.type = 'number';
  8515. keepInput.value = keepInput.min = '0';
  8516. keepInput.max = getGameValue(item).toString();
  8517. keepInput.addEventListener('keyup', watchKeepInput);
  8518. keepInput.addEventListener('mouseup', watchKeepInput);
  8519. updateKeepMaxValue(keepInput, true);
  8520. div.appendChild(keepInput);
  8521. parent.insertBefore(div, nextNext);
  8522. }
  8523. else if (nextNext.nodeName !== 'BR' && !settings.get(settings.KEY.addKeepInput))
  8524. {
  8525. var br = document.createElement('br');
  8526. parent.insertBefore(br, nextNext);
  8527. parent.removeChild(nextNext);
  8528. }
  8529. }
  8530. }
  8531.  
  8532. function init()
  8533. {
  8534. var _multiCraft = win.multiCraft;
  8535. win.multiCraft = function (item)
  8536. {
  8537. _multiCraft(item);
  8538. ensureMaxBtn('dialogue-multicraft-chosen', 'dialogue-multicraft-input', win.craftingRecipes, item);
  8539. };
  8540. var _brew = win.brew;
  8541. win.brew = function (potion)
  8542. {
  8543. _brew(potion);
  8544. ensureMaxBtn('dialogue-potion-chosen', 'dialogue-brewing-input', win.brewingRecipes, potion);
  8545. };
  8546. var _cooksBookInputDialogue = win.cooksBookInputDialogue;
  8547. win.cooksBookInputDialogue = function (food)
  8548. {
  8549. _cooksBookInputDialogue(food);
  8550. ensureMaxBtn('dialogue-cooksBook-chosen', 'dialogue-cooksBook-input', win.cooksBookRecipes, food);
  8551. };
  8552. var _openSellNPCDialogue = win.openSellNPCDialogue;
  8553. win.openSellNPCDialogue = function (item)
  8554. {
  8555. _openSellNPCDialogue(item);
  8556. ensureKeepInput(item);
  8557. };
  8558. var allowedInputs = [
  8559. 'dialogue-ashes'
  8560. , 'dialogue-bindDonorCoins'
  8561. , 'dialogue-bonemeal'
  8562. , 'dialogue-bones'
  8563. , 'dialogue-brewing'
  8564. , 'dialogue-buy-item-2'
  8565. , 'dialogue-buyFromMarket'
  8566. , 'dialogue-charcoalFoundry'
  8567. , 'dialogue-consume'
  8568. , 'dialogue-cooksBook'
  8569. , 'dialogue-createArrows'
  8570. , 'dialogue-createFireArrows'
  8571. , 'dialogue-createIceArrows'
  8572. , 'dialogue-furnace'
  8573. , 'dialogue-iceBones'
  8574. , 'dialogue-id-boundHammer'
  8575. , 'dialogue-id-boundPickaxe'
  8576. , 'dialogue-id-cook-food'
  8577. , 'dialogue-id-oven-addheat'
  8578. , 'dialogue-market-chosenpostitem'
  8579. , 'dialogue-multicraft'
  8580. , 'dialogue-oilBarrels'
  8581. , 'dialogue-oilFactory'
  8582. , 'dialogue-sell-item'
  8583. , 'dialogue-stardustCrystals'
  8584. , 'dialogue-wand'
  8585. ];
  8586. var _openDialogue = win.openDialogue;
  8587. win.openDialogue = function (id, width, position)
  8588. {
  8589. _openDialogue(id, width, position);
  8590. if (allowedInputs.indexOf(id) === -1
  8591. || id === 'dialogue-buyFromMarket' && market.detectTedsUI()
  8592. || id === 'dialogue-market-chosenpostitem' && market.detectTedsUI())
  8593. {
  8594. return;
  8595. }
  8596. var dialog = document.getElementById(id);
  8597. var input = dialog && dialog.querySelector('input[type="text"],input[type="number"]');
  8598. if (!input)
  8599. {
  8600. return;
  8601. }
  8602. ensureNumberInput(input);
  8603. };
  8604. }
  8605. amountInputs.init = init;
  8606. })(amountInputs || (amountInputs = {}));
  8607.  
  8608. /**
  8609. * improves the top bar
  8610. */
  8611. var newTopbar;
  8612. (function (newTopbar)
  8613. {
  8614. newTopbar.name = 'newTopbar';
  8615. var linkCell, tabCell, infoCell;
  8616. var addQueues = {
  8617. link: []
  8618. , tab: []
  8619. , info: []
  8620. };
  8621.  
  8622. function createPipeNode()
  8623. {
  8624. return document.createTextNode('|');
  8625. }
  8626.  
  8627. function addLinkEntry(el)
  8628. {
  8629. if (!linkCell)
  8630. {
  8631. addQueues.link.push(el);
  8632. }
  8633. else
  8634. {
  8635. linkCell.appendChild(createPipeNode());
  8636. linkCell.appendChild(el);
  8637. }
  8638. }
  8639. newTopbar.addLinkEntry = addLinkEntry;
  8640.  
  8641. function addTabEntry(el)
  8642. {
  8643. if (!tabCell)
  8644. {
  8645. addQueues.tab.push(el);
  8646. }
  8647. else
  8648. {
  8649. tabCell.appendChild(createPipeNode());
  8650. tabCell.appendChild(el);
  8651. }
  8652. }
  8653. newTopbar.addTabEntry = addTabEntry;
  8654.  
  8655. function addInfoEntry(el)
  8656. {
  8657. if (!infoCell)
  8658. {
  8659. addQueues.info.push(el);
  8660. }
  8661. else
  8662. {
  8663. if (infoCell.firstChild)
  8664. {
  8665. infoCell.insertBefore(createPipeNode(), infoCell.firstChild);
  8666. infoCell.insertBefore(el, infoCell.firstChild);
  8667. }
  8668. else
  8669. {
  8670. infoCell.appendChild(createPipeNode());
  8671. infoCell.appendChild(el);
  8672. }
  8673. }
  8674. }
  8675. newTopbar.addInfoEntry = addInfoEntry;
  8676.  
  8677. function init()
  8678. {
  8679. if (!settings.get(settings.KEY.useNewToolbar))
  8680. {
  8681. return;
  8682. }
  8683. 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");
  8684. var table = document.querySelector('table.top-links');
  8685. if (!table)
  8686. {
  8687. return;
  8688. }
  8689. var row = table.rows.item(0);
  8690. var cells = row.cells;
  8691. var tabIdx = [2, 5];
  8692. var infoIdx = [6, 7];
  8693. var newRow = table.insertRow(-1);
  8694. linkCell = newRow.insertCell(-1);
  8695. tabCell = newRow.insertCell(-1);
  8696. tabCell.style.textAlign = 'center';
  8697. infoCell = newRow.insertCell(-1);
  8698. infoCell.style.textAlign = 'right';
  8699. for (var i = 0; i < cells.length; i++)
  8700. {
  8701. var container = linkCell;
  8702. if (tabIdx.indexOf(i) != -1)
  8703. {
  8704. container = tabCell;
  8705. }
  8706. else if (infoIdx.indexOf(i) != -1)
  8707. {
  8708. container = infoCell;
  8709. }
  8710. var cell = cells.item(i);
  8711. var el = cell.firstElementChild;
  8712. if (cell.childNodes.length > 1)
  8713. {
  8714. el = document.createElement('span');
  8715. el.style.color = 'yellow';
  8716. while (cell.childNodes.length > 0)
  8717. {
  8718. el.appendChild(cell.childNodes[0]);
  8719. }
  8720. }
  8721. if (container.children.length > 0)
  8722. {
  8723. container.appendChild(createPipeNode());
  8724. }
  8725. if (el)
  8726. {
  8727. container.appendChild(el);
  8728. }
  8729. }
  8730. var parent = row.parentElement;
  8731. if (parent)
  8732. {
  8733. parent.removeChild(row);
  8734. }
  8735. for (var _i = 0, _a = addQueues.link; _i < _a.length; _i++)
  8736. {
  8737. var el = _a[_i];
  8738. addLinkEntry(el);
  8739. }
  8740. for (var _b = 0, _c = addQueues.tab; _b < _c.length; _b++)
  8741. {
  8742. var el = _c[_b];
  8743. addTabEntry(el);
  8744. }
  8745. for (var _d = 0, _e = addQueues.info; _d < _e.length; _d++)
  8746. {
  8747. var el = _e[_d];
  8748. addInfoEntry(el);
  8749. }
  8750. var _openTab = win.openTab;
  8751. win.openTab = function (newTab)
  8752. {
  8753. var oldTab = win.currentOpenTab;
  8754. _openTab(newTab);
  8755. var children = tabCell.children;
  8756. for (var i = 0; i < children.length; i++)
  8757. {
  8758. var el = children[i];
  8759. var match = (el.getAttribute('onclick') || '').match(/openTab\('([^']+)'\)/);
  8760. if (!match)
  8761. {
  8762. continue;
  8763. }
  8764. var tab = match[1];
  8765. if (oldTab == tab)
  8766. {
  8767. el.style.color = '';
  8768. }
  8769. if (newTab == tab)
  8770. {
  8771. el.style.color = 'white';
  8772. }
  8773. }
  8774. };
  8775. }
  8776. newTopbar.init = init;
  8777. })(newTopbar || (newTopbar = {}));
  8778.  
  8779. /**
  8780. * style tweaks
  8781. */
  8782. var styleTweaks;
  8783. (function (styleTweaks)
  8784. {
  8785. styleTweaks.name = 'styleTweaks';
  8786. var bodyRegex = /(\bbody)(\s|$)/i;
  8787.  
  8788. function addTweakStyle(setting, style)
  8789. {
  8790. if (setting != '')
  8791. {
  8792. var prefix_1 = setting === '' ? '' : 'body.' + setting + ' ';
  8793. style = style
  8794. .replace(/(^\s*|\}\s*)([^\{\}]+)(?=\s*\{)/g, function (wholeMatch, before, rules)
  8795. {
  8796. return before + rules.split(',').map(function (rule)
  8797. {
  8798. if (bodyRegex.test(rule) && setting !== '')
  8799. {
  8800. return rule.replace(bodyRegex, '$1.' + setting + '$2');
  8801. }
  8802. return rule.replace(/^(\s*\n\s*)?/, '$1' + prefix_1);
  8803. }).join(',');
  8804. });
  8805. document.body.classList.add(setting);
  8806. }
  8807. addStyle(style, setting != '' ? setting : null);
  8808. }
  8809. // tweak oil production/consumption
  8810. function tweakOil()
  8811. {
  8812. 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");
  8813. // make room for oil cell on small devices
  8814. var oilFlowValues = document.getElementById('oil-flow-values');
  8815. var oilFlowCell = oilFlowValues.parentElement;
  8816. oilFlowCell.style.width = '30%';
  8817. }
  8818.  
  8819. function tweakSelection()
  8820. {
  8821. 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");
  8822. }
  8823. // tweak stardust monitor of DH2QoL to keep it in place
  8824. function tweakStardust()
  8825. {
  8826. 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");
  8827. }
  8828.  
  8829. function tweakSkillLevelText()
  8830. {
  8831. addTweakStyle('', "\ndiv.skill-xp-label\n{\n\ttext-shadow: white 0px 0px 0.5rem;\n}\n\t\t");
  8832. }
  8833.  
  8834. function tweakFightDialog()
  8835. {
  8836. 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");
  8837. }
  8838.  
  8839. function addAdditionalSkillBars()
  8840. {
  8841. if (!settings.get(settings.KEY.skillBars)){
  8842. return;
  8843. }
  8844. var _loadSkillTabs = win.loadSkillTabs;
  8845. win.loadSkillTabs = function ()
  8846. {
  8847. _loadSkillTabs();
  8848. for (var _i = 0, SKILL_LIST_1 = SKILL_LIST; _i < SKILL_LIST_1.length; _i++)
  8849. {
  8850. var skill = SKILL_LIST_1[_i];
  8851. var unlocked = getGameValue(skill + 'Unlocked') == 1;
  8852. if (!unlocked)
  8853. {
  8854. continue;
  8855. }
  8856. var xp = getGameValue(skill + 'Xp');
  8857. var currentLevelXp = win.getXpNeeded(win.getLevel(xp));
  8858. var nextLevelXp = win.getXpNeeded(win.getLevel(xp) + 1);
  8859. var perc = (xp - currentLevelXp) / (nextLevelXp - currentLevelXp) * 100;
  8860. var progress = document.getElementById('skill-progress-' + skill);
  8861. if (progress)
  8862. {
  8863. if (currentLevelXp >= 10000000)
  8864. {
  8865. perc = 100;
  8866. progress.style.backgroundColor = "yellow";
  8867. }
  8868. progress.style.width = perc + '%';
  8869. }
  8870. }
  8871. };
  8872. // init additional skill bars
  8873. 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");
  8874. for (var _i = 0, SKILL_LIST_2 = SKILL_LIST; _i < SKILL_LIST_2.length; _i++)
  8875. {
  8876. var skill = SKILL_LIST_2[_i];
  8877. var cell = document.getElementById('top-bar-level-td-' + skill);
  8878. if (!cell)
  8879. {
  8880. continue;
  8881. }
  8882. var levelBar = document.createElement('div');
  8883. levelBar.className = 'skill-bar';
  8884. var progress = document.createElement('div');
  8885. progress.id = 'skill-progress-' + skill;
  8886. progress.className = 'skill-progress';
  8887. levelBar.appendChild(progress);
  8888. cell.appendChild(levelBar);
  8889. // update skill level progress bars on click
  8890. levelBar.addEventListener('click', function ()
  8891. {
  8892. return win.loadSkillTabs();
  8893. });
  8894. }
  8895. win.loadSkillTabs();
  8896. }
  8897. // highlight cooking level requirement when not matched
  8898. function highlightCookinglevel()
  8899. {
  8900. var _cookFoodDialogue = win.cookFoodDialogue;
  8901. win.cookFoodDialogue = function (rawFood)
  8902. {
  8903. _cookFoodDialogue(rawFood);
  8904. var dialog = document.getElementById('dialogue-id-cook-food');
  8905. if (!dialog)
  8906. {
  8907. return;
  8908. }
  8909. var levelReq = document.getElementById('dialogue-cook-levelReq');
  8910. var levelReqLabel = levelReq && levelReq.previousElementSibling;
  8911. if (!levelReq || !levelReqLabel)
  8912. {
  8913. return;
  8914. }
  8915. var fulfilled = win.getCookingLevelReq(rawFood) > win.getLevel(win.cookingXp);
  8916. levelReq.style.color = fulfilled ? 'rgb(204, 0, 0)' : '';
  8917. levelReq.style.fontWeight = fulfilled ? 'bold' : '';
  8918. levelReqLabel.style.color = fulfilled ? 'rgb(204, 0, 0)' : '';
  8919. var ratioEl = document.getElementById('dialogue-cook-ratio');
  8920. if (!ratioEl)
  8921. {
  8922. var cookReqBox = levelReq.parentElement;
  8923. var br = document.createElement('br');
  8924. cookReqBox.appendChild(br);
  8925. var b = document.createElement('b');
  8926. 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\">: ";
  8927. cookReqBox.appendChild(b);
  8928. ratioEl = document.createElement('span');
  8929. ratioEl.id = 'dialogue-cook-ratio';
  8930. cookReqBox.appendChild(ratioEl);
  8931. }
  8932. var heat = win.getHeatNeeded(rawFood);
  8933. var energy = win.getEnergyGained(rawFood);
  8934. ratioEl.textContent = format.number(Math.round(energy / heat * 100) / 100);
  8935. };
  8936. }
  8937.  
  8938. function amountStyle()
  8939. {
  8940. var tweakName = 'amount-symbol';
  8941. 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");
  8942.  
  8943. function setAmountSymbolVisibility(init)
  8944. {
  8945. if (init === void 0)
  8946. {
  8947. init = false;
  8948. }
  8949. var show = settings.get(settings.KEY.amountSymbol);
  8950. document.body.classList[show ? 'add' : 'remove'](tweakName);
  8951. if (init)
  8952. {
  8953. settings.observe(settings.KEY.amountSymbol, function ()
  8954. {
  8955. return setAmountSymbolVisibility();
  8956. });
  8957. }
  8958. }
  8959. setAmountSymbolVisibility(true);
  8960. }
  8961.  
  8962. function efficiency()
  8963. {
  8964. var EFFICIENCY_CLASS = 'efficiency';
  8965. 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");
  8966. var farmingTab = document.getElementById('tab-container-farming');
  8967. if (farmingTab)
  8968. {
  8969. removeWhitespaceChildNodes(farmingTab);
  8970. }
  8971. var combatSubTab = document.getElementById('tab-sub-container-combat');
  8972. if (combatSubTab)
  8973. {
  8974. removeWhitespaceChildNodes(combatSubTab);
  8975. }
  8976.  
  8977. function checkSetting(init)
  8978. {
  8979. if (init === void 0)
  8980. {
  8981. init = false;
  8982. }
  8983. var show = settings.get(settings.KEY.useEfficiencyStyle);
  8984. document.body.classList[show ? 'add' : 'remove'](EFFICIENCY_CLASS);
  8985. if (init)
  8986. {
  8987. settings.observe(settings.KEY.useEfficiencyStyle, function ()
  8988. {
  8989. return checkSetting();
  8990. });
  8991. }
  8992. }
  8993. checkSetting(true);
  8994. }
  8995.  
  8996. function hardcore()
  8997. {
  8998. if (win.isHardcore != 1)
  8999. {
  9000. return;
  9001. }
  9002. addStyle("\nspan#shop-giant-button-playermarket\n{\n\tbackground-color: gray;\n\tbackground-image: none;\n\tcursor: not-allowed;\n}\n\t\t");
  9003. var marketBtn = document.getElementById('shop-giant-button-playermarket');
  9004. if (marketBtn)
  9005. {
  9006. marketBtn.removeAttribute('onclick');
  9007. marketBtn.setAttribute('title', 'The player market is disabled for hardcore accounts');
  9008. }
  9009. }
  9010.  
  9011. function smallScreen()
  9012. {
  9013. addStyle("\ntable.top-links\n{\n\tz-index: 10;\n}\n\t\t");
  9014. }
  9015.  
  9016. function init()
  9017. {
  9018. tweakOil();
  9019. tweakSelection();
  9020. tweakStardust();
  9021. tweakSkillLevelText();
  9022. tweakFightDialog();
  9023. addAdditionalSkillBars();
  9024. highlightCookinglevel();
  9025. amountStyle();
  9026. efficiency();
  9027. //hardcore();
  9028. smallScreen();
  9029. }
  9030. styleTweaks.init = init;
  9031. })(styleTweaks || (styleTweaks = {}));
  9032.  
  9033. /**
  9034. * add ingame notification boxes
  9035. */
  9036. var notifBoxes;
  9037. (function (notifBoxes)
  9038. {
  9039. notifBoxes.name = 'notifBoxes';
  9040.  
  9041. function addNotifBox(imageKey, itemKey, showFront)
  9042. {
  9043. if (itemKey === void 0)
  9044. {
  9045. itemKey = null;
  9046. }
  9047. if (showFront === void 0)
  9048. {
  9049. showFront = false;
  9050. }
  9051. var notifBox = document.createElement('span');
  9052. notifBox.className = 'notif-box';
  9053. notifBox.id = 'notification-static-' + imageKey;
  9054. notifBox.style.display = 'none';
  9055. if (showFront)
  9056. {
  9057. notifBox.style.cssFloat = 'left';
  9058. }
  9059. notifBox.innerHTML = "<img src=\"images/" + imageKey + ".png\" class=\"image-icon-50\" id=\"notif-" + imageKey + "-img\">";
  9060. if (itemKey != null)
  9061. {
  9062. notifBox.innerHTML += "<span data-item-display=\"" + itemKey + "\" style=\"margin-left: 10px;\"></span>";
  9063. }
  9064. var notifArea = document.getElementById('notifaction-area');
  9065. if (notifArea)
  9066. {
  9067. notifArea.appendChild(notifBox);
  9068. }
  9069. return notifBox;
  9070. }
  9071.  
  9072. function addWorker()
  9073. {
  9074. var notifBox = addNotifBox('workers', null, true);
  9075.  
  9076. function setVisibility()
  9077. {
  9078. var show = win.workersTimer === 1 && settings.get(settings.KEY.useWorkerNotif);
  9079. notifBox.style.display = show ? '' : 'none';
  9080. }
  9081. setVisibility();
  9082. observer.addTick(function ()
  9083. {
  9084. return setVisibility();
  9085. });
  9086. }
  9087. function addFaradoxCrystal()
  9088. {
  9089. var notifBox = addNotifBox('faradoxsLair/tombIcon', null, true);
  9090.  
  9091. function setVisibility()
  9092. {
  9093. var show = (win.tombCd == 0 && quest16 == -1) && settings.get(settings.KEY.useTombNotif);
  9094. notifBox.style.display = show ? '' : 'none';
  9095. }
  9096. setVisibility();
  9097. observer.addTick(function ()
  9098. {
  9099. return setVisibility();
  9100. });
  9101. }
  9102. function addBobsUncle()
  9103. {
  9104. var notifBox = addNotifBox('bobsUncle', null, true);
  9105.  
  9106. function setVisibility()
  9107. {
  9108. var show = win.farmingPatchStage7 == 4 && settings.get(settings.KEY.useBobsUncleNotif);
  9109. notifBox.style.display = show ? '' : 'none';
  9110. }
  9111. setVisibility();
  9112. observer.addTick(function ()
  9113. {
  9114. return setVisibility();
  9115. });
  9116. }
  9117. function addRedCombatLootOrb()
  9118. {
  9119. var notifBox = addNotifBox('redCombatLootOrb', null, true);
  9120.  
  9121. function setVisibility()
  9122. {
  9123. var show = (win.redCombatLootOrbTimer === 0 && win.boundRedCombatLootOrb === 1);
  9124. notifBox.style.display = show ? '' : 'none';
  9125. }
  9126. setVisibility();
  9127. observer.addTick(function ()
  9128. {
  9129. return setVisibility();
  9130. });
  9131. }
  9132. function addRedMap()
  9133. {
  9134. var notifBox = addNotifBox('redTreasureMap', null, true);
  9135.  
  9136. function setVisibility()
  9137. {
  9138. var show = win.redTreasureMap !== 0;
  9139. notifBox.style.display = show ? '' : 'none';
  9140. }
  9141. setVisibility();
  9142. observer.addTick(function ()
  9143. {
  9144. return setVisibility();
  9145. });
  9146. }
  9147.  
  9148. function init()
  9149. {
  9150. 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(239, 255, 0));\n}\n\t\t");
  9151. // fix mixing stand timer color
  9152. addStyle("\nspan.notif-box#notification-static-mixingStand\n{\n\tbackground: linear-gradient(#801A00, #C15033);\n}\n\t\t");
  9153. // remove pure text nodes
  9154. var notifArea = document.getElementById('notifaction-area');
  9155. if (notifArea)
  9156. {
  9157. removeWhitespaceChildNodes(notifArea);
  9158. }
  9159. addWorker();
  9160. addBobsUncle();
  9161. //addFaradoxCrystal();
  9162. addRedCombatLootOrb();
  9163. addRedMap();
  9164. }
  9165. notifBoxes.init = init;
  9166. })(notifBoxes || (notifBoxes = {}));
  9167.  
  9168.  
  9169. /**
  9170. * extend market
  9171. */
  9172. var market;
  9173. (function (market)
  9174. {
  9175. market.name = 'market';
  9176. // max limit age: 5min
  9177. var MAX_LIMIT_AGE = 5 * 60 * 1e3;
  9178. var PRICE_HISTORY_KEY = 'priceHistory';
  9179. // 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)
  9180. var MAX_ENTRIES_PER_ITEM = 2e3;
  9181. var SYNC_URL_REGEX = /^(?:https?:\/\/)?(?:(?:www\.)?myjson\.com\/|api\.myjson\.com\/bins\/)([^\/]+)$/i;
  9182. var detectedTedsUIOnce = false;
  9183.  
  9184. function detectTedsUI()
  9185. {
  9186. return detectedTedsUIOnce = detectedTedsUIOnce || typeof win.changeSetting === 'function';
  9187. }
  9188. market.detectTedsUI = detectTedsUI;
  9189. var priceHistory = store.has(PRICE_HISTORY_KEY) ? store.get(PRICE_HISTORY_KEY) :
  9190. {};
  9191. var getItemColor = function (H, S, L)
  9192. {
  9193. return [
  9194. "hsl(" + H + ", " + S + "%, " + L + "%)"
  9195. , "hsl(" + H + ", " + S + "%, " + (L < 35 ? L + 35 : L - 35) + "%)"
  9196. ];
  9197. };
  9198. var itemColor = {
  9199. 'blewitMushroom': getItemColor(255, 100, 78)
  9200. , 'bronzeBar': getItemColor(39, 100, 46)
  9201. , 'crystalLeaf': getItemColor(226, 100, 50)
  9202. , 'diamond': getItemColor(186, 76, 82)
  9203. , 'dottedGreenLeaf': getItemColor(92, 63, 19)
  9204. , 'emerald': getItemColor(110, 100, 48)
  9205. , 'goldLeaf': getItemColor(50, 100, 50)
  9206. , 'goldBar': getItemColor(54, 100, 46)
  9207. , 'greenLeaf': getItemColor(92, 63, 28)
  9208. , 'ironBar': getItemColor(44, 11, 46)
  9209. , 'limeLeaf': getItemColor(110, 72, 40)
  9210. , 'promethiumBar': getItemColor(354, 81, 46)
  9211. , 'redMushroom': getItemColor(0, 83, 48)
  9212. , 'ruby': getItemColor(5, 87, 45)
  9213. , 'sapphire': getItemColor(197, 100, 32)
  9214. , 'shrimp': getItemColor(17, 88, 50)
  9215. , 'silverBar': getItemColor(0, 0, 74)
  9216. , 'snapegrass': getItemColor(120, 99, 42)
  9217. , 'stardust': getItemColor(37, 100, 50)
  9218. //, 'strangeLeaf': getItemColor(195, 100, 40)
  9219. };
  9220. // use ambassadors to name the categories
  9221. var categoryAmbassador2CategoryName = {
  9222. 'stone': 'Ores' // 0
  9223. , 'emptyChisel': 'Crystals' // 1
  9224. , 'bronzeBar': 'Bars' // 2
  9225. , 'dottedGreenLeafSeeds': 'Seeds' // 3
  9226. , 'logs': 'Logs' // 4
  9227. , 'dottedGreenLeaf': 'Ingredients' // 5
  9228. , 'rawShrimp': 'Fish' // 6
  9229. , 'shrimp': 'Food' // 7
  9230. , 'stinger': 'Equipment' // 8
  9231. , 'promethiumHelmetMould': 'Mould' // 9
  9232. //, 'essence': 'Magic' // 10
  9233. , 'blueFishingRodOrb': 'Orbs' // 10
  9234. , 'stardust': 'Other' // 11
  9235. };
  9236. var item2Category = new Map();
  9237. var category2Name = new Map();
  9238. var item2Resolver = new Map();
  9239. var itemLimits = new Map();
  9240. var offerPerItem = new Map();
  9241. var offerList = new Array();
  9242. var lastSyncValue = '{}';
  9243.  
  9244. function getSyncUrl()
  9245. {
  9246. if (!settings.get(settings.KEY.syncPriceHistory))
  9247. {
  9248. return null;
  9249. }
  9250. var url = settings.getSub(settings.KEY.syncPriceHistory, 'url');
  9251. var match = url.match(SYNC_URL_REGEX);
  9252. if (!match)
  9253. {
  9254. console.error('URL "' + url + '" does not match the expected pattern: ' + SYNC_URL_REGEX.source);
  9255. return null;
  9256. }
  9257. return 'https://api.myjson.com/bins/' + match[1];
  9258. }
  9259.  
  9260. function integratePriceData(data, responseText)
  9261. {
  9262. var changed = recIntegrate(data, priceHistory);
  9263. lastSyncValue = responseText;
  9264. return changed;
  9265.  
  9266. function recIntegrate(source, target)
  9267. {
  9268. var changed = false;
  9269. if (typeof source !== typeof target)
  9270. {
  9271. console.error('Different data types. Could not integrate data into local price history.\nsource: ' + JSON.stringify(source) + '\ntarget: ' + JSON.stringify(target));
  9272. }
  9273. else if (typeof source === 'object')
  9274. {
  9275. for (var key in source)
  9276. {
  9277. if (source.hasOwnProperty(key))
  9278. {
  9279. if (!target.hasOwnProperty(key))
  9280. {
  9281. target[key] = source[key];
  9282. changed = true;
  9283. }
  9284. else if (recIntegrate(source[key], target[key]))
  9285. {
  9286. changed = true;
  9287. }
  9288. }
  9289. }
  9290. }
  9291. else
  9292. {
  9293. // do nothing and prefer the local value
  9294. }
  9295. return changed;
  9296. }
  9297. }
  9298.  
  9299. function loadPriceHistory()
  9300. {
  9301. var url = getSyncUrl();
  9302. if (url)
  9303. {
  9304. win.$.get(url, function (data, textStatus, jqXHR)
  9305. {
  9306. if (integratePriceData(data, jqXHR.responseText))
  9307. {
  9308. savePriceHistory(true);
  9309. }
  9310. });
  9311. }
  9312. }
  9313.  
  9314. function savePriceHistory(forceWrite)
  9315. {
  9316. if (forceWrite === void 0)
  9317. {
  9318. forceWrite = false;
  9319. }
  9320. for (var itemKey in priceHistory)
  9321. {
  9322. var history_1 = priceHistory[itemKey];
  9323. var timestampList = Object.keys(history_1).sort();
  9324. var i = 0;
  9325. for (var _i = 0, timestampList_1 = timestampList; _i < timestampList_1.length; _i++)
  9326. {
  9327. var timestamp = timestampList_1[_i];
  9328. i++;
  9329. if (i > MAX_ENTRIES_PER_ITEM)
  9330. {
  9331. delete history_1[timestamp];
  9332. }
  9333. }
  9334. }
  9335. store.set(PRICE_HISTORY_KEY, priceHistory);
  9336. var url = getSyncUrl();
  9337. if (url)
  9338. {
  9339. var doPut_1 = function ()
  9340. {
  9341. $.ajax(
  9342. {
  9343. url: url
  9344. , type: 'PUT'
  9345. , data: JSON.stringify(priceHistory)
  9346. , contentType: 'application/json; charset=utf-8'
  9347. , dataType: 'json'
  9348. , success: function (data, textStatus, jqXHR)
  9349. {
  9350. lastSyncValue = jqXHR.responseText;
  9351. }
  9352. });
  9353. };
  9354. if (forceWrite === true)
  9355. {
  9356. doPut_1();
  9357. }
  9358. else
  9359. {
  9360. win.$.get(url, function (data, textStatus, jqXHR)
  9361. {
  9362. if (lastSyncValue !== jqXHR.responseText)
  9363. {
  9364. integratePriceData(data, jqXHR.responseText);
  9365. }
  9366. doPut_1();
  9367. });
  9368. }
  9369. }
  9370. }
  9371.  
  9372. function processMarketData(data)
  9373. {
  9374. var nowKey = now();
  9375. offerPerItem = new Map();
  9376. offerList = new Array();
  9377. if (data != 'NONE')
  9378. {
  9379. offerList = data.split(';').map(function (offerData)
  9380. {
  9381. var values = offerData.split('~');
  9382. var itemId = Number(values[1]);
  9383. var itemKey = win.jsItemArray[itemId];
  9384. var itemName = key2Name(itemKey);
  9385. var categoryId = item2Category.has(itemKey) ? item2Category.get(itemKey) : -1;
  9386. var offer = {
  9387. offerId: Number(values[0])
  9388. , itemId: itemId
  9389. , itemKey: itemKey
  9390. , itemName: itemName
  9391. , categoryId: categoryId
  9392. , amount: Number(values[2])
  9393. , price: Number(values[3])
  9394. , timeLeft: values[4]
  9395. , playerId: Number(values[5])
  9396. };
  9397. if (!offerPerItem.has(itemKey))
  9398. {
  9399. offerPerItem.set(itemKey, []);
  9400. }
  9401. offerPerItem.get(itemKey).push(offer);
  9402. var history = priceHistory[itemKey];
  9403. if (!history)
  9404. {
  9405. history = {};
  9406. priceHistory[itemKey] = history;
  9407. }
  9408. if (!history.hasOwnProperty(nowKey)
  9409. || history[nowKey] > offer.price)
  9410. {
  9411. history[nowKey] = offer.price;
  9412. }
  9413. return offer;
  9414. });
  9415. }
  9416. savePriceHistory();
  9417. }
  9418.  
  9419. function processItemLimits(itemKey, lowerLimit, upperLimit)
  9420. {
  9421. var limit = {
  9422. timestamp: now()
  9423. , min: lowerLimit
  9424. , max: upperLimit
  9425. };
  9426. itemLimits.set(itemKey, limit);
  9427. if (item2Resolver.has(itemKey))
  9428. {
  9429. var limitArr_1 = [lowerLimit, upperLimit];
  9430. item2Resolver.get(itemKey).forEach(function (resolve)
  9431. {
  9432. return resolve(limitArr_1);
  9433. });
  9434. item2Resolver.delete(itemKey);
  9435. return false;
  9436. }
  9437. return true;
  9438. }
  9439.  
  9440. function showOfferCancelCooldown()
  9441. {
  9442. if (detectTedsUI())
  9443. {
  9444. return;
  9445. }
  9446. 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");
  9447.  
  9448. function slotCooldown(i, init)
  9449. {
  9450. if (init === void 0)
  9451. {
  9452. init = false;
  9453. }
  9454. var cooldownKey = 'marketCancelCooldownSlot' + i;
  9455. var btn = document.getElementById('market-slot-' + i + '-cancel-btn');
  9456. if (btn)
  9457. {
  9458. btn.dataset.cooldown = detectTedsUI() ? '0' : getGameValue(cooldownKey).toString();
  9459. }
  9460. if (init)
  9461. {
  9462. observer.add(cooldownKey, function ()
  9463. {
  9464. return slotCooldown(i);
  9465. });
  9466. }
  9467. }
  9468. for (var i = 1; i <= 3; i++)
  9469. {
  9470. slotCooldown(i, true);
  9471. }
  9472. }
  9473.  
  9474. function addExtraBtns()
  9475. {
  9476. var browseBtn = document.querySelector('.market-browse-button');
  9477. if (!browseBtn)
  9478. {
  9479. return;
  9480. }
  9481. var HISTORY_CLASS = 'local-history';
  9482. var paddingLeft = 30 + 42;
  9483. var paddingRight = 30;
  9484. 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");
  9485. var historyBtn = document.createElement('span');
  9486. historyBtn.className = 'market-browse-button ' + HISTORY_CLASS;
  9487. browseBtn.appendChild(historyBtn);
  9488. var historyItemKey = null;
  9489. var _postItemDialogue = win.postItemDialogue;
  9490. win.postItemDialogue = function (offerTypeEl, itemName, inputEl)
  9491. {
  9492. historyItemKey = itemName;
  9493. _postItemDialogue(offerTypeEl, itemName, inputEl);
  9494. };
  9495. var PRICE_HISTORY_DIALOG_ID = 'dialog-price-history';
  9496. var PRICE_HISTORY_ID = 'price-history';
  9497. var PRICE_HISTORY_ITEM_SELECT_ID = 'price-history-item-select';
  9498. 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");
  9499. var dialog = document.createElement('dialog');
  9500. dialog.id = PRICE_HISTORY_DIALOG_ID;
  9501. dialog.style.display = 'none';
  9502. dialog.style.overflowX = 'hidden';
  9503. 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";
  9504. document.body.appendChild(dialog);
  9505. var itemSelect = document.getElementById(PRICE_HISTORY_ITEM_SELECT_ID);
  9506. var $itemSelect = win.$(itemSelect);
  9507.  
  9508. function loadScripts(urlList, callback)
  9509. {
  9510. var url = urlList[0];
  9511. if (!url)
  9512. {
  9513. callback && callback();
  9514. return;
  9515. }
  9516. var script = document.createElement('script');
  9517. script.src = url;
  9518. script.onload = function ()
  9519. {
  9520. return loadScripts(urlList.slice(1), callback);
  9521. };
  9522. document.head.appendChild(script);
  9523. }
  9524. var monthArray = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  9525. var lastHistoryItemKey;
  9526. var itemKey2SeriesId = {};
  9527. var chart;
  9528. var stage;
  9529. // add style for select2
  9530. var style = document.createElement('link');
  9531. style.rel = 'stylesheet';
  9532. style.href = 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css';
  9533. document.head.appendChild(style);
  9534. loadScripts([
  9535. 'https://cdn.anychart.com/js/7.14.3/anychart.min.js'
  9536. , 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js'
  9537. ], function ()
  9538. {
  9539. chart = win.anychart.area();
  9540. // pass the container id, chart will be displayed there
  9541. stage = anychart.graphics.create(PRICE_HISTORY_ID);
  9542. chart.container(stage);
  9543. var tooltip = chart.tooltip();
  9544. tooltip.displayMode('union');
  9545. tooltip.format(passThis(function (context)
  9546. {
  9547. var name = context.seriesName || 'Price';
  9548. return name + ': ' + (isNaN(context.value) ? '-' : format.number(context.value));
  9549. }));
  9550. tooltip.titleFormat(passThis(function (context)
  9551. {
  9552. var d = new Date(context.x);
  9553. return monthArray[d.getMonth()] + ' ' + d.getDate() + ' @ ' + zeroPadLeft(d.getHours()) + ':' + zeroPadLeft(d.getMinutes()) + ':' + zeroPadLeft(d.getSeconds());
  9554. }));
  9555. var valueAxis = chart.yAxis();
  9556. valueAxis.title().text('Price').enabled(true);
  9557. valueAxis.labels().format(passThis(function (context)
  9558. {
  9559. return format.number(context.value);
  9560. }));
  9561. var timeAxis = chart.xAxis();
  9562. timeAxis.labels().format(passThis(function (context)
  9563. {
  9564. var d = new Date(context.tickValue);
  9565. return d.getDate() + '. ' + monthArray[d.getMonth()];
  9566. }));
  9567. var timeScale = win.anychart.scales.dateTime();
  9568. var ticks = timeScale.ticks();
  9569. ticks.interval(0, 0, 1);
  9570. chart.xScale(timeScale);
  9571. var timeScroller = chart.xScroller();
  9572. timeScroller.enabled(true);
  9573. chart.animation(true, 300);
  9574. chart.legend(true);
  9575. });
  9576. historyBtn.addEventListener('click', function (event)
  9577. {
  9578. event.preventDefault();
  9579. event.stopPropagation();
  9580. var height = Math.floor(.66 * window.innerHeight);
  9581. var width = Math.min(Math.floor(.66 * window.innerWidth), window.innerWidth - 30);
  9582. win.$(dialog).dialog(
  9583. {
  9584. title: 'Price history from local data'
  9585. , height: height
  9586. , width: width
  9587. });
  9588. dialog.style.height = (height) + 'px';
  9589. var itemKeyList = Object.keys(priceHistory).sort();
  9590. itemSelect.innerHTML = "";
  9591. var category2OptGroup = {};
  9592.  
  9593. function ensureOptGroup(categoryId)
  9594. {
  9595. var optGroup = category2OptGroup[categoryId];
  9596. if (!optGroup)
  9597. {
  9598. optGroup = document.createElement('optgroup');
  9599. optGroup.label = category2Name.get(categoryId) || 'Stuff';
  9600. itemSelect.appendChild(optGroup);
  9601. category2OptGroup[categoryId] = optGroup;
  9602. }
  9603. return optGroup;
  9604. }
  9605. var categoryList = Array.from(category2Name.keys()).map(function (id)
  9606. {
  9607. return Number(id);
  9608. }).sort();
  9609. for (var _i = 0, categoryList_1 = categoryList; _i < categoryList_1.length; _i++)
  9610. {
  9611. var categoryId = categoryList_1[_i];
  9612. ensureOptGroup(categoryId);
  9613. }
  9614. var itemKey2EnabledFn = {};
  9615.  
  9616. function replaceEnabled(itemKey, series)
  9617. {
  9618. var _enabled = series.enabled.bind(series);
  9619. itemKey2EnabledFn[itemKey] = _enabled;
  9620. series.enabled = function (value)
  9621. {
  9622. if (value !== undefined)
  9623. {
  9624. var itemList = $itemSelect.val();
  9625. var index = itemList.indexOf(itemKey);
  9626. if (index !== -1)
  9627. {
  9628. itemList.splice(index, 1);
  9629. }
  9630. else
  9631. {
  9632. itemList.push(itemKey);
  9633. }
  9634. $itemSelect.val(itemList).trigger('change');
  9635. }
  9636. return _enabled(value);
  9637. };
  9638. }
  9639. var min = Number.MAX_SAFE_INTEGER;
  9640. var max = 0;
  9641. var enabledSeriesList = [];
  9642. var _loop_1 = function (itemKey)
  9643. {
  9644. if (!itemColor[itemKey])
  9645. {
  9646. var baseColor = colorGenerator.getRandom(
  9647. {
  9648. format: 'hslArray'
  9649. });
  9650. var borderColor = baseColor.slice(0);
  9651. if (borderColor[2] < 35)
  9652. {
  9653. borderColor[2] += 35;
  9654. }
  9655. else
  9656. {
  9657. borderColor[2] -= 35;
  9658. }
  9659. itemColor[itemKey] = [
  9660. "hsl(" + baseColor[0] + ", " + baseColor[1] + "%, " + baseColor[2] + "%)"
  9661. , "hsl(" + borderColor[0] + ", " + borderColor[1] + "%, " + borderColor[2] + "%)"
  9662. ];
  9663. }
  9664. var history_2 = priceHistory[itemKey];
  9665. var keyList = Object.keys(history_2).sort();
  9666. var data = keyList
  9667. .map(function (n)
  9668. {
  9669. return ([
  9670. Number(n)
  9671. , history_2[n]
  9672. ]);
  9673. });
  9674. min = Math.min(Number(keyList[0]), min);
  9675. max = Math.max(Number(keyList[keyList.length - 1]), max);
  9676. var id = itemKey2SeriesId[itemKey];
  9677. var series = void 0;
  9678. if (id != null)
  9679. {
  9680. series = chart.getSeries(id);
  9681. series.data(data);
  9682. }
  9683. else
  9684. {
  9685. var hoverifyColor = function (hslColor)
  9686. {
  9687. return (
  9688. {
  9689. color: hslColor
  9690. , opacity: .8
  9691. });
  9692. };
  9693. series = chart.area(data);
  9694. itemKey2SeriesId[itemKey] = series.id();
  9695. series.name(key2Name(itemKey));
  9696. var bgColor = itemColor[itemKey][0];
  9697. var strokeColor = itemColor[itemKey][1];
  9698. series.fill(bgColor);
  9699. var bgColorHover = hoverifyColor(bgColor);
  9700. series.selectFill(bgColorHover);
  9701. series.hoverFill(bgColorHover);
  9702. series.stroke(strokeColor, 2);
  9703. var strokeColorHover = hoverifyColor(strokeColor);
  9704. series.hoverStroke(strokeColorHover, 2);
  9705. series.selectStroke(strokeColorHover, 2);
  9706. var markerOptions = {
  9707. fill: strokeColor
  9708. , size: 5
  9709. , type: 'circle'
  9710. };
  9711. series.hoverMarkers(markerOptions);
  9712. series.selectMarkers(markerOptions);
  9713. replaceEnabled(itemKey, series);
  9714. }
  9715. if (lastHistoryItemKey !== historyItemKey)
  9716. {
  9717. if (itemKey === historyItemKey)
  9718. {
  9719. enabledSeriesList.push(series);
  9720. }
  9721. series.enabled(false);
  9722. }
  9723. var categoryId = item2Category.has(itemKey) ? item2Category.get(itemKey) : -1;
  9724. var optGroup = ensureOptGroup(categoryId);
  9725. var option = document.createElement('option');
  9726. option.value = itemKey;
  9727. option.textContent = key2Name(itemKey);
  9728. optGroup.appendChild(option);
  9729. };
  9730. for (var _a = 0, itemKeyList_1 = itemKeyList; _a < itemKeyList_1.length; _a++)
  9731. {
  9732. var itemKey = itemKeyList_1[_a];
  9733. _loop_1(itemKey);
  9734. }
  9735. stage.listenOnce('renderfinish', function ()
  9736. {
  9737. enabledSeriesList.forEach(function (series)
  9738. {
  9739. return series.enabled(true);
  9740. });
  9741. });
  9742. var timeScale = chart.xScale();
  9743. timeScale.minimum(min);
  9744. timeScale.maximum(max);
  9745. var timeZoom = chart.xZoom();
  9746. var threeDaysLong = 3 * 24 * 60 * 60 * 1e3;
  9747. timeZoom.setToValues(Math.max(max - threeDaysLong, min), max);
  9748. // call the chart draw() method to initiate chart display
  9749. chart.draw(true);
  9750. // init item select
  9751. if ($itemSelect.data('select2'))
  9752. {
  9753. $itemSelect.select2('destroy');
  9754. }
  9755. $itemSelect.select2();
  9756.  
  9757. function getEnabledFn(event)
  9758. {
  9759. var data = event.params.data;
  9760. var itemKey = data.id;
  9761. var enabledFn = itemKey2EnabledFn[itemKey];
  9762. if (enabledFn)
  9763. {
  9764. return enabledFn;
  9765. }
  9766. else
  9767. {
  9768. var id = itemKey2SeriesId[itemKey];
  9769. var series = chart.getSeries(id);
  9770. return series.enabled.bind(series);
  9771. }
  9772. }
  9773. $itemSelect.on('select2:select', function (event)
  9774. {
  9775. getEnabledFn(event)(true);
  9776. });
  9777. $itemSelect.on('select2:unselect', function (event)
  9778. {
  9779. getEnabledFn(event)(false);
  9780. // close select menu when it was closed before an element has been removed
  9781. var openBefore = $itemSelect.data('select2').$container.hasClass('select2-container--open');
  9782. setTimeout(function ()
  9783. {
  9784. if (!openBefore && $itemSelect.data('select2').$container.hasClass('select2-container--open'))
  9785. {
  9786. $itemSelect.select2('close');
  9787. }
  9788. });
  9789. });
  9790. lastHistoryItemKey = historyItemKey;
  9791. });
  9792. }
  9793. var categoryList = [-1];
  9794. var itemListPerCategory = new Map();
  9795.  
  9796. function improveOfferList()
  9797. {
  9798. var itemArea = document.getElementById('dialogue-market-items-area');
  9799. if (itemArea)
  9800. {
  9801. var children = itemArea.children;
  9802. for (var i = 1; i < children.length; i++)
  9803. {
  9804. var categoryId = i - 1;
  9805. categoryList.push(categoryId);
  9806. var box = children.item(i);
  9807. var inputs = box.children;
  9808. for (var j = 0; j < inputs.length; j++)
  9809. {
  9810. var match = inputs.item(j).src.match(/images\/([^\/]+)\.(?:png|jpe?g|gif)/);
  9811. if (!match)
  9812. {
  9813. continue;
  9814. }
  9815. var itemKey = match[1];
  9816. item2Category.set(itemKey, categoryId);
  9817. if (categoryAmbassador2CategoryName[itemKey])
  9818. {
  9819. category2Name.set(categoryId, categoryAmbassador2CategoryName[itemKey]);
  9820. }
  9821. if (!itemListPerCategory.has(categoryId))
  9822. {
  9823. itemListPerCategory.set(categoryId, []);
  9824. }
  9825. itemListPerCategory.get(categoryId).push(itemKey);
  9826. }
  9827. }
  9828. }
  9829. }
  9830.  
  9831. function getItemLimit(itemKey)
  9832. {
  9833. // TODO: combine list of offers with min/max-boundries
  9834. var limit = itemLimits.get(itemKey);
  9835. if (limit && limit.timestamp > now() - MAX_LIMIT_AGE)
  9836. {
  9837. return Promise.resolve([limit.min, limit.max]);
  9838. }
  9839. else if (!win.jsTradalbeItems.hasOwnProperty(itemKey))
  9840. {
  9841. return Promise.resolve([0, 0]);
  9842. }
  9843. return new Promise(function (resolve, reject)
  9844. {
  9845. win.postItemDialogue(
  9846. {
  9847. value: 'sell'
  9848. }, itemKey, null);
  9849. if (!item2Resolver.has(itemKey))
  9850. {
  9851. item2Resolver.set(itemKey, []);
  9852. }
  9853. item2Resolver.get(itemKey).push(resolve);
  9854. setTimeout(function ()
  9855. {
  9856. return reject(new Error('Request timed out'));
  9857. }, 30e3);
  9858. });
  9859. }
  9860.  
  9861. function calcMarketValue(items)
  9862. {
  9863. var itemKeyList = Object.keys(items);
  9864. return Promise.all(itemKeyList.map(function (key)
  9865. {
  9866. return getItemLimit(key);
  9867. }))
  9868. .then(function (limitList)
  9869. {
  9870. var sum = [0, 0];
  9871. for (var i = 0; i < itemKeyList.length; i++)
  9872. {
  9873. var amount = items[itemKeyList[i]];
  9874. var limit = limitList[i];
  9875. sum[0] += amount * limit[0];
  9876. sum[1] += amount * limit[1];
  9877. }
  9878. return sum;
  9879. });
  9880. }
  9881. market.calcMarketValue = calcMarketValue;
  9882.  
  9883. function init()
  9884. {
  9885.  
  9886. showOfferCancelCooldown();
  9887. addExtraBtns();
  9888. improveOfferList();
  9889. var _chosenPostItemDialogue = win.chosenPostItemDialogue;
  9890. win.chosenPostItemDialogue = function (itemName, lowerLimit, upperLimit)
  9891. {
  9892. if (processItemLimits(itemName, Number(lowerLimit), Number(upperLimit)))
  9893. {
  9894. _chosenPostItemDialogue(itemName, lowerLimit, upperLimit);
  9895. }
  9896. };
  9897. var _addToPlayerMarket = win.addToPlayerMarket;
  9898. win.addToPlayerMarket = function (data)
  9899. {
  9900. processMarketData(data);
  9901. _addToPlayerMarket(data);
  9902. };
  9903. loadPriceHistory();
  9904. // delay (debounce) sending the request for 3s
  9905. var startDebouncedRequest = debounce(function ()
  9906. {
  9907. return loadPriceHistory();
  9908. }, 3e3);
  9909. settings.observe(settings.KEY.syncPriceHistory, function ()
  9910. {
  9911. return startDebouncedRequest();
  9912. });
  9913. settings.observeSub(settings.KEY.syncPriceHistory, 'url', function ()
  9914. {
  9915. return startDebouncedRequest();
  9916. });
  9917. }
  9918. market.init = init;
  9919. })(market || (market = {}));
  9920.  
  9921. var combat;
  9922. (function (combat)
  9923. {
  9924. combat.name = 'combat';
  9925. var LOOT_TABLE_URL = '/wiki/combat.php';
  9926. var COMBAT_LOOT_TABLES_ID = 'combat-loot-tables';
  9927. var CAT_2_NAME = {
  9928. 'always': 'Always'
  9929. , 'common': 'Common'
  9930. , 'uncommon': 'Uncommon'
  9931. , 'rare': 'Rare'
  9932. , 'veryrare': 'Very Rare'
  9933. };
  9934. var lootInfoInitialized = false;
  9935. var lootInfo = {};
  9936.  
  9937. function readLootTable(table)
  9938. {
  9939. var monsterImg = table.getElementsByTagName('img').item(0);
  9940. var src = monsterImg.getAttribute('src') || '';
  9941. var monsterId = src.replace(/.+npc\/(\d+)\.png$/, '$1');
  9942. var info = {
  9943. always: []
  9944. , common: []
  9945. , uncommon: []
  9946. , rare: []
  9947. , veryrare: []
  9948. };
  9949. for (var i = 2; i < table.rows.length; i++)
  9950. {
  9951. var row = table.rows.item(i);
  9952. var match = row.cells.item(0).innerHTML.match(/images\/(.+)\.png/) || row.cells.item(0).innerHTML.match(/images\/(.+)\.gif/);
  9953. if (!match)
  9954. {
  9955. console.error('no item key found:', row.innerHTML);
  9956. continue;
  9957. }
  9958. var itemKey = match[1];
  9959. var amount = row.cells.item(1).textContent || '';
  9960. var rarityCategory = row.cells.item(2).className;
  9961. var dropRate = (rarityCategory == 'Always') ? 'Always' : row.cells.item(2).textContent;
  9962. if (!info.hasOwnProperty(rarityCategory))
  9963. {
  9964. console.error('unknown rarity category:', rarityCategory);
  9965. continue;
  9966. }
  9967. info[rarityCategory].push(
  9968. {
  9969. key: itemKey
  9970. , amount: amount.split(' - ').map(function (s)
  9971. {
  9972. return Number(s.replace(/\D/g, ''));
  9973. })
  9974. , dropRate: dropRate
  9975. });
  9976. }
  9977. lootInfo[monsterId] = info;
  9978. lootInfoInitialized = true;
  9979. }
  9980.  
  9981. function updateLootTableInfo()
  9982. {
  9983. return doGet(LOOT_TABLE_URL)
  9984. .then(function (response)
  9985. {
  9986. var parser = new DOMParser();
  9987. var doc = parser.parseFromString(response, 'text/html');
  9988. var tables = doc.getElementsByTagName('table');
  9989. for (var i = 0; i < tables.length; i++)
  9990. {
  9991. readLootTable(tables.item(i));
  9992. }
  9993. return lootInfo;
  9994. })
  9995. .then(function (info)
  9996. {
  9997. setLootTableTabContent(info);
  9998. });
  9999. }
  10000.  
  10001. function addLootTableTab()
  10002. {
  10003. var subTabContainer = document.getElementById('tab-sub-container-combat');
  10004. var itemContainer = document.getElementById('tab-sub-container-combat-large-btns');
  10005. var afterEl = itemContainer && itemContainer.previousElementSibling;
  10006. if (!subTabContainer || !afterEl)
  10007. {
  10008. return;
  10009. }
  10010. 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");
  10011. var REFRESH_LOOT_TABLE_ID = 'refresh-loot-table';
  10012. var subTab = document.createElement('span');
  10013. subTab.className = 'large-button';
  10014. subTab.innerHTML = "<img class=\"image-icon-50\" src=\"images/combatDropTable.png\" style=\"filter: grayscale(100%);\">Loot";
  10015. subTab.addEventListener('click', function ()
  10016. {
  10017. var _confirmDialogue = win.confirmDialogue;
  10018. win.confirmDialogue = function () {};
  10019. win.clicksOpenDropTable();
  10020. win.confirmDialogue = _confirmDialogue;
  10021. win.openSubTab('loot');
  10022. });
  10023.  
  10024. function setLootTabVisibility()
  10025. {
  10026. var show = settings.get(settings.KEY.showLootTab);
  10027. subTab.style.display = show ? '' : 'none';
  10028. var dropTableItemBox = document.getElementById('item-box-combatDropTable');
  10029. if (dropTableItemBox)
  10030. {
  10031. dropTableItemBox.style.display = show ? 'none' : '';
  10032. }
  10033. if (show && !lootInfoInitialized)
  10034. {
  10035. updateLootTableInfo();
  10036. }
  10037. }
  10038. setLootTabVisibility();
  10039. settings.observe(settings.KEY.showLootTab, function ()
  10040. {
  10041. return setLootTabVisibility();
  10042. });
  10043. subTabContainer.insertBefore(subTab, afterEl);
  10044. var combatSubTab = document.getElementById('tab-sub-container-combat');
  10045. var equipSubTab = document.getElementById('tab-sub-container-equip');
  10046. var spellsSubTab = document.getElementById('tab-sub-container-spells');
  10047. var subPanelContainer = combatSubTab.parentElement;
  10048. var lootSubTab = document.createElement('div');
  10049. lootSubTab.id = 'tab-sub-container-loot';
  10050. lootSubTab.style.display = 'none';
  10051. 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>";
  10052. subPanelContainer.appendChild(lootSubTab);
  10053. var refreshBtn = document.getElementById(REFRESH_LOOT_TABLE_ID);
  10054. if (refreshBtn)
  10055. {
  10056. refreshBtn.addEventListener('click', function ()
  10057. {
  10058. if (refreshBtn.classList.contains('active'))
  10059. {
  10060. return;
  10061. }
  10062. refreshBtn.classList.add('active');
  10063. updateLootTableInfo()
  10064. .then(function ()
  10065. {
  10066. return refreshBtn.classList.remove('active');
  10067. })
  10068. .catch(function ()
  10069. {
  10070. return refreshBtn.classList.remove('active');
  10071. });
  10072. });
  10073. }
  10074. var _openSubTab = win.openSubTab;
  10075. win.openSubTab = function (tab)
  10076. {
  10077. combatSubTab.style.display = 'none';
  10078. equipSubTab.style.display = 'none';
  10079. spellsSubTab.style.display = 'none';
  10080. lootSubTab.style.display = 'none';
  10081. _openSubTab(tab);
  10082. if (tab == 'loot')
  10083. {
  10084. lootSubTab.style.display = 'block';
  10085. }
  10086. };
  10087. var _loadDefaultCombatTab = win.loadDefaultCombatTab;
  10088. win.loadDefaultCombatTab = function ()
  10089. {
  10090. _loadDefaultCombatTab();
  10091. lootSubTab.style.display = 'none';
  10092. };
  10093. }
  10094.  
  10095. function setLootTableTabContent(lootInfo)
  10096. {
  10097. var combatTableWrapper = document.getElementById(COMBAT_LOOT_TABLES_ID);
  10098. if (!combatTableWrapper)
  10099. {
  10100. return;
  10101. }
  10102. combatTableWrapper.innerHTML = "";
  10103. for (var monsterId in lootInfo)
  10104. {
  10105. var info = lootInfo[monsterId];
  10106. var monsterNum = Number(monsterId);
  10107. if (monsterNum > 1 && monsterNum % 3 === 1)
  10108. {
  10109. var lineBreak = document.createElement('div');
  10110. lineBreak.style.clear = 'both';
  10111. lineBreak.innerHTML = "<br>";
  10112. combatTableWrapper.appendChild(lineBreak);
  10113. }
  10114. var table = document.createElement('table');
  10115. table.className = 'hiscores-table';
  10116. var imgRow = table.insertRow(-1);
  10117. 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>";
  10118. var headerRow = table.insertRow(-1);
  10119. headerRow.innerHTML = "<th>Item</th><th>Amount</th><th>Rarity</th>";
  10120. for (var rarityCategory in info)
  10121. {
  10122. var itemList = info[rarityCategory];
  10123. for (var i = 0; i < itemList.length; i++)
  10124. {
  10125. var item = itemList[i];
  10126. var row = table.insertRow(-1);
  10127. row.innerHTML = "<td><img src=\"../images/" + item.key + ".png\" class=\"image-icon-40\"></td><td>" + item.amount.map(function (n){
  10128. return format.number(n);
  10129. }).join(' - ') + "</td><td class=\"" + rarityCategory + "\">" + item.dropRate + "</td>";
  10130. }
  10131. }
  10132. combatTableWrapper.appendChild(table);
  10133. }
  10134. var images = document.querySelectorAll('.hiscores-table .image-icon-40');
  10135. for (let i=0; i < images.length; i++){
  10136. var enchantSG = images[i];
  10137. var fixURL = enchantSG.src = enchantSG.src.replace('/images/enchantedStargemPotion.png','/images/enchantedStargemPotion.gif');
  10138. }
  10139. }
  10140.  
  10141.  
  10142. function init()
  10143. {
  10144. addLootTableTab();
  10145. if (settings.get(settings.KEY.showLootTab))
  10146. {
  10147. updateLootTableInfo();
  10148. }
  10149. }
  10150. combat.init = init;
  10151. })(combat || (combat = {}));
  10152.  
  10153. /**
  10154. * farming improvements
  10155. */
  10156. var farming;
  10157. (function (farming)
  10158. {
  10159. farming.name = 'farming';
  10160. var SEED_INFO_REGEX = {
  10161. minLevel: />\s*Level:/
  10162. , stopsDyingLevel: />\s*Stops\s+Dying\s+Level:/
  10163. , bonemeal: />\s*Bonemeal:/
  10164. , woodcuttingLevel: />\s*Woodcutting\s+Level:/
  10165. };
  10166. var seedInfoSpans = {};
  10167. var seedInfo = {};
  10168. var checkInfo = {
  10169. bonemeal: function (amount)
  10170. {
  10171. return amount <= win.bonemeal;
  10172. }
  10173. , minLevel: function (level)
  10174. {
  10175. return level <= win.getLevel(win.farmingXp);
  10176. }
  10177. , stopsDyingLevel: function (level)
  10178. {
  10179. return level <= win.getLevel(win.farmingXp);
  10180. }
  10181. , woodcuttingLevel: function (level)
  10182. {
  10183. return level <= win.getLevel(win.woodcuttingXp);
  10184. }
  10185. };
  10186. var RED = 'rgb(204, 0, 0)';
  10187.  
  10188. function addBetterStyle()
  10189. {
  10190. var CLASS_NAME = 'seedHighlight';
  10191. 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");
  10192. // seedHighlight
  10193. function updateHoverStyle()
  10194. {
  10195. document.body.classList[settings.get(settings.KEY.highlightUnplantableSeed) ? 'add' : 'remove'](CLASS_NAME);
  10196. }
  10197. updateHoverStyle();
  10198. settings.observe(settings.KEY.highlightUnplantableSeed, function ()
  10199. {
  10200. return updateHoverStyle();
  10201. });
  10202. }
  10203.  
  10204. function readSeedInfo(seedName, tooltipEl)
  10205. {
  10206. var spans = tooltipEl.querySelectorAll(':scope > span');
  10207. var infoSpans = {
  10208. bonemeal: null
  10209. , minLevel: null
  10210. , stopsDyingLevel: null
  10211. , woodcuttingLevel: null
  10212. };
  10213. var info = {
  10214. bonemeal: 0
  10215. , minLevel: 0
  10216. , stopsDyingLevel: 0
  10217. , woodcuttingLevel: 0
  10218. };
  10219. var i = 0;
  10220. for (var key in SEED_INFO_REGEX)
  10221. {
  10222. if (SEED_INFO_REGEX[key].test(spans[i].innerHTML))
  10223. {
  10224. infoSpans[key] = spans.item(i);
  10225. var textNode = spans.item(i).lastChild;
  10226. info[key] = parseInt(textNode.textContent || '', 10);
  10227. i++;
  10228. }
  10229. }
  10230. seedInfoSpans[seedName] = infoSpans;
  10231. seedInfo[seedName] = info;
  10232. }
  10233.  
  10234. function checkSpan(span, fulfilled)
  10235. {
  10236. span.style.color = fulfilled ? '' : RED;
  10237. span.style.fontWeight = fulfilled ? '' : 'bold';
  10238. }
  10239.  
  10240. function checkSeedInfo(seedName, init)
  10241. {
  10242. if (init === void 0)
  10243. {
  10244. init = false;
  10245. }
  10246. var highlight = settings.get(settings.KEY.highlightUnplantableSeed);
  10247. var info = seedInfo[seedName];
  10248. var spans = seedInfoSpans[seedName];
  10249. var canBePlanted = true;
  10250. for (var key in info)
  10251. {
  10252. var span = spans[key];
  10253. if (span)
  10254. {
  10255. var fulfilled = checkInfo[key](info[key]);
  10256. checkSpan(span, !highlight || fulfilled);
  10257. canBePlanted = !highlight || canBePlanted && (key == 'stopsDyingLevel' || fulfilled);
  10258. }
  10259. }
  10260. var itemBox = document.getElementById('item-box-' + seedName);
  10261. if (itemBox)
  10262. {
  10263. itemBox.style.opacity = (!highlight || canBePlanted) ? '' : '.5';
  10264. }
  10265. var plantInput = document.getElementById('dialogue-plant-' + seedName);
  10266. if (plantInput)
  10267. {
  10268. plantInput.style.backgroundColor = (!highlight || canBePlanted) ? '' : 'hsla(0, 100%, 50%, .5)';
  10269. }
  10270. if (init)
  10271. {
  10272. observer.add('bonemeal', function ()
  10273. {
  10274. return checkSeedInfo(seedName);
  10275. });
  10276. observer.add('farmingXp', function ()
  10277. {
  10278. return checkSeedInfo(seedName);
  10279. });
  10280. observer.add('woodcuttingXp', function ()
  10281. {
  10282. return checkSeedInfo(seedName);
  10283. });
  10284. settings.observe(settings.KEY.highlightUnplantableSeed, function ()
  10285. {
  10286. return checkSeedInfo(seedName);
  10287. });
  10288. }
  10289. }
  10290.  
  10291. function getSeedInfo(seedName)
  10292. {
  10293. return seedInfo[seedName];
  10294. }
  10295. farming.getSeedInfo = getSeedInfo;
  10296.  
  10297. function init()
  10298. {
  10299. addBetterStyle();
  10300. // read all seed information
  10301. var tooltipEls = document.querySelectorAll('div[id^="tooltip-"][id$="Seeds"]');
  10302. for (var i = 0; i < tooltipEls.length; i++)
  10303. {
  10304. var tooltipEl = tooltipEls[i];
  10305. var seedName = tooltipEl.id.replace(/^tooltip-/, '');
  10306. readSeedInfo(seedName, tooltipEl);
  10307. checkSeedInfo(seedName, true);
  10308. }
  10309. }
  10310. farming.init = init;
  10311. })(farming || (farming = {}));
  10312.  
  10313. /**
  10314. * add in-game calculators
  10315. */
  10316. var calc;
  10317. (function (calc)
  10318. {
  10319. var mining = {};
  10320. var crafting = {};
  10321. mining.XPConvert = 'xp-gain-pickaxe-convert';
  10322. mining.dialog = 'dialogue-id-boundPickaxe';
  10323. mining.name = 'mining';
  10324. crafting.XPConvert = 'xp-gain-hammer-convert';
  10325. crafting.dialog = 'dialogue-id-boundHammer';
  10326. crafting.name = 'crafting';
  10327.  
  10328. function doubleCalcs(skill){
  10329. var getXPConvert = document.getElementById(skill.XPConvert).innerHTML;
  10330. getXPConvert = getXPConvert.replace(/\,/g,'');
  10331. getXPConvert = parseInt(getXPConvert, 10);
  10332. var currentXP = getGameValue(skill.name + 'Xp');
  10333. var totalXP = currentXP + getXPConvert;
  10334. var level = getLevel(totalXP);
  10335.  
  10336. $('#'+skill.name+'-level').html(format.number(level));
  10337. $('#'+skill.name+'-xp').html(format.number(totalXP));
  10338. }
  10339. function doubleSkills(skill){
  10340. var getSkillDialog = document.getElementById(skill.dialog);
  10341. var div = document.createElement("div");
  10342. div.className = 'basic-smallbox';
  10343. div.innerHTML = '<b>Your next level will be: <x id="'+skill.name+'-level" style="color: blue"></x></b> (<x id="'+skill.name+'-xp"></x> xp)';
  10344.  
  10345. var smallboxes = getSkillDialog.querySelectorAll('div.basic-smallbox');
  10346. getSkillDialog.insertBefore(div, smallboxes[0]);
  10347. }
  10348.  
  10349.  
  10350. function magic(){
  10351.  
  10352. var getSkillDialog = document.getElementById("dialogue-id-meditate");
  10353. var div = document.createElement("div");
  10354. var div2 = document.createElement("div");
  10355. var title = document.createElement("h1");
  10356. title.className = 'container-title';
  10357. title.innerHTML = "Meditation Calculator";
  10358. var closeButton= '<br/><input type="button" value="Close"/>';
  10359.  
  10360. div2.className = 'basic-smallbox';
  10361. div.className = 'basic-smallbox';
  10362. div2.innerHTML = '<b>Target level: </b><input type="number" value="1" id="magic-level" size="4" min="1" max="100" style="width: 47px;">';
  10363. div.innerHTML = '<span> \
  10364. <input type="image" width="50px" id="stone" src="images/empoweredStone.png"> \
  10365. <input type="image" width="50px" id="moonstone" src="images/empoweredMoonstone.png"> \
  10366. <input type="image" width="50px" id="marsrock" src="images/empoweredMarsRock.png"> \
  10367. <input type="image" width="50px" id="promethium" src="images/empoweredPromethium.png"> \
  10368. <input type="image" width="50px" id="runite" src="images/empoweredRunite.png"> \
  10369. </span><br /><b>Empowered Rocks needed:</b> \
  10370. <input type="number" value="0" id="input-empowered-amount" size="4" min="0" max="9999" style="width: 67px;"> \
  10371. <br><img src="images/icons/wizardhat.png" class="image-icon-20"> +<span id="xp-gain-meditate-convert"></span> xp \
  10372. <br><span id="stone-display"><img src="images/stone.png" class="image-icon-20"> -<span id="stone-cost-meditate-convert"></span></span> \
  10373. <span id="moonstone-display" style="display: none"> \
  10374. <img src="images/moonstone.png" class="image-icon-20"> -<span id="moonstone-cost-meditate-convert"></span></span></span> \
  10375. <span id="marsrock-display" style="display: none"> \
  10376. <img src="images/marsRock.png" class="image-icon-20"> -<span id="marsrock-cost-meditate-convert"></span></span> \
  10377. <span id="promethium-display" style="display: none"> \
  10378. <img src="images/promethium.png" class="image-icon-20"> -<span id="promethium-cost-meditate-convert"></span></span> \
  10379. <span id="runite-display" style="display: none"><img src="images/runite.png" class="image-icon-20"> -<span id="runite-cost-meditate-convert"></span></span> \
  10380. <br><img src="images/icons/stardust.png" class="image-icon-20"> -<span id="stardust-cost-meditate-convert"></span> \
  10381. <br><img src="images/icons/hourglass.png" class="image-icon-20"> <span id="duration-meditate-convert"></span> hours \
  10382. ';
  10383. $(getSkillDialog).append(title, div2, div, closeButton);
  10384. }
  10385. function magicCalcXP(number, node){
  10386. if (!number){
  10387. return;
  10388. }
  10389. if (!node){
  10390. return;
  10391. }
  10392. var rock;
  10393. var inputLevel = $('#magic-level');
  10394. var inputRock = $('#input-empowered-amount');
  10395.  
  10396. var getRocks = inputRock.val();
  10397. var donorXPBoost = (win.donorXpBoost > win.currentTimeMillis) ? 1.1 : 1;
  10398. var greenRockOrb = (boundGreenEmpoweredRockOrb) ? 0.8 : 1;
  10399. var achvPerk = (achMagicMediumCompleted) ? 0.5 : 1;
  10400. var blueMeditateOrb = (boundBlueMeditationOrb) ? 0.5 : 1;
  10401.  
  10402. var materials = 1;
  10403. if (number === 1){
  10404. rock = 'stone';
  10405. materials = 1000000 * achvPerk;
  10406. }else if (number === 2){
  10407. rock = 'moonstone';
  10408. materials = 100 * achvPerk;
  10409. }else if (number === 3){
  10410. rock = 'marsrock';
  10411. materials = 10 * achvPerk;
  10412. }else if (number === 4){
  10413. rock = 'promethium';
  10414. materials = 30 * achvPerk;
  10415. }else if (number === 5){
  10416. rock = 'runite';
  10417. materials = 1;
  10418. }
  10419. //find meditate level and time
  10420. var meditateTime = 0;
  10421. for (var i = 1; i <= 9; i++){
  10422. if (getGameValue("meditate"+i) === 1){
  10423. meditateTime = 11 - i;
  10424. }
  10425. }
  10426.  
  10427. var gainXP = (getRocks > 9999) ? Number.NaN : getRocks*10000*donorXPBoost;
  10428. var sdCost = (getRocks > 9999) ? Number.NaN : getRocks*100000*greenRockOrb;
  10429. var matCost = (getRocks > 9999) ? Number.NaN : getRocks*materials;
  10430. var duration = (getRocks > 9999) ? Number.NaN : getRocks*meditateTime*blueMeditateOrb;
  10431. gainXP = parseInt(Math.round(gainXP), 10);
  10432. sdCost = parseInt(Math.round(sdCost), 10);
  10433. var totalXP = win.magicXp + gainXP;
  10434. var level = getLevel(totalXP);
  10435.  
  10436. $('#xp-gain-meditate-convert').html(format.number(gainXP));
  10437. $('#stardust-cost-meditate-convert').html(format.number(sdCost));
  10438. $('#'+node.id+'-cost-meditate-convert').html(format.number(matCost));
  10439. $('#duration-meditate-convert').html(format.number(duration));
  10440. inputLevel.val(level);
  10441.  
  10442. if (node.id == rock){
  10443. document.getElementById('stone').style.backgroundColor = '';
  10444. document.getElementById('moonstone').style.backgroundColor = '';
  10445. document.getElementById('marsrock').style.backgroundColor = '';
  10446. document.getElementById('promethium').style.backgroundColor = '';
  10447. document.getElementById('runite').style.backgroundColor = '';
  10448. node.style.backgroundColor = 'red';
  10449. document.getElementById('stone-display').style.display = "none";
  10450. document.getElementById('moonstone-display').style.display = "none";
  10451. document.getElementById('marsrock-display').style.display = "none";
  10452. document.getElementById('promethium-display').style.display = "none";
  10453. document.getElementById('runite-display').style.display = "none";
  10454. document.getElementById(node.id+'-display').style.display = "";
  10455. }
  10456. }
  10457.  
  10458. function magicCalcLevel(number, node){
  10459. if (!number){
  10460. return;
  10461. }
  10462. if (!node){
  10463. return;
  10464. }
  10465.  
  10466. var inputLevel = $('#magic-level');
  10467. var inputRock = $('#input-empowered-amount');
  10468.  
  10469. var desireLevel = inputLevel.val();
  10470. var donorXPBoost = (win.donorXpBoost > win.currentTimeMillis) ? 1.1 : 1;
  10471. var greenRockOrb = (boundGreenEmpoweredRockOrb) ? 0.8 : 1;
  10472. var achvPerk = (achMagicMediumCompleted) ? 0.5 : 1;
  10473. var blueMeditateOrb = (boundBlueMeditationOrb) ? 0.5 : 1;
  10474. var rock;
  10475. var materials = 1;
  10476. if (number === 1){
  10477. rock = 'stone';
  10478. materials = 1000000 * achvPerk;
  10479. }else if (number === 2){
  10480. rock = 'moonstone';
  10481. materials = 100 * achvPerk;
  10482. }else if (number === 3){
  10483. rock = 'marsrock';
  10484. materials = 10 * achvPerk;
  10485. }else if (number === 4){
  10486. rock = 'promethium';
  10487. materials = 30 * achvPerk;
  10488. }else if (number === 5){
  10489. rock = 'runite';
  10490. materials = 1;
  10491. }
  10492. //find meditate level and time
  10493. var meditateTime = 0;
  10494. for (var i = 1; i <= 9; i++){
  10495. if (getGameValue("meditate"+i) === 1){
  10496. meditateTime = 11 - i;
  10497. }
  10498. }
  10499.  
  10500. var desireXP = Math.round(Math.pow(desireLevel, 3 + desireLevel/200));
  10501. var actualXPneed = (desireLevel > 100) ? Number.NaN : (desireXP - win.magicXp);
  10502. var rockneed = Math.round(actualXPneed/(donorXPBoost * 10000));
  10503. var rockneed2 = (rockneed < 1) ? 1 : rockneed;
  10504. var sdneed = (desireLevel > 100) ? Number.NaN : rockneed2*100000*greenRockOrb;
  10505. var matneed = (desireLevel > 100) ? Number.NaN : rockneed2*materials;
  10506. var duration = (desireLevel > 100) ? Number.NaN : rockneed2*meditateTime*blueMeditateOrb;
  10507.  
  10508. inputRock.val(rockneed2);
  10509. $('#xp-gain-meditate-convert').html(format.number(actualXPneed));
  10510. $('#stardust-cost-meditate-convert').html(format.number(sdneed));
  10511. $('#'+node.id+'-cost-meditate-convert').html(format.number(matneed));
  10512. $('#duration-meditate-convert').html(format.number(duration));
  10513.  
  10514. if (node.id == rock){
  10515. document.getElementById('stone').style.backgroundColor = '';
  10516. document.getElementById('moonstone').style.backgroundColor = '';
  10517. document.getElementById('marsrock').style.backgroundColor = '';
  10518. document.getElementById('promethium').style.backgroundColor = '';
  10519. document.getElementById('runite').style.backgroundColor = '';
  10520. node.style.backgroundColor = 'red';
  10521. document.getElementById('stone-display').style.display = "none";
  10522. document.getElementById('moonstone-display').style.display = "none";
  10523. document.getElementById('marsrock-display').style.display = "none";
  10524. document.getElementById('promethium-display').style.display = "none";
  10525. document.getElementById('runite-display').style.display = "none";
  10526. document.getElementById(node.id+'-display').style.display = "";
  10527. }
  10528. }
  10529. function woodcuttingCalc(){
  10530. var treeXP = {0: 0, 1: 1000, 2: 2500, 3: 5000, 4: 10000, 5: 16000, 6: 20000, 7: 1000,
  10531. 8: 2500, 9: 5000, 10: 10000, 11: 16000, 12: 20000, 13: 40000, 14: 40000};
  10532. var getXP = 0;
  10533.  
  10534. for (var i = 1; i <= 6 ;i++){
  10535. getXP += treeXP[getGameValue('treeId'+ i)];
  10536. }
  10537. var donorXPBoost = (win.donorXpBoost > win.currentTimeMillis) ? 1.1 : 1;
  10538. getXP = getXP*donorXPBoost;
  10539. var bonusPerk = (achWoodcuttingMediumCompleted) ? 5 : 0;
  10540. var bonusGem;
  10541.  
  10542. if (boundEmptyAxe){
  10543. bonusGem = 0;
  10544. }else if (boundSapphireAxe){
  10545. bonusGem = 5;
  10546. }else if (boundEmeraldAxe){
  10547. bonusGem = 10;
  10548. }else if (boundRubyAxe){
  10549. bonusGem = 15;
  10550. }else if (boundDiamondAxe){
  10551. bonusGem = 20;
  10552. }
  10553. var bonusLevel = {};
  10554. bonusLevel = {max: 1, average: 1};
  10555. var WCLevel = win.getLevel(win.woodcuttingXp);
  10556. if (WCLevel < 20){
  10557. bonusLevel = {max: 1, average: 1};
  10558. }else if (WCLevel >= 20 && WCLevel < 30){
  10559. bonusLevel = {max: 2, average: 1};
  10560. }else if (WCLevel >= 30 && WCLevel < 40){
  10561. bonusLevel = {max: 3, average: 2};
  10562. }else if (WCLevel >= 40 && WCLevel < 50){
  10563. bonusLevel = {max: 4, average: 2};
  10564. }else if (WCLevel >= 50 && WCLevel < 60){
  10565. bonusLevel = {max: 5, average: 3};
  10566. }else if (WCLevel >= 60 && WCLevel < 70){
  10567. bonusLevel = {max: 6, average: 3};
  10568. }else if (WCLevel >= 70 && WCLevel < 80){
  10569. bonusLevel = {max: 7, average: 4};
  10570. }else if (WCLevel >= 80 && WCLevel < 90){
  10571. bonusLevel = {max: 8, average: 4};
  10572. }else if (WCLevel >= 90 && WCLevel < 100){
  10573. bonusLevel = {max: 9, average: 5};
  10574. }else if (WCLevel == 100){
  10575. bonusLevel = {max: 10, average: 5};
  10576. }
  10577. var totalMin = 15+bonusPerk+bonusGem+1;
  10578. var totalMax = 30+bonusPerk+bonusGem+bonusLevel.max;
  10579. var totalAverage = (totalMin+totalMax)/2;
  10580. $('#wc-xp').html(format.number(getXP));
  10581. $('#wc-logs-perk').html(format.number(bonusPerk));
  10582. $('#wc-logs-gem').html(format.number(bonusGem));
  10583. $('#wc-level-max').html(format.number(bonusLevel.max));
  10584. $('#wc-level-average').html(format.number(bonusLevel.average));
  10585. $('#wc-total-min').html(format.number(totalMin));
  10586. $('#wc-total-max').html(format.number(totalMax));
  10587. $('#wc-total-logs-average').html(format.number(totalAverage));
  10588. }
  10589. function woodcutting(){
  10590. addStyle('div.smallbox-fix-lines \n{\n\tline-height: 1.6;\n}');
  10591. $("#dialogue-axe-chance").parentsUntil("div").css({"display": "none"});
  10592. $("#dialogue-id-axe").find("br:first").remove();
  10593. var getSkillDialog = document.getElementById('dialogue-id-axe');
  10594. var div = document.createElement("div");
  10595. div.className = 'basic-smallbox';
  10596.  
  10597. div.innerHTML = '<div class="smallbox-fix-lines"><b>Total xp for chopping all of current trees: <x id="wc-xp" style="color: blue"></x></b><br /> \
  10598. <b>Current total logs per tree: <x id="wc-total-min" style="color: blue"></x> - <x id="wc-total-max" style="color: blue"></x> \
  10599. (<x id="wc-total-logs-average" style="color: blue"></x> on average)</b><br/> \
  10600. Original logs per tree: 15 - 30 (22 on average)<br/> \
  10601. Bonus logs from woodcutting level: random between 1 - <x id="wc-level-max"></x> \
  10602. (<x id="wc-level-average"></x> on average)</b><br/> \
  10603. Bonus logs from gems: <x id="wc-logs-gem"></x><br/> \
  10604. Bonus logs from achievement perk: <x id="wc-logs-perk"></x></div><br/> \
  10605. <table border="1"><tr><th>Level</th><th>1</th><th>15</th><th>30</th><th>50</th><th>70</th><th>85</th><th>95</th></tr> \
  10606. <tr><th>Tree</th><td><img src="images/woodcutting/tree4.png" width="65"></td><td><img src="images/woodcutting/oakTree4.png" width="65"></td> \
  10607. <td><img src="images/woodcutting/willowTree4.png" width="65"></td><td><img src="images/woodcutting/mapleTree4.png" width="65"></td> \
  10608. <td><img src="images/woodcutting/stardustTree4.png" width="65"></td><td><img src="images/woodcutting/strangeLeafTree4.png" width="65"></td> \
  10609. <td><img src="images/woodcutting/ancientTree4.png" width="65"></td> \
  10610. <tr><th>XP</th><th>1,000</th><th>2,500</th><th>5,000</th><th>10,000</th><th>16,000</th><th>20,000</th><th>40,000</th></tr> \
  10611. <tr><th>Time</th><th>3</th><th>6</th><th>8</th><th>12</th><th>16</th><th>20</th><th>40</th></tr> \
  10612. <tr><th>XP/h ratio</th><th>333</th><th>416</th><th>625</th><th>833</th><th>1,000</th><th>1,000</th><th>1,000</th></tr> \
  10613. </table>';
  10614.  
  10615. getSkillDialog.insertBefore(div, document.getElementById('dialgoue-axe-upgrade-with'));
  10616. }
  10617. function bonemealBinCalc(){
  10618. var stripedCrystalLeafSeeds = ['stripedCrystalLeafSeeds', 100];
  10619. var ancientTreeSeeds = ['ancientTreeSeeds', 100];
  10620. var strangeLeafTreeSeeds = ['strangeLeafTreeSeeds', 65];
  10621. var stardustTreeSeeds = ['stardustTreeSeeds', 50];
  10622. var crystalLeafSeeds = ['crystalLeafSeeds', 50];
  10623. var mapleTreeSeeds = ['mapleTreeSeeds', 30];
  10624. var willowTreeSeeds = ['willowTreeSeeds', 15];
  10625. var goldLeafSeeds = ['goldLeafSeeds', 10];
  10626. var stardustSeeds = ['stardustSeeds', 5];
  10627.  
  10628. var stripedCrystalBM = getGameValue(stripedCrystalLeafSeeds[0]) * stripedCrystalLeafSeeds[1];
  10629. var ancientTreeBM = getGameValue(ancientTreeSeeds[0]) * ancientTreeSeeds[1];
  10630. var strangeLeafTreeBM = getGameValue(strangeLeafTreeSeeds[0]) * strangeLeafTreeSeeds[1];
  10631. var stardustTreeBM = getGameValue(stardustTreeSeeds[0]) * stardustTreeSeeds[1];
  10632. var crystalLeafBM = getGameValue(crystalLeafSeeds[0]) * crystalLeafSeeds[1];
  10633. var mapleTreeBM = getGameValue(mapleTreeSeeds[0]) * mapleTreeSeeds[1];
  10634. var willowTreeBM = getGameValue(willowTreeSeeds[0]) * willowTreeSeeds[1];
  10635. var goldLeafBM = getGameValue(goldLeafSeeds[0]) * goldLeafSeeds[1];
  10636. var stardustBM = getGameValue(stardustSeeds[0]) * stardustSeeds[1];
  10637.  
  10638. var totalBM = stripedCrystalBM+ancientTreeBM+strangeLeafTreeBM+stardustTreeBM +crystalLeafBM +mapleTreeBM +willowTreeBM +goldLeafBM +stardustBM;
  10639. $("#bonemeal-need").text(format.number(totalBM));
  10640. }
  10641. function bonemealBin(){
  10642. $('#bonemeal-bones-input').css('width', "51px");
  10643. var getSkillDialog = document.getElementById('dialogue-bonemeal');
  10644. var div = document.createElement("div");
  10645. div.className = 'basic-smallbox';
  10646. div.innerHTML = '<div class="smallbox-fix-lines"><b>You would need <x id="bonemeal-need" style="color: blue"></x> bonemeal to grow all of your seeds</b><br /> \
  10647. Bone Amulet (Skeleton in Caves) or Bone Ring (Vendor) x2 bones in lootbags<br /> \
  10648. Green Bonemeal Bin Orb +1 bonemeal for every bonemeal item<br /></div> \
  10649. ';
  10650. $(div).insertAfter("#dialogue-bonemeal h2:first");
  10651. $("#dialogue-bonemeal h2:first").css("display", "none");
  10652. var boneSource = " <b>Source: </b><img title='Treasure Chest' src='images/treasureChest.png' class='image-icon-50'> \
  10653. <img title='Chicken' src='images/hero/npc/1.png' class='image-icon-50'> \
  10654. <img title='Rat' src='images/hero/npc/2.png' class='image-icon-50'> <img title='Thief' src='images/hero/npc/6.png' class='image-icon-50'> \
  10655. <img title='Bear' src='images/hero/npc/7.png' class='image-icon-50'> <img title='Skeleton' src='images/hero/npc/9.png' class='image-icon-50'> \
  10656. <img title='Vendor' src='images/vendor.png' class='image-icon-50'> \
  10657. ";
  10658. var ashesSource = " <b>Source: </b><img title='Green Treasure Chest' src='images/greenTreasureChest.png' class='image-icon-50'> \
  10659. <img title='Golem' src='images/hero/npc/10.png' class='image-icon-50'> \
  10660. <img title='Fire Bird' src='images/hero/npc/11.png' class='image-icon-50'> <img title='Fire Mage' src='images/hero/npc/12.png' class='image-icon-50'> \
  10661. ";
  10662. var iceBonesSource = " <b>Source: </b><img title='Lizard' src='images/hero/npc/13.png' class='image-icon-50'> \
  10663. <img title='Ice Bird' src='images/hero/npc/15.png' class='image-icon-50'> \
  10664. ";
  10665. var moonBonesSource = " <b>Source: </b><img title='Giant' src='images/hero/npc/19.png' class='image-icon-50'> \
  10666. <img title='Five Eyed' src='images/hero/npc/20.png' class='image-icon-50'> \
  10667. ";
  10668. var darkBonesSource = " <b>Source: </b><img title='Dark Mage' src='images/hero/npc/22.png' class='image-icon-50'> \
  10669. <img title='Pirate Skeleton' src='images/hero/npc/23.png' class='image-icon-50'> <img title='Dark Witch' src='images/hero/npc/24.png' class='image-icon-50'> \
  10670. ";
  10671. $("#bonemeal-bones-box").append(boneSource);
  10672. $("#bonemeal-ashes-box").append(ashesSource);
  10673. $("#bonemeal-iceBones-box").append(iceBonesSource);
  10674. $("#bonemeal-moonBones-box").append(moonBonesSource);
  10675. $("#bonemeal-darkBones-box").append(darkBonesSource);
  10676. }
  10677. function brewing(){
  10678. var getSkillDialog = document.getElementById("dialogue-id-brewingkit");
  10679. var note = (!boundBrewingKit) ? '<b style="color:red">Note:</b> You do not have this item yet, this is just a DH2 Fixed effect to<br/> show the calculator' : '';
  10680. var title = "<h1 class='container-title'>Brewing Calculator</h1>";
  10681. var closeButton= '<br/><input type="button" value="Close"/>';
  10682. var div = `<br/><div class='basic-smallbox' style="line-height: 1.6"><b>You need about <span style="color:blue" id="total-current-pot-xp"></span> \
  10683. to drink all of current potions</b> <br/>(click on headers to sort the table)<br/> \
  10684. The <b>Brewable XP</b> column will give you an idea about the priority of which potion<br/> should be brewed in term of XP<br/> \
  10685. <table id="brewing-calc-table" border="1" style="text-align:center"><thead><tr><th>Potion</th><th class="sortable ascending-sort number"> \
  10686. Current</th><th class="sortable ascending-sort number">Brewable</th><th class="sortable ascending-sort number">Total</th> \
  10687. <th class="sortable ascending-sort number"> \
  10688. Current XP</th><th class="sortable ascending-sort number">Brewable XP</th><th class="sortable ascending-sort number">Total XP</th> \
  10689. <th class="sortable ascending-sort time">Current Time</th></tr></thead><tbody></tbody></table></div>`;
  10690.  
  10691. $(getSkillDialog).append(title);
  10692. $(getSkillDialog).append(note);
  10693. $(getSkillDialog).append(div);
  10694. $(getSkillDialog).append(closeButton);
  10695. var allPots = ['stardust', 'tree', 'seed', 'smelting', 'oil', 'bar','supersd', 'cd', 'farmingspeed', 'stargem', 'mana', 'superoil',
  10696. 'supertree', 'supercombatcd', 'supercompost', 'supermana', 'dark', 'oxygen', 'crit', 'lootbag'];
  10697. var image = ['stardust', 'tree', 'seed', 'smelting', 'oil', 'bar','superStardust', 'combatCooldown', 'farmingSpeed', 'stargem', 'mana', 'superOil',
  10698. 'superTree', 'superCombatCooldown', 'superCompost', 'superMana', 'dark', 'oxygen', 'criticalStrike', 'lootBag'];
  10699.  
  10700. for (let i = 0; i < allPots.length; i++){
  10701. var potRow = `<tr><td><img src='images/`+image[i]+`Potion.png' class="image-icon-40"></td><td id ="`+allPots[i]+`-current"> \
  10702. </td><td id ="`+allPots[i]+`-brewable"></td><td id ="`+allPots[i]+`-total"></td><td id ="`+allPots[i]+`-current-xp"> \
  10703. </td><td id ="`+allPots[i]+`-brewable-xp"></td><td id ="`+allPots[i]+`-total-xp"></td> \
  10704. <td id ="`+allPots[i]+`-current-time"></td></tr>`;
  10705. $("#brewing-calc-table tbody").append(potRow);
  10706. }
  10707. }
  10708. function findMinPot(ingre1, ratio1, ingre2, ratio2, ingre3, ratio3, ingre4, ratio4, ingre5, ratio5){
  10709.  
  10710. var first = isNaN(ingre1/ratio1)? Infinity : ingre1/ratio1;
  10711. var second = isNaN(ingre2/ratio2)? Infinity : ingre2/ratio2;
  10712. var third = isNaN(ingre3/ratio3)? Infinity : ingre3/ratio3;
  10713. var fourth = isNaN(ingre4/ratio4)? Infinity : ingre4/ratio4;
  10714. var fifth = isNaN(ingre5/ratio5)? Infinity : ingre5/ratio5;
  10715. var getMin = Math.min(first, second, third, fourth, fifth);
  10716. getMin = Math.floor(getMin);
  10717. return getMin;
  10718. }
  10719. function formatRound(value){
  10720. return format.number(Math.floor(value));
  10721.  
  10722. }
  10723. function fullTime(timer)
  10724. {
  10725.  
  10726. if (typeof timer === 'string')
  10727. {
  10728. timer = parseInt(timer, 10);
  10729. }
  10730. timer = Math.max(timer, 0);
  10731. var days = Math.floor(timer / 86400);
  10732. var hours = Math.floor((timer % 86400) / 3600);
  10733. var minutes = Math.floor((timer % 3600) / 60);
  10734. var seconds = timer % 60;
  10735. return zeroPadLeft(days) + 'd ' + zeroPadLeft(hours) + ':' + zeroPadLeft(minutes) + ':' + zeroPadLeft(seconds) ;
  10736. }
  10737. function removeComma(string){
  10738. return parseInt(string.replace(/,/g,''), 10);
  10739. }
  10740. function convertTime(time){
  10741. return new Date("2018/01/01 "+ time.replace(/[0-9][0-9]d\s/g,'')).getTime() +
  10742. parseInt(time.replace(/d\s[0-2]?[0-3]:[0-5][0-9]:[0-5][0-9]/g,''), 10) * 86400000;
  10743. }
  10744.  
  10745. function brewingCalc(){
  10746.  
  10747. var donorXPBoost = (win.donorXpBoost > win.currentTimeMillis) ? 1.1 : 1;
  10748. var bonusDuration = 1;
  10749. var bonusAch = 0;
  10750. var bonusLevel = 0;
  10751. var brewingLevel = win.getLevel(win.brewingXp);
  10752. if (achBrewingHardCompleted){
  10753. bonusAch = 15;
  10754. }else if (achBrewingMediumCompleted){
  10755. bonusAch = 10;
  10756. }else if (achBrewingEasyCompleted){
  10757. bonusAch = 5;
  10758. }else{
  10759. bonusAch = 0;
  10760. }
  10761. for(let i = 0; i <= 100; i += 5){
  10762. if (brewingLevel >= i && brewingLevel < (i+5)){
  10763. bonusLevel = i/5;
  10764. }
  10765. }
  10766. bonusDuration = bonusDuration * (1 + (bonusAch+bonusLevel)/100);
  10767.  
  10768. var sdBrewable = findMinPot(dottedGreenLeaf, 1, redMushroom, 25);
  10769. var treeBrewable = findMinPot(dottedGreenLeaf, 2, redMushroom, 15);
  10770. var seedBrewable = findMinPot(dottedGreenLeaf, 1, redMushroom, 30);
  10771. var smeltingBrewable = findMinPot(dottedGreenLeaf, 3);
  10772. var oilBrewable = findMinPot(greenLeaf, 1, redMushroom, 50);
  10773. var barBrewable = findMinPot(greenLeaf, 3, blewitMushroom, 50);
  10774. var supersdBrewable = findMinPot(limeLeaf, 5, snapegrass, 50);
  10775. var cdBrewable = findMinPot(strangeBlueLeaf, 1, greenLeaf, 5);
  10776. var farmingspeedBrewable = findMinPot(redMushroom, 100, blewitMushroom, 50, snapegrass, 10);
  10777. var stargemBrewable = findMinPot(goldLeaf, 1, blewitMushroom, 100);
  10778. var manaBrewable = findMinPot(goldLeaf, 1, limeLeaf, 10, strangePurpleLeaf, 1);
  10779. var superoilBrewable = findMinPot(goldLeaf, 3, redMushroom, 150);
  10780. var supertreeBrewable = findMinPot(goldLeaf, 3, blewitMushroom, 50);
  10781. var supercombatcdBrewable = findMinPot(strangeBlueLeaf, 4, greenLeaf, 20);
  10782. var supercompostBrewable = findMinPot(crystalLeaf, 5, redMushroom, 200, blewitMushroom, 100, snapegrass, 50);
  10783. var supermanaBrewable = findMinPot(crystalLeaf, 5, limeLeaf, 25, strangePurpleLeaf, 5);
  10784. var darkBrewable = findMinPot(limeLeaf, 25, goldLeaf, 10, darkMushroomLair, 10);
  10785. var oxygenBrewable = findMinPot(greenLeaf, 100, limeLeaf, 50, goldLeaf, 20, crystalLeaf, 10, strangePinkLeaf, 1);
  10786. var critBrewable = findMinPot(crystalLeaf, 10, stripedCrystalLeaf, 1, strangeBlueLeaf, 5);
  10787. var lootbagBrewable = findMinPot(crystalLeaf, 10, stripedCrystalLeaf, 2, goldLeaf, 15, strangePurpleLeaf, 1);
  10788.  
  10789. var stardust = {"current" : win.stardustPotion, "brewable" : sdBrewable, "xp": 50, "time": 5};
  10790. var tree = {"current" : win.treePotion, "brewable" : treeBrewable, "xp": 70, "time": 10};
  10791. var seed = {"current" : win.seedPotion, "brewable" : seedBrewable, "xp": 75, "time": 30};
  10792. var smelting = {"current" : win.smeltingPotion, "brewable" : smeltingBrewable, "xp": 200, "time": 30};
  10793. var oil = {"current" : win.oilPotion, "brewable" : oilBrewable, "xp": 210, "time": 15};
  10794. var bar = {"current" : win.barPotion, "brewable" : barBrewable, "xp": 380, "time": 30};
  10795. var supersd = {"current" : win.superStardustPotion, "brewable" : supersdBrewable, "xp": 480, "time": 5};
  10796. var cd = {"current" : win.combatCooldownPotion, "brewable" : cdBrewable, "xp": 555, "time": 0};
  10797. var farmingspeed = {"current" : win.farmingSpeedPotion, "brewable" : farmingspeedBrewable, "xp": 900, "time": 30};
  10798. var stargem = {"current" : win.stargemPotion, "brewable" : stargemBrewable, "xp": 1000, "time": 0};
  10799. var mana = {"current" : win.manaPotion, "brewable" : manaBrewable, "xp": 1250, "time": 1};
  10800. var superoil = {"current" : win.superOilPotion, "brewable" : superoilBrewable, "xp": 2200, "time": 15};
  10801. var supertree = {"current" : win.superTreePotion, "brewable" : supertreeBrewable, "xp": 2350, "time": 30};
  10802. var supercombatcd = {"current" : win.superCombatCooldownPotion, "brewable" : supercombatcdBrewable, "xp": 2550, "time": 0};
  10803. var supercompost = {"current" : win.superCompostPotion, "brewable" : supercompostBrewable, "xp": 4550, "time": 0};
  10804. var supermana = {"current" : win.superManaPotion, "brewable" : supermanaBrewable, "xp": 5000, "time": 1};
  10805. var dark = {"current" : win.darkPotion, "brewable" : darkBrewable, "xp": 6000, "time": 1440};
  10806. var oxygen = {"current" : win.oxygenPotion, "brewable" : oxygenBrewable, "xp": 6650, "time": 0};
  10807. var crit = {"current" : win.criticalStrikePotion, "brewable" : critBrewable, "xp": 7000, "time": 1};
  10808. var lootbag = {"current" : win.lootBagPotion, "brewable" : lootbagBrewable, "xp": 15000, "time": 0};
  10809.  
  10810. var allPots = ['stardust', 'tree', 'seed', 'smelting', 'oil', 'bar','supersd', 'cd', 'farmingspeed', 'stargem', 'mana', 'superoil',
  10811. 'supertree', 'supercombatcd', 'supercompost', 'supermana', 'dark', 'oxygen', 'crit', 'lootbag'];
  10812.  
  10813. var durationList = [];
  10814.  
  10815. for (let i = 0; i < allPots.length; i++){
  10816. durationList.push(eval(allPots[i]).current * Math.floor(eval(allPots[i]).time * 60 * bonusDuration));
  10817.  
  10818. $('#'+allPots[i]+'-current').html(formatRound(eval(allPots[i]).current));
  10819. $('#'+allPots[i]+'-brewable').html(formatRound(eval(allPots[i]).brewable));
  10820. $('#'+allPots[i]+'-total').html(formatRound(eval(allPots[i]).current + eval(allPots[i]).brewable));
  10821. $('#'+allPots[i]+'-current-xp').html(formatRound(eval(allPots[i]).current * eval(allPots[i]).xp * donorXPBoost));
  10822. $('#'+allPots[i]+'-brewable-xp').html(formatRound(eval(allPots[i]).brewable * eval(allPots[i]).xp * 2* donorXPBoost));
  10823. $('#'+allPots[i]+'-total-xp').html(formatRound(eval(allPots[i]).current * eval(allPots[i]).xp* donorXPBoost +
  10824. eval(allPots[i]).brewable * eval(allPots[i]).xp * 2* donorXPBoost));
  10825. $('#'+allPots[i]+'-current-time').html(fullTime(eval(allPots[i]).current * Math.floor(eval(allPots[i]).time * 60 * bonusDuration)));
  10826. }
  10827.  
  10828. $('#total-current-pot-xp').html(format.timer(Math.max(...durationList)));
  10829.  
  10830. }
  10831. function orbs(){
  10832. var getSkillDialog = document.getElementById("dialogue-id-orbs-tracking");
  10833. var title = "<h1 class='container-title'>Orbs tracking status</h1>";
  10834. var closeButton= '<br/><input type="button" value="Close"/>';
  10835. var blueOrbBox = `<br/><div class='basic-smallbox'> \
  10836. <table id="blue-orbs-table" style="text-align:center"><tr></tr><tr></tr></table></div>`;
  10837. var greenOrbBox = `<br/><div class='basic-smallbox'> \
  10838. <table id="green-orbs-table" style="text-align:center"><tr></tr><tr></tr></table></div>`;
  10839. var redOrbBox = `<br/><div class='basic-smallbox'> \
  10840. <table id="red-orbs-table" style="text-align:center"><tr></tr><tr></tr></table></div>`;
  10841. $(getSkillDialog).append(title);
  10842. $(getSkillDialog).append(blueOrbBox);
  10843. $(getSkillDialog).append(greenOrbBox);
  10844. $(getSkillDialog).append(redOrbBox);
  10845. $(getSkillDialog).append(closeButton);
  10846.  
  10847. var statusNo = "<td><img src='images/icons/x.png' class='image-icon-20'></td>";
  10848. var statusYes = "<td><img src='images/icons/check.png' class='image-icon-20'></td>";
  10849.  
  10850. var blueOrbs = ["FishingRod", "Shovel", "Axe", "Rake", "Trowel", "Pickaxe", "OilPipe", "Hammer", "Chisel", "Meditation"];
  10851. var blueTitles = ["Your fishermen will catch 3 new types of fish", "Collects bait over time", "10% chance that a tree will rewgrow instantly when chopped",
  10852. "10% chance of getting seeds back on harvest", "10% chance of getting food seeds back on harvest", "Ores will grant twice the XP \
  10853. when using the pickaxe", "Doubles your oil pipe income", "Save 2 stardust per xp for when converting bars to xp", "10% more stardust when opening stardust \
  10854. crystals", "Meditate twice as fast"];
  10855. for (let i = 0; i < blueOrbs.length; i++){
  10856. var orbRow1 = "<td><img title='"+blueTitles[i]+"' src='images/blue"+blueOrbs[i]+"Orb.png' class='image-icon-50'></td>";
  10857. $("#blue-orbs-table tr:first").append(orbRow1);
  10858. $("#blue-orbs-table tr:eq(1)").append((getGameValue("boundBlue"+blueOrbs[i]+"Orb")) ? statusYes : statusNo);
  10859. }
  10860. var greenOrbs = ["OilFactory", "Combat", "BrewingKit", "Bow", "BonemealBin", "Rocket", "OilStorage", "EmpoweredRock"];
  10861. var greenTitles = ["Doubles your oil income for each factory worker", "Increases your attack, accuracy, defence and magic by 1 permanently",
  10862. "Doubles the chances of getting two potions instead of one from the brewing kit", "50% chance to save an arrow every attack",
  10863. "+1 bonemeal on every bone", "Allows your rocket to travel to mars", "Doubles oil capacity on every oil \
  10864. storage", "Get 20% stardust back each time you use an empowered rock"];
  10865. for (let i = 0; i < greenOrbs.length; i++){
  10866. var orbRow2 = "<td><img title='"+greenTitles[i]+"' src='images/green"+greenOrbs[i]+"Orb.png' class='image-icon-50'></td>";
  10867. $("#green-orbs-table tr:first").append(orbRow2);
  10868. $("#green-orbs-table tr:eq(1)").append((getGameValue("boundGreen"+greenOrbs[i]+"Orb")) ? statusYes : statusNo);
  10869. }
  10870. var redOrbs = ["MagicWand", "CharcoalFactory", "ManaStar", "CombatLoot", "Axe", "FishingBait", "Rocket"];
  10871. var redTitles = ["Double damage on all magic spells", "Doubles oil income from the charcoal factory and uses much less charcoal \
  10872. ", "Every mana star is increased by 1", "Allows you to convert a loot bag into a shiny one by right clicking it every 72h", "Allows \
  10873. you to convert a fully grown tree into a shiny one every 72h", "Increases efficiency of bait on all boats", "Allows your rocket \
  10874. travelling into intesteller space to collect space dust."];
  10875. for (let i = 0; i < redOrbs.length; i++){
  10876. var orbRow3 = "<td><img title='"+redTitles[i]+"' src='images/red"+redOrbs[i]+"Orb.png' class='image-icon-50'></td>";
  10877. $("#red-orbs-table tr:first").append(orbRow3);
  10878. $("#red-orbs-table tr:eq(1)").append((getGameValue("boundRed"+redOrbs[i]+"Orb")) ? statusYes : statusNo);
  10879. }
  10880. }
  10881. function orbsCalc(){
  10882. var blueOrbs = ["FishingRod", "Shovel", "Axe", "Rake", "Trowel", "Pickaxe", "OilPipe", "Hammer", "Chisel", "Meditation"];
  10883. var greenOrbs = ["OilFactory", "Combat", "BrewingKit", "Bow", "BonemealBin", "Rocket", "OilStorage", "EmpoweredRock"];
  10884. var redOrbs = ["MagicWand", "CharcoalFactory", "ManaStar", "CombatLoot", "Axe", "FishingBait", "Rocket"];
  10885. var statusNo = "<img src='images/icons/x.png' class='image-icon-20'>";
  10886. var statusYes = "<img src='images/icons/check.png' class='image-icon-20'>";
  10887.  
  10888. for (let i = 0; i < blueOrbs.length; i++){
  10889. $("#blue-orbs-table tr:eq(1) td:eq("+i+")").html((getGameValue("boundBlue"+blueOrbs[i]+"Orb")) ? statusYes : statusNo);
  10890. }
  10891. for (let i = 0; i < greenOrbs.length; i++){
  10892. $("#green-orbs-table tr:eq(1) td:eq("+i+")").html((getGameValue("boundGreen"+greenOrbs[i]+"Orb")) ? statusYes : statusNo);
  10893. }
  10894. for (let i = 0; i < redOrbs.length; i++){
  10895. $("#red-orbs-table tr:eq(1) td:eq("+i+")").html((getGameValue("boundRed"+redOrbs[i]+"Orb")) ? statusYes : statusNo);
  10896. }
  10897.  
  10898. }
  10899. function levelDialog(){
  10900. var getDialog = $("#level-table-dialog");
  10901. var title = `<h1 class='container-title'>XP/level calculator</h1>`;
  10902. var box1 = `<br/><div class='basic-smallbox' style="line-height: 1.7;">Calculate the XP needed to upgrade <br/>
  10903. one of your skills<br/><table><tr><td><b>Target level: </b></td><td><input type="number" value="1" \
  10904. id="input-level-calc" size="4" min="1" max="100" style="width: 47px;"></td></tr> \
  10905. <tr><td><b>Current level: </b></td><td><input type="number" value="1" id="input-current-level-calc" \
  10906. size="4" min="1" max="100" style="width: 47px;"></td></tr></table></div>`;
  10907. var box2 = `<div class='basic-smallbox' style="line-height: 1.7;"><table><tr><td><b>Target XP: </b></td><td><span id="output-xp-calc" ></span></td> \
  10908. </tr><tr><td><b>Needed XP: </b></td><td><span id="output-needed-xp-calc" ></span></td></tr></table></div>`;
  10909.  
  10910. var closeButton= '<br/><input type="button" value="Close"/>';
  10911. getDialog.append(title);
  10912. getDialog.append(box1);
  10913. getDialog.append(box2);
  10914. getDialog.append(closeButton);
  10915. }
  10916. function levelCalc(){
  10917. var levelVal = $('#input-level-calc').val();
  10918. var XP = (levelVal > 100) ? Number.NaN : Math.pow(levelVal, 3+(levelVal/200));
  10919. XP = Math.floor(XP);
  10920. var currentLevel = $('#input-current-level-calc').val();
  10921. var currentXP = (currentLevel > 100) ? Number.NaN : Math.pow(currentLevel, 3+(currentLevel/200));
  10922. var needXP = XP - currentXP;
  10923. needXP = Math.floor(needXP);
  10924. $('#output-xp-calc').html(format.number(XP));
  10925. $('#output-needed-xp-calc').html(format.number(needXP));
  10926. }
  10927. function fightDialog(){
  10928. $("#dialogue-fight table tr:eq(0)").append("<th>Avg XP/energy</th><th>Avg XP/minute</th>");
  10929. $("#dialogue-fight table tr:eq(1)").append("<td>0.8</td><td>2.67</td>");
  10930. $("#dialogue-fight table tr:eq(2)").append("<td style='background-color: yellow'>1.6</td><td>5.33</td>");
  10931. $("#dialogue-fight table tr:eq(3)").append("<td style='background-color: #e4bf91'>1.23</td><td>20.56</td>");
  10932. $("#dialogue-fight table tr:eq(4)").append("<td style='background-color: #e0dcdc'>1.47</td><td style='background-color: #e4bf91'>36.67</td>");
  10933. $("#dialogue-fight table tr:eq(5)").append("<td>0.82</td><td>31.85</td>");
  10934. $("#dialogue-fight table tr:eq(6)").append("<td>0.92</td><td style='background-color: yellow'>57.78</td>");
  10935. $("#dialogue-fight table tr:eq(8)").append("<td>0.41</td><td style='background-color: #e0dcdc'>55.22</td>");
  10936. $("#dialogue-fight table tr:eq(9) td:first").attr("colspan", 7);
  10937. }
  10938. function fishingBait(){
  10939. var getSkillDialog = document.getElementById("dialogue-id-fishingbait-calc");
  10940. var title = "<h1 class='container-title'>Fishing Bait Calculator</h1>";
  10941. var closeButton= '<br/><input type="button" value="Close"/>';
  10942. var baitTable = `<br/><div class='basic-smallbox smallbox-fix-lines'>Beside from loot bags, baits can be found from<br> the shovel with Blue Shovel Orb<br/> \
  10943. <br/><table id="fishing-bait-table" border="1" style="text-align:center"><tr><th>Area</th><th>Baits/hour</th><th>Energy cost/bait</th></tr></table></div>`;
  10944.  
  10945. $(getSkillDialog).append(title);
  10946. $(getSkillDialog).append(baitTable);
  10947. $(getSkillDialog).append(closeButton);
  10948.  
  10949. var areaList = {name : ["Fields", "Forests", "Caves", "Volcano", "Northern Fields", "Haunted Mansion", "Moon", "Dark Forest"],
  10950. baitPerhour: [1, 2.88, 1.7, 0.92, 0.61, 2, 0.71, 2.05],
  10951. energyPerbait: [200, 69, 588, 1620, 3825, 1875, 2000, 3902]};
  10952. for (let i = 0; i < areaList.name.length; i++){
  10953. var row = "<tr><td>"+areaList.name[i]+"</td><td>"+areaList.baitPerhour[i]+"</td><td>"+format.number(areaList.energyPerbait[i])+"</td></tr>";
  10954. $("#fishing-bait-table").append(row);
  10955. }
  10956. $("#fishing-bait-table tr:eq(2) td:eq(1)").css("background-color", "yellow");
  10957. $("#fishing-bait-table tr:eq(2) td:eq(2)").css("background-color", "yellow");
  10958. $("#fishing-bait-table tr:eq(8) td:eq(1)").css("background-color", "silver");
  10959. $("#fishing-bait-table tr:eq(1) td:eq(2)").css("background-color", "silver");
  10960. $("#fishing-bait-table tr:eq(6) td:eq(1)").css("background-color", "#e4bf91");
  10961. $("#fishing-bait-table tr:eq(3) td:eq(2)").css("background-color", "#e4bf91");
  10962. }
  10963. var gradientColorLight = '#00ff37';
  10964. var gradientColorDark = '#065b00';
  10965. function initFishingBaitCalc(){
  10966. var box = $("#item-box-fishingBait");
  10967. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  10968. box.hover(function(){
  10969. box.css("background", ""+gradientColorDark+"");
  10970. }, function(){
  10971. $(this).css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  10972. });
  10973. $("#default-item-img-tag-fishingBait").hover(function(){
  10974. box.css("background", ""+gradientColorDark+"");
  10975. }, function(){
  10976. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  10977. });
  10978. var dialog = document.createElement('dialog');
  10979. dialog.id = 'dialogue-id-fishingbait-calc';
  10980. document.body.appendChild(dialog);
  10981.  
  10982. box.click(function(){
  10983. $(dialog).dialog(
  10984. {
  10985. title: 'Fishing Bait',
  10986. height: 'auto',
  10987. width: 'auto'
  10988. });
  10989. });
  10990. fishingBait();
  10991. $("#dialogue-id-fishingbait-calc :button").click(function(){
  10992. $(this).closest(".ui-dialog-content").dialog("close");
  10993. });
  10994. }
  10995. function initlevelCalc(){
  10996.  
  10997. $("<tr><td colspan='3'><span id='level-table-btn' class='market-browse-button' style='font-size:30px;font-weight:bold;color: \
  10998. #f57a90;'><img src='images/icons/skills.png' class='image-icon-50'>XP/level calculator</span></td></tr>").insertBefore("#view-full-profile-btn");
  10999.  
  11000. var btn = $("#level-table-btn");
  11001. var dialog = document.createElement('dialog');
  11002. dialog.id = 'level-table-dialog';
  11003. document.body.appendChild(dialog);
  11004. btn.click(function(){
  11005. $(dialog).dialog(
  11006. {
  11007. title: 'XP and level',
  11008. height: 'auto',
  11009. width: 'auto'
  11010. });
  11011. });
  11012. levelDialog();
  11013. var getDialog = $('#level-table-dialog');
  11014. $(":button", getDialog).click(function(){
  11015. $(this).closest(".ui-dialog-content").dialog("close");
  11016. });
  11017. document.getElementById("input-level-calc").addEventListener("keyup", function(){
  11018. levelCalc();
  11019. });
  11020. document.getElementById("input-level-calc").addEventListener("mouseup", function(){
  11021. levelCalc();
  11022. });
  11023. document.getElementById("input-current-level-calc").addEventListener("keyup", function(){
  11024. levelCalc();
  11025. });
  11026. document.getElementById("input-current-level-calc").addEventListener("mouseup", function(){
  11027. levelCalc();
  11028. });
  11029. }
  11030. function initOrbsCalc(){
  11031. var box = $("#item-box-pirate");
  11032. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11033. box.hover(function(){
  11034. box.css("background", ""+gradientColorDark+"");
  11035. }, function(){
  11036. $(this).css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11037. });
  11038. $("#default-item-img-tag-pirate").hover(function(){
  11039. box.css("background", ""+gradientColorDark+"");
  11040. }, function(){
  11041. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11042. });
  11043. var dialog = document.createElement('dialog');
  11044. dialog.id = 'dialogue-id-orbs-tracking';
  11045. document.body.appendChild(dialog);
  11046.  
  11047. box.click(function(){
  11048. $(dialog).dialog(
  11049. {
  11050. title: 'Orb tracker',
  11051. height: 'auto',
  11052. width: 'auto'
  11053. });
  11054. orbsCalc();
  11055. });
  11056. orbs();
  11057. $("#dialogue-id-orbs-tracking :button").click(function(){
  11058. $(this).closest(".ui-dialog-content").dialog("close");
  11059. });
  11060. }
  11061. function initBrewingCalc(){
  11062. var brewingKit = $("#item-box-boundBrewingKit");
  11063. if(!boundBrewingKit){
  11064. brewingKit.css("display", "inline-block");
  11065. }
  11066. var dialog = document.createElement('dialog');
  11067. dialog.id = 'dialogue-id-brewingkit';
  11068. document.body.appendChild(dialog);
  11069.  
  11070. brewingKit.click(function(){
  11071. $(dialog).dialog(
  11072. {
  11073. title: 'Brewing Kit',
  11074. height: 'auto',
  11075. width: 'auto'
  11076.  
  11077. });
  11078. brewingCalc();
  11079. });
  11080. brewing();
  11081.  
  11082. brewingKit.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11083. brewingKit.hover(function(){
  11084. brewingKit.css("background", ""+gradientColorDark+"");
  11085. }, function(){
  11086. brewingKit.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11087. });
  11088. $("#default-item-img-tag-boundBrewingKit").hover(function(){
  11089. brewingKit.css("background", ""+gradientColorDark+"");
  11090. }, function(){
  11091. brewingKit.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11092. });
  11093.  
  11094. $("#dialogue-id-brewingkit :button").click(function(){
  11095. $(this).closest(".ui-dialog-content").dialog("close");
  11096. });
  11097.  
  11098. $(".sortable").click(function(){
  11099. var header = this;
  11100. var table = document.getElementById("brewing-calc-table");
  11101. var rows = table.rows, arr = [];
  11102. var col = $(this).index();
  11103. for (let i = 1; i < rows.length; i++) {
  11104. var cells = rows[i].cells;
  11105. arr[i] = [];
  11106. for (let j = 0; j < cells.length; j++) {
  11107. arr[i][j] = cells[j].innerHTML;
  11108. }
  11109. }
  11110.  
  11111. if($(this).hasClass('ascending-sort')){
  11112. $(this).removeClass('ascending-sort').addClass("descending-sort");
  11113. arr.sort(function(a, b){
  11114. if($(header).hasClass('number')){
  11115. return removeComma(a[col]) - removeComma(b[col]);
  11116. }else if($(header).hasClass('time')){
  11117. return convertTime(a[col]) - convertTime(b[col]);
  11118. }
  11119. });
  11120.  
  11121. } else if($(this).hasClass('descending-sort')){
  11122. $(this).removeClass('descending-sort').addClass("ascending-sort");
  11123. arr.sort(function(a, b){
  11124. if($(header).hasClass('number')){
  11125. return removeComma(b[col]) - removeComma(a[col]);
  11126. }else if($(header).hasClass('time')){
  11127. return convertTime(b[col]) - convertTime(a[col]);
  11128. }
  11129. });
  11130. }
  11131. for (let i = 1; i < rows.length; i++) {
  11132. rows[i].innerHTML = "<td>" + arr[i-1].join("</td><td>") + "</td>";
  11133. }
  11134. });
  11135. }
  11136. function initBonemealBinCalc(){
  11137. var box = $("#item-box-boundBonemealBin");
  11138. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11139. box.hover(function(){
  11140. box.css("background", ""+gradientColorDark+"");
  11141. }, function(){
  11142. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11143. });
  11144. $("#default-item-img-tag-boundBonemealBin").hover(function(){
  11145. box.css("background", ""+gradientColorDark+"");
  11146. }, function(){
  11147. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11148. });
  11149. var box2 = $("#item-box-boundFilledBonemealBin");
  11150. box2.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11151. box2.hover(function(){
  11152. box2.css("background", ""+gradientColorDark+"");
  11153. }, function(){
  11154. box2.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11155. });
  11156. $("#default-item-img-tag-boundFilledBonemealBin").hover(function(){
  11157. box2.css("background", ""+gradientColorDark+"");
  11158. }, function(){
  11159. box2.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11160. });
  11161. bonemealBin();
  11162. var _clicksBonemealBin = win.clicksBonemealBin;
  11163. win.clicksBonemealBin = function()
  11164. {
  11165. _clicksBonemealBin();
  11166. bonemealBinCalc();
  11167. };
  11168. }
  11169. function initMagicCalc()
  11170. {
  11171. var meditateLevel = 0;
  11172. for (var i = 1; i <= 9; i++){
  11173. if (getGameValue("meditate"+i) === 1){
  11174. meditateLevel = i;
  11175. }
  11176. }
  11177. var box = $("#item-box-meditate"+meditateLevel);
  11178. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11179. box.hover(function(){
  11180. box.css("background", ""+gradientColorDark+"");
  11181. }, function(){
  11182. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11183. });
  11184. $("#default-item-img-tag-meditate"+meditateLevel).hover(function(){
  11185. box.css("background", ""+gradientColorDark+"");
  11186. }, function(){
  11187. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11188. });
  11189.  
  11190. var dialog = document.createElement('dialog');
  11191. dialog.id = 'dialogue-id-meditate';
  11192. document.body.appendChild(dialog);
  11193.  
  11194. var _clicksMeditate = win.clicksMeditate;
  11195. win.clicksMeditate = function()
  11196. {
  11197. //openDialogue('dialogue-id-1');
  11198. var height = 430;
  11199. var width = 370;
  11200. $(dialog).dialog(
  11201. {
  11202. title: 'Magic Meditation',
  11203. height: height,
  11204. width: width
  11205. });
  11206. };
  11207. magic();
  11208. $("#stone").click(function(){
  11209. magicCalcXP(1, this);
  11210. });
  11211. $("#moonstone").click(function(){
  11212. magicCalcXP(2, this);
  11213. });
  11214. $("#marsrock").click(function(){
  11215. magicCalcXP(3, this);
  11216. });
  11217. $("#promethium").click(function(){
  11218. magicCalcXP(4, this);
  11219. });
  11220. $("#runite").click(function(){
  11221. magicCalcXP(5, this);
  11222. });
  11223. $("#dialogue-id-meditate :button").click(function(){
  11224. $(this).closest(".ui-dialog-content").dialog("close");
  11225. });
  11226.  
  11227. function checkRock(){
  11228. var rock = [];
  11229. var getstone = document.getElementById('stone');
  11230. var getmoonstone = document.getElementById('moonstone');
  11231. var getmarsrock = document.getElementById('marsrock');
  11232. var getpromethium = document.getElementById('promethium');
  11233. var getrunite = document.getElementById('runite');
  11234.  
  11235. if (getstone.style.backgroundColor == 'red'){
  11236. rock[0] = 1;
  11237. rock[1] = getstone;
  11238. }else if (getmoonstone.style.backgroundColor == 'red'){
  11239. rock[0] = 2;
  11240. rock[1] = getmoonstone;
  11241. }else if (getmarsrock.style.backgroundColor == 'red'){
  11242. rock[0] = 3;
  11243. rock[1] = getmarsrock;
  11244. }else if (getpromethium.style.backgroundColor == 'red'){
  11245. rock[0] = 4;
  11246. rock[1] = getpromethium;
  11247. }else if (getrunite.style.backgroundColor == 'red'){
  11248. rock[0] = 5;
  11249. rock[1] = getrunite;
  11250. }
  11251. return rock;
  11252. }
  11253.  
  11254. document.getElementById("magic-level").addEventListener("keyup", function(){
  11255. magicCalcLevel(checkRock()[0], checkRock()[1]);
  11256. });
  11257. document.getElementById("magic-level").addEventListener("mouseup", function(){
  11258.  
  11259. magicCalcLevel(checkRock()[0], checkRock()[1]);
  11260. });
  11261.  
  11262. document.getElementById("input-empowered-amount").addEventListener("keyup", function(){
  11263. magicCalcXP(checkRock()[0], checkRock()[1]);
  11264. });
  11265. document.getElementById("input-empowered-amount").addEventListener("mouseup", function(){
  11266.  
  11267. magicCalcXP(checkRock()[0], checkRock()[1]);
  11268. });
  11269.  
  11270. }
  11271.  
  11272. function initWoodcuttingCalc(){
  11273. var gem = 'Empty';
  11274. if (boundEmptyAxe){
  11275. gem = 'Empty';
  11276. }else if (boundSapphireAxe){
  11277. gem = 'Sapphire';
  11278. }else if (boundEmeraldAxe){
  11279. gem = 'Emerald';
  11280. }else if (boundRubyAxe){
  11281. gem = 'Ruby';
  11282. }else if (boundDiamondAxe){
  11283. gem = 'Diamond';
  11284. }
  11285.  
  11286. var box = $("#item-box-bound"+gem+"Axe");
  11287. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11288. box.hover(function(){
  11289. box.css("background", ""+gradientColorDark+"");
  11290. }, function(){
  11291. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11292. });
  11293. $("#default-item-img-tag-bound"+gem+"Axe").hover(function(){
  11294. box.css("background", ""+gradientColorDark+"");
  11295. }, function(){
  11296. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11297. });
  11298. woodcutting();
  11299. var _clicksAxe = win.clicksAxe;
  11300. win.clicksAxe = function()
  11301. {
  11302. _clicksAxe();
  11303. woodcuttingCalc();
  11304. };
  11305. }
  11306.  
  11307. function initMiningCalc()
  11308. {
  11309. var gem = 'Empty';
  11310. if (boundEmptyPickaxe){
  11311. gem = 'Empty';
  11312. }else if (boundSapphirePickaxe){
  11313. gem = 'Sapphire';
  11314. }else if (boundEmeraldPickaxe){
  11315. gem = 'Emerald';
  11316. }else if (boundRubyPickaxe){
  11317. gem = 'Ruby';
  11318. }else if (boundDiamondPickaxe){
  11319. gem = 'Diamond';
  11320. }
  11321. var box = $("#item-box-bound"+gem+"Pickaxe");
  11322. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11323. box.hover(function(){
  11324. box.css("background", ""+gradientColorDark+"");
  11325. }, function(){
  11326. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11327. });
  11328. $("#default-item-img-tag-bound"+gem+"Pickaxe").hover(function(){
  11329. box.css("background", ""+gradientColorDark+"");
  11330. }, function(){
  11331. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11332. });
  11333. doubleSkills(mining);
  11334. document.getElementById("xp-gain-pickaxe-convert").addEventListener("DOMSubtreeModified", function(){
  11335. doubleCalcs(mining);
  11336. });
  11337. }
  11338.  
  11339. function initCraftingCalc()
  11340. {
  11341. var gem = 'Empty';
  11342. if (boundEmptyHammer){
  11343. gem = 'Empty';
  11344. }else if (boundSapphireHammer){
  11345. gem = 'Sapphire';
  11346. }else if (boundEmeraldHammer){
  11347. gem = 'Emerald';
  11348. }else if (boundRubyHammer){
  11349. gem = 'Ruby';
  11350. }else if (boundDiamondHammer){
  11351. gem = 'Diamond';
  11352. }
  11353. var box = $("#item-box-bound"+gem+"Hammer");
  11354. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11355. box.hover(function(){
  11356. box.css("background", ""+gradientColorDark+"");
  11357. }, function(){
  11358. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11359. });
  11360. $("#default-item-img-tag-bound"+gem+"Hammer").hover(function(){
  11361. box.css("background", ""+gradientColorDark+"");
  11362. }, function(){
  11363. box.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11364. });
  11365. doubleSkills(crafting);
  11366. document.getElementById("xp-gain-hammer-convert").addEventListener("DOMSubtreeModified", function(){
  11367. doubleCalcs(crafting);
  11368. });
  11369. }
  11370. function init(){
  11371. initFishingBaitCalc();
  11372. initMiningCalc();
  11373. initCraftingCalc();
  11374. initMagicCalc();
  11375. initWoodcuttingCalc();
  11376. initBonemealBinCalc();
  11377. initBrewingCalc();
  11378. initOrbsCalc();
  11379. initlevelCalc();
  11380. fightDialog();
  11381. }
  11382. calc.init = init;
  11383.  
  11384. })(calc || (calc = {}));
  11385.  
  11386. /**
  11387. * general features which doesn't really belong anywhere
  11388. */
  11389. var general;
  11390. (function (general)
  11391. {
  11392. general.name = 'general';
  11393. // disable the drink button for 3 seconds
  11394. var DRINK_DELAY = 3;
  11395.  
  11396. function getSentBoat()
  11397. {
  11398. for (var i = 0; i < BOAT_LIST.length; i++)
  11399. {
  11400. if (getGameValue(BOAT_LIST[i] + 'Timer') > 0)
  11401. {
  11402. return BOAT_LIST[i];
  11403. }
  11404. }
  11405. return null;
  11406. }
  11407.  
  11408. function checkBoat(boat)
  11409. {
  11410. var boatDialog = null;
  11411. var sendBtn = null;
  11412. var initiatedDialogs = document.querySelectorAll('div[role="dialog"]');
  11413. for (var i = 0; i < initiatedDialogs.length; i++)
  11414. {
  11415. var dialog = initiatedDialogs[i];
  11416. if (dialog.style.display !== 'none')
  11417. {
  11418. var btn = dialog.querySelector('input[type="button"][value="Send Boat"]');
  11419. if (btn)
  11420. {
  11421. sendBtn = btn;
  11422. boatDialog = dialog;
  11423. break;
  11424. }
  11425. }
  11426. }
  11427. if (!boatDialog || !sendBtn)
  11428. {
  11429. return;
  11430. }
  11431. var smallboxes = boatDialog.querySelectorAll('div.basic-smallbox');
  11432. var baitBox = smallboxes[0];
  11433. var runningBox = smallboxes[1];
  11434. if (smallboxes.length === 1)
  11435. {
  11436. runningBox = document.createElement('div');
  11437. runningBox.className = 'basic-smallbox';
  11438. runningBox.style.display = 'none';
  11439. var parent_1 = baitBox.parentElement;
  11440. var next = baitBox.nextElementSibling;
  11441. if (parent_1)
  11442. {
  11443. if (next)
  11444. {
  11445. parent_1.insertBefore(runningBox, next);
  11446. }
  11447. else
  11448. {
  11449. parent_1.appendChild(runningBox);
  11450. }
  11451. }
  11452. }
  11453. var sentBoat = getSentBoat();
  11454. baitBox.style.display = sentBoat !== null ? 'none' : '';
  11455. runningBox.style.display = sentBoat !== null ? '' : 'none';
  11456. // just in case Smitty changes this game mechanic somehow, don't disable the button:
  11457. // sendBtn.disabled = sentBoat !== null;
  11458.  
  11459. sendBtn.style.color = sentBoat !== null ? 'gray' : '';
  11460. win.$(boatDialog).on('dialogclose', function ()
  11461. {
  11462. if (sendBtn)
  11463. {
  11464. sendBtn.style.color = '';
  11465. }
  11466. });
  11467. if (sentBoat === boat)
  11468. {
  11469. runningBox.innerHTML = "<b>Returning in:</b> <span data-item-display=\"" + boat + "Timer\">" + format.timer(getGameValue(boat + 'Timer')) + "</span>";
  11470. }
  11471.  
  11472. else if (sentBoat !== null)
  11473. {
  11474. runningBox.innerHTML = "Wait for the other boat to return.";
  11475. }
  11476.  
  11477. else
  11478. {
  11479. var enoughBaitAndCoal = win.fishingBait >= win.fishingBaitCost(boat)
  11480. && (boat !== 'steamBoat' || win.charcoal >= 300);
  11481. baitBox.style.color = enoughBaitAndCoal ? '' : 'red';
  11482. }
  11483.  
  11484. }
  11485.  
  11486. function initBoatDialog()
  11487. {
  11488. var _clicksBoat = win.clicksBoat;
  11489. win.clicksBoat = function (boat)
  11490. {
  11491. _clicksBoat(boat);
  11492. checkBoat(boat);
  11493. };
  11494. var _doCommand = win.doCommand;
  11495. win.doCommand = function (data)
  11496. {
  11497. _doCommand(data);
  11498. if (data.startsWith('RUN_FUNC=SAIL_BOAT_WIND'))
  11499. {
  11500. checkBoat('sailBoat');
  11501. }
  11502. };
  11503. }
  11504. var potionDrinkEnable = null;
  11505. var POTION_ACTIVE_HTML = "<br>It's already active.";
  11506. function updateDialogEls(timerKey, dialog, close)
  11507. {
  11508. if (close === void 0)
  11509. {
  11510. close = false;
  11511. }
  11512. var timer = getGameValue(timerKey);
  11513. var showActive = settings.get(settings.KEY.usePotionWarning) && timer > 0 && !close;
  11514. var confirmText = document.getElementById('dialogue-confirm-text');
  11515. var br = confirmText && confirmText.nextElementSibling;
  11516. if (confirmText && br)
  11517. {
  11518. if (showActive)
  11519. {
  11520. confirmText.innerHTML += POTION_ACTIVE_HTML;
  11521. }
  11522. else
  11523. {
  11524. confirmText.innerHTML = confirmText.innerHTML.replace(POTION_ACTIVE_HTML, '');
  11525. }
  11526. br.style.display = showActive ? 'none' : '';
  11527. }
  11528. var confirmBtn = document.getElementById('dialogue-confirm-yes');
  11529. if (confirmBtn && showActive)
  11530. {
  11531. confirmBtn.disabled = true;
  11532. var i_1 = DRINK_DELAY;
  11533. var updateValue_1 = function ()
  11534. {
  11535. confirmBtn.value = 'Drink' + (i_1 > 0 ? ' (' + i_1 + ')' : '');
  11536. if (i_1 === 0)
  11537. {
  11538. potionDrinkEnable && potionDrinkEnable();
  11539. }
  11540. else
  11541. {
  11542. i_1--;
  11543. }
  11544. };
  11545. var countDownInterval_1;
  11546. var dialogClose_1 = function ()
  11547. {
  11548. return potionDrinkEnable && potionDrinkEnable();
  11549. };
  11550. potionDrinkEnable = function ()
  11551. {
  11552. potionDrinkEnable = null;
  11553. win.$(dialog).off('dialogclose', dialogClose_1);
  11554. countDownInterval_1 && clearInterval(countDownInterval_1);
  11555. confirmBtn.disabled = false;
  11556. confirmBtn.value = 'Drink';
  11557. };
  11558. updateValue_1();
  11559. countDownInterval_1 = setInterval(function ()
  11560. {
  11561. return updateValue_1();
  11562. }, 1e3);
  11563. win.$(dialog).on('dialogclose', dialogClose_1);
  11564. }
  11565. else if (!showActive)
  11566. {
  11567. potionDrinkEnable && potionDrinkEnable();
  11568. }
  11569. }
  11570.  
  11571. function checkPotionActive(potion)
  11572. {
  11573. var dialog = document.getElementById('dialogue-confirm');
  11574. var parent = dialog && dialog.parentElement;
  11575. if (!dialog || !parent || parent.style.display === 'none')
  11576. {
  11577. return;
  11578. }
  11579. var timerKey = potion + 'Timer';
  11580. updateDialogEls(timerKey, dialog);
  11581. var fn = observer.add(timerKey, function (key, oldValue, newValue)
  11582. {
  11583. if (oldValue < newValue && oldValue === 0
  11584. || oldValue > newValue && newValue === 0)
  11585. {
  11586. updateDialogEls(timerKey, dialog);
  11587. }
  11588. });
  11589. win.$(dialog).on('dialogclose', function ()
  11590. {
  11591. updateDialogEls(timerKey, dialog, true);
  11592. observer.remove(timerKey, fn);
  11593. });
  11594. }
  11595.  
  11596. function initPotionDialog()
  11597. {
  11598. var _confirmDialogue = win.confirmDialogue;
  11599. win.confirmDialogue = function (width, text, btn1Text, btn2Text, cmd)
  11600. {
  11601. potionDrinkEnable && potionDrinkEnable();
  11602. _confirmDialogue(width, text, btn1Text, btn2Text, cmd);
  11603. };
  11604. var _clicksPotion = win.clicksPotion;
  11605. win.clicksPotion = function (potion)
  11606. {
  11607. _clicksPotion(potion);
  11608. checkPotionActive(potion);
  11609. };
  11610. }
  11611. function init()
  11612. {
  11613. //initBoatDialog();
  11614. initPotionDialog();
  11615. }
  11616. general.init = init;
  11617. })(general || (general = {}));
  11618.  
  11619. /**
  11620. * init
  11621. */
  11622. var scriptInitialized = false;
  11623.  
  11624. function init()
  11625. {
  11626. console.info('[%s] "DH2 Fixed %s" up and running.', (new Date).toLocaleTimeString(), version);
  11627.  
  11628. scriptInitialized = true;
  11629. var initModules = [
  11630. settings
  11631. , notifications
  11632. , log
  11633. , gameEvents
  11634. , temporaryFixes
  11635. , crafting
  11636. , itemBoxes
  11637. , chat
  11638. , timer
  11639. , smelting
  11640. , fishingInfo
  11641. //, recipeTooltips
  11642. //, fixNumbers
  11643. , machineDialog
  11644. , amountInputs
  11645. , newTopbar
  11646. , styleTweaks
  11647. , notifBoxes
  11648. , market
  11649. , combat
  11650. , farming
  11651. , general
  11652. , calc
  11653. ];
  11654. for (var _i = 0, initModules_1 = initModules; _i < initModules_1.length; _i++)
  11655. {
  11656. var module = initModules_1[_i];
  11657. try
  11658. {
  11659. module.init();
  11660. }
  11661. catch (error)
  11662. {
  11663. console.error('Error during initialization in module "' + module.name + '":', error);
  11664. }
  11665. }
  11666. }
  11667. document.addEventListener('DOMContentLoaded', function ()
  11668. {
  11669. var oldValues = new Map();
  11670. var _doCommand = win.doCommand;
  11671. win.doCommand = function (data)
  11672. {
  11673. if (data.startsWith('REFRESH_ITEMS='))
  11674. {
  11675. oldValues = new Map();
  11676. for (var _i = 0, _a = win.jsItemArray; _i < _a.length; _i++)
  11677. {
  11678. var key = _a[_i];
  11679. oldValues.set(key, getGameValue(key));
  11680. }
  11681. _doCommand(data);
  11682. if (!scriptInitialized)
  11683. {
  11684. init();
  11685. }
  11686. return;
  11687. }
  11688. else if (!scriptInitialized)
  11689. {
  11690. if (data.startsWith('CHAT='))
  11691. {
  11692. var parts = data.substr(5).split('~');
  11693. return chat.newAddToChatBox(parts[0], parts[1], parts[2], parts[3], 0);
  11694. }
  11695. else if (data.startsWith('PM='))
  11696. {
  11697. return chat.newAddToChatBox(win.username, '0', '0', data.substr(3), 1);
  11698. }
  11699. }
  11700. var ret = commands.process(data);
  11701. if (ret === void 0)
  11702. {
  11703. ret = _doCommand(commands.formatData(data));
  11704. }
  11705. return ret;
  11706. };
  11707. var _refreshItemValues = win.refreshItemValues;
  11708. win.refreshItemValues = function (itemKeyList, firstLoad)
  11709. {
  11710. _refreshItemValues(itemKeyList, firstLoad);
  11711. for (var _i = 0, itemKeyList_2 = itemKeyList; _i < itemKeyList_2.length; _i++)
  11712. {
  11713. var key = itemKeyList_2[_i];
  11714. observer.notify(key, oldValues.get(key));
  11715. }
  11716. observer.notifyTick();
  11717. };
  11718. });
  11719.  
  11720. /**
  11721. * fix web socket errors
  11722. */
  11723. var main;
  11724. (function (main)
  11725. {
  11726. var WS_TIMEOUT_SEC = 30;
  11727. var WS_TIMEOUT_CODE = 3000;
  11728. var WS_OPEN_TIMEOUT_SEC = 2 * 60; // 2 minutes
  11729. // reload the page after 5 consecutive reconnect attempts without successfully opening the websocket once
  11730. var MAX_RECONNECTS = 5;
  11731.  
  11732. function webSocketLoaded(event)
  11733. {
  11734. if (win.webSocket == null)
  11735. {
  11736. //console.error('WebSocket instance not initialized!');
  11737. return;
  11738. }
  11739. // cache old event listener
  11740. var _onClose = win.webSocket.onclose;
  11741. var _onError = win.webSocket.onerror;
  11742. var _onMessage = win.webSocket.onmessage;
  11743. var _onOpen = win.webSocket.onopen;
  11744. var commandQueue = [];
  11745. var _cBytes = win.cBytes;
  11746. win.cBytes = function (command)
  11747. {
  11748. if (win.webSocket && win.webSocket.readyState === WebSocket.OPEN)
  11749. {
  11750. _cBytes(command);
  11751. }
  11752. else
  11753. {
  11754. commandQueue.push(command);
  11755. }
  11756. };
  11757. var pageLoaded = false;
  11758. var wsTimeout = null;
  11759. var reconnectAttempts = 0;
  11760.  
  11761. function onTimeout()
  11762. {
  11763. wsTimeout = null;
  11764. // renew the websocket
  11765. if (reconnectAttempts <= MAX_RECONNECTS)
  11766. {
  11767. win.webSocket = new WebSocket(win.SSL_ENABLED);
  11768. win.ignoreBytesTracker = Date.now();
  11769. initWSListener(win.webSocket);
  11770. reconnectAttempts++;
  11771. }
  11772. if (win.webSocket)
  11773. {
  11774. win.webSocket.close(WS_TIMEOUT_CODE, 'Connection timed out after ' + WS_TIMEOUT_SEC + ' seconds');
  11775. }
  11776. }
  11777.  
  11778. function updateWSTimeout()
  11779. {
  11780. if (wsTimeout)
  11781. {
  11782. win.clearTimeout(wsTimeout);
  11783. }
  11784. wsTimeout = win.setTimeout(onTimeout, WS_TIMEOUT_SEC * 1e3);
  11785. }
  11786. var messageQueue = [];
  11787.  
  11788. function onMessage(event)
  11789. {
  11790. if (pageLoaded)
  11791. {
  11792. updateWSTimeout();
  11793. return _onMessage.call(this, event);
  11794. }
  11795. else
  11796. {
  11797. messageQueue.push(event);
  11798. }
  11799. };
  11800. var wsOpenTimeout = null;
  11801.  
  11802. function onOpenTimeout()
  11803. {
  11804. wsOpenTimeout = null;
  11805. location.reload();
  11806. }
  11807.  
  11808. function onOpen(event)
  11809. {
  11810. reconnectAttempts = 0;
  11811. if (wsOpenTimeout)
  11812. {
  11813. win.clearTimeout(wsOpenTimeout);
  11814. wsOpenTimeout = null;
  11815. }
  11816. // do the handshake first
  11817. _onOpen.call(this, event);
  11818. commandQueue.forEach(function (command)
  11819. {
  11820. return win.cBytes(command);
  11821. });
  11822. }
  11823.  
  11824. function onError(event)
  11825. {
  11826. console.error('error in websocket:', event);
  11827. return _onError.call(this, event);
  11828. }
  11829.  
  11830. function onClose(event)
  11831. {
  11832. console.info('websocket closed:', event);
  11833. if (event.code !== WS_TIMEOUT_CODE || reconnectAttempts > MAX_RECONNECTS)
  11834. {
  11835. location.reload();
  11836. }
  11837. return _onClose.call(this, event);
  11838. }
  11839.  
  11840. function initWSListener(ws)
  11841. {
  11842. if (ws.readyState === WebSocket.CONNECTING)
  11843. {
  11844. wsOpenTimeout = win.setTimeout(onOpenTimeout, WS_OPEN_TIMEOUT_SEC * 1e3);
  11845. }
  11846. ws.onclose = onClose;
  11847. ws.onerror = onError;
  11848. ws.onmessage = onMessage;
  11849. ws.onopen = onOpen;
  11850. }
  11851. initWSListener(win.webSocket);
  11852. document.addEventListener('DOMContentLoaded', function ()
  11853. {
  11854. pageLoaded = true;
  11855. messageQueue.forEach(function (event)
  11856. {
  11857. return win.webSocket.onmessage(event);
  11858. });
  11859. });
  11860. }
  11861.  
  11862. function isScriptElement(el)
  11863. {
  11864. return el.nodeName === 'SCRIPT';
  11865. }
  11866.  
  11867. function isWebSocketScript(script)
  11868. {
  11869. return script.src.includes('socket.js');
  11870. }
  11871. var found = false;
  11872. if (document.head)
  11873. {
  11874. var scripts = document.head.querySelectorAll('script');
  11875. for (var i = 0; i < scripts.length; i++)
  11876. {
  11877. if (isWebSocketScript(scripts[i]))
  11878. {
  11879. // does this work?
  11880. scripts[i].onload = webSocketLoaded;
  11881. found = true;
  11882. }
  11883. }
  11884. }
  11885. if (!found)
  11886. {
  11887. // create an observer instance
  11888. var mutationObserver_1 = new MutationObserver(function (mutationList)
  11889. {
  11890. mutationList.forEach(function (mutation)
  11891. {
  11892. if (mutation.addedNodes.length === 0)
  11893. {
  11894. return;
  11895. }
  11896. for (var i = 0; i < mutation.addedNodes.length; i++)
  11897. {
  11898. var node = mutation.addedNodes[i];
  11899. if (isScriptElement(node) && isWebSocketScript(node))
  11900. {
  11901. mutationObserver_1.disconnect();
  11902. node.onload = webSocketLoaded;
  11903. return;
  11904. }
  11905. }
  11906. });
  11907. });
  11908. mutationObserver_1.observe(document.head
  11909. , {
  11910. childList: true
  11911. });
  11912. }
  11913. // fix scrollText (e.g. when joining the game and receiving xp at that moment)
  11914. win.mouseX = win.innerWidth / 2;
  11915. win.mouseY = win.innerHeight / 2;
  11916. var _confirm = win.confirm;
  11917. win.confirm = function (message)
  11918. {
  11919. // don't show the annoying update confirm box (instead of a confirm box, an ingame dialog could be used...)
  11920. if (message && message.indexOf('Ted\'s Market Script') !== -1)
  11921. {
  11922. return false;
  11923. }
  11924. return _confirm(message);
  11925. };
  11926. })(main || (main = {}));
  11927.  
  11928. })();