DH2 Fixed's temporary fixed

Improve Diamond Hunt 2's DH2 Fixed

  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.21
  6. // @author Zorbing
  7. // @license ISC; http://opensource.org/licenses/ISC
  8. // @grant none
  9. // @run-at document-start
  10. // @include *.diamondhunt.co/*
  11. // @match https://www.diamondhunt.co
  12.  
  13.  
  14. // Total errors: 352
  15. // To-do list:
  16. // add xp and stats into table loot mobs
  17. // option to disable calc color
  18. // hide button/drop down
  19.  
  20. // ==/UserScript==
  21. /*jshint multistr: true */
  22. /*jslint es5: true */
  23. // This is a continue developing script from Zorbing's since he has been inactive for a long time, with help from other players
  24. /**
  25. * ISC License (ISC)
  26. *
  27. * Copyright (c) 2017, Martin Boekhoff
  28. *
  29. * Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby
  30. * granted, provided that the above copyright notice and this permission notice appear in all copies.
  31. *
  32. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  33. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  34. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  35. * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  36. * PERFORMANCE OF THIS SOFTWARE.
  37. *
  38. * Source: http://opensource.org/licenses/ISC
  39. */
  40.  
  41. // main script
  42. (function ()
  43. {
  44. 'use strict';
  45. var version = '0.246.2';
  46. var buildTime = new Date('2017-08-12T16:37:11.942Z');
  47. var win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;
  48.  
  49.  
  50. /**
  51. * observer
  52. */
  53. var observer;
  54. (function (observer)
  55. {
  56. observer.GAME_TICK_KEY = 'dh2.gameTick';
  57. var observedKeys = new Map();
  58.  
  59. function add(key, fn)
  60. {
  61. if (key instanceof Array)
  62. {
  63. for (var _i = 0, key_1 = key; _i < key_1.length; _i++)
  64. {
  65. var k = key_1[_i];
  66. add(k, fn);
  67. }
  68. }
  69. else
  70. {
  71. if (!observedKeys.has(key))
  72. {
  73. observedKeys.set(key, new Set());
  74. }
  75. observedKeys.get(key).add(fn);
  76. }
  77. return fn;
  78. }
  79.  
  80. observer.add = add;
  81.  
  82. function notify(key, oldValue)
  83. {
  84. var newValue = getGameValue(key);
  85. if (observedKeys.has(key))
  86. {
  87. observedKeys.get(key).forEach(function (fn)
  88. {
  89. return fn(key, oldValue, newValue);
  90. });
  91. }
  92. }
  93. observer.notify = notify;
  94.  
  95. function notifyTick()
  96. {
  97. notify(observer.GAME_TICK_KEY, Math.floor(now() / 1000));
  98. }
  99. observer.notifyTick = notifyTick;
  100.  
  101. function remove(key, fn)
  102. {
  103. if (key instanceof Array)
  104. {
  105. var ret = [];
  106. for (var _i = 0, key_2 = key; _i < key_2.length; _i++)
  107. {
  108. var k = key_2[_i];
  109. ret.push(remove(k, fn));
  110. }
  111. return ret;
  112. }
  113. if (!observedKeys.has(key))
  114. {
  115. return false;
  116. }
  117. return observedKeys.get(key).delete(fn);
  118. }
  119. observer.remove = remove;
  120.  
  121. function addTick(fn)
  122. {
  123. return add(observer.GAME_TICK_KEY, fn);
  124. }
  125. observer.addTick = addTick;
  126.  
  127. function removeTick(fn)
  128. {
  129. return remove(observer.GAME_TICK_KEY, fn);
  130. }
  131. observer.removeTick = removeTick;
  132. })(observer || (observer = {}));
  133. /**
  134. * global constants
  135. */
  136. var PLUS_MINUS_SIGN = String.fromCharCode(177);
  137. var TIER_LEVELS = ['empty', 'sapphire', 'emerald', 'ruby', 'diamond'];
  138. var TIER_NAMES = ['Standard', 'Sapphire', 'Emerald', 'Ruby', 'Diamond'];
  139. var TIER_ITEMS = ['pickaxe', 'shovel', 'hammer', 'axe', 'rake', 'trowel', 'fishingRod', 'chisel'];
  140. var ORB_ITEMS = ['pickaxe', 'shovel', 'hammer', 'axe', 'rake', 'trowel', 'fishingRod', 'chisel', 'oilPipe'];
  141. var TIER_ITEMS_NOT_BINDABLE = ['rake', 'trowel'];
  142. var FURNACE_LEVELS = ['stone', 'bronze', 'iron', 'silver', 'gold', 'promethium', 'runite'];
  143. var OVEN_LEVELS = ['bronze', 'iron', 'silver', 'gold', 'promethium', 'runite'];
  144. var WAND_LEVELS = ['wooden', 'oak', 'willow', 'maple', 'stardust', 'strange', 'ancient'];
  145. var OIL_STORAGE_SIZES = [10e3, 50e3, 100e3, 300e3, 600e3, 2e6];
  146. var RECIPE_MAX = {
  147. 'brewing':
  148. {
  149. 'braveryPotion':
  150. {
  151. max: 1
  152. }
  153. , 'stardustCrystalPotion':
  154. {
  155. max: 1
  156. }
  157. }
  158. , 'cooksBook':
  159. {}
  160. , 'crafting':
  161. {
  162. 'drills':
  163. {
  164. max: 10
  165. }
  166. , 'crushers':
  167. {
  168. max: 10
  169. }
  170. , 'giantDrills':
  171. {
  172. max: 10
  173. }
  174. , 'excavators':
  175. {
  176. max: 10
  177. }
  178. , 'oilPipe':
  179. {
  180. max: 1
  181. }
  182. , 'pumpjacks':
  183. {
  184. max: 10
  185. }
  186. , 'rowBoat':
  187. {
  188. max: 1
  189. }
  190. , 'canoe':
  191. {
  192. max: 1
  193. }
  194. , 'sailBoat':
  195. {
  196. max: 1
  197. }
  198. , 'steamBoat':
  199. {
  200. max: 1
  201. }
  202. // thanks aguyd
  203. , 'bonemealBin':
  204. {
  205. extraKeys: ['boundFilledBonemealBin']
  206. , max: 1
  207. }
  208. , 'oilFactory':
  209. {
  210. max: 1
  211. }
  212. , 'brewingKit':
  213. {
  214. max: 1
  215. }
  216. , 'rocket':
  217. {
  218. max: 1
  219. }
  220. }
  221. , 'magic':
  222. {}
  223. };
  224. var SMELTING_REQUIREMENTS = {
  225. 'glass':
  226. {
  227. sand: 1
  228. , oil: 10
  229. }
  230. , 'bronzeBar':
  231. {
  232. copper: 1
  233. , tin: 1
  234. , oil: 10
  235. }
  236. , 'ironBar':
  237. {
  238. iron: 1
  239. , oil: 100
  240. }
  241. , 'silverBar':
  242. {
  243. silver: 1
  244. , oil: 300
  245. }
  246. , 'goldBar':
  247. {
  248. gold: 1
  249. , oil: 1e3
  250. }
  251. , 'promethiumBar':
  252. {
  253. promethium: 1
  254. , charcoal: 1
  255. }
  256. };
  257. var PLANT_NAME = {
  258. '1': 'Dark Mushrooms'
  259. , '2': 'Red Mushrooms'
  260. , '3': 'Dotted Green Leaves'
  261. , '4': 'Green Leaves'
  262. , '5': 'Lime Leaves'
  263. , '6': 'Gold Leaves'
  264. , '7': 'Striped Gold Leaves'
  265. , '8': 'Crystal Leaves'
  266. , '9': 'Striped Crystal Leaves'
  267. , '10': 'Blewit Mushrooms'
  268. , '11': 'Snapegrass'
  269. , '12': 'Tree'
  270. , '13': 'Oak Tree'
  271. , '14': 'Wheat'
  272. , '15': 'Willow Tree'
  273. , '16': 'Grass'
  274. , '17': 'Maple Tree'
  275. , '18': 'Stardust Tree'
  276. , '19': 'Carrots'
  277. , '20': 'Tomatoes'
  278. , '21': 'Potatoes'
  279. , '22': 'Strange Leaf Tree'
  280. , '23': 'Light Mushrooms'
  281. , '24': 'Pumpkins'
  282. , '25': 'Ancient Tree'
  283. , '26': 'Stardust Plant'
  284. , '27': 'White Leaf'
  285. , '28': 'Dark Leaf'
  286. , '29': 'Dark Mushrooms'
  287. , '30': 'Redwood Tree'
  288. , '31': 'Fire Wheat'
  289. , '32': 'Frozen Wheat'
  290. };
  291. var SKILL_LIST = ['mining', 'crafting', 'woodcutting', 'farming', 'brewing', 'combat', 'fishing', 'cooking', 'magic'];
  292. var AREA_LIST = ['fields', 'forests', 'caves', 'volcano', 'northFields', 'hauntedMansion'];
  293. var AREA_NAMES = ['Fields', 'Forests', 'Caves', 'Volcano', 'Northern Fields', 'Haunted Mansion', 'Moon', 'Dark Forest', 'Near Faradox\'s Castle'];
  294.  
  295. function getAreaName(areaId)
  296. {
  297. if (areaId === 33)
  298. {
  299. return 'Quest';
  300. }
  301. else if (areaId === 34)
  302. {
  303. return "Faradox's Tombs";
  304. }
  305. else if (areaId === 35)
  306. {
  307. return "Goblin Hideout";
  308. }
  309. else if (areaId === 36)
  310. {
  311. return "Dark Faradox's Tombs";
  312. }
  313. else if (areaId === 38)
  314. {
  315. return "Lava's Pond";
  316. }
  317. else if (areaId === 39)
  318. {
  319. return "Cold Lake";
  320. }
  321. else
  322. {
  323. return AREA_NAMES[areaId];
  324. }
  325. }
  326. 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', 'Dragon', 'Castle Golem', 'Triplet'];
  327.  
  328. function getMonsterName(monsterId)
  329. {
  330. if (monsterId === 101)
  331. {
  332. return 'Ghostly Old Mage';
  333. }
  334. else if (monsterId === 99)
  335. {
  336. return 'Evil Snake';
  337. }
  338. else if (monsterId === 100)
  339. {
  340. return 'Easter Bunny';
  341. }
  342. else if (monsterId === 102)
  343. {
  344. return '1st Tomb Monster';
  345. }
  346. else if (monsterId === 103)
  347. {
  348. return '2nd Tomb Monster';
  349. }
  350. else if (monsterId === 104)
  351. {
  352. return '3rd Tomb Monster';
  353. }
  354. else if (monsterId === 105)
  355. {
  356. return '4th Tomb Monster';
  357. }
  358. else if (monsterId === 106)
  359. {
  360. return '5th Tomb Monster';
  361. }
  362. else if (monsterId === 107)
  363. {
  364. return 'Gem Goblin';
  365. }
  366. else if (monsterId === 108)
  367. {
  368. return 'Skeleton Trainer';
  369. }
  370. else if (monsterId === 109)
  371. {
  372. return 'Faradox\'s Guardian';
  373. }
  374. else if (monsterId === 110)
  375. {
  376. return '1st Dark Tomb Monster';
  377. }
  378. else if (monsterId === 111)
  379. {
  380. return '2nd Dark Tomb Monster';
  381. }
  382. else if (monsterId === 112)
  383. {
  384. return '3rd Dark Tomb Monster';
  385. }
  386. else if (monsterId === 113)
  387. {
  388. return '4th Dark Tomb Monster';
  389. }
  390. else if (monsterId === 114)
  391. {
  392. return '5th Dark Tomb Monster';
  393. }
  394. else if (monsterId === 115)
  395. {
  396. return 'White Wizard';
  397. }
  398. else if (monsterId === 116)
  399. {
  400. return 'Fire Wheat';
  401. }
  402. else if (monsterId === 117)
  403. {
  404. return 'Frozen Wheat';
  405. }
  406. else
  407. {
  408. return MONSTER_NAMES[monsterId];
  409. }
  410. }
  411. var FISH_XP = {
  412. 'rawShrimp': 50
  413. , 'rawSardine': 500
  414. , 'rawSalmon': 700
  415. , 'rawTuna': 3e3
  416. , 'rawLobster': 5e3
  417. , 'rawSwordfish': 5e3
  418. , 'rawEel': 6e3
  419. , 'rawShark': 12e3
  420. , 'rawWhale': 20e3
  421. , 'rawRainbowFish': 30e3
  422. };
  423. var BOAT_LIST = ['rowBoat', 'canoe', 'sailBoat', 'steamBoat'];
  424. var TRIP_DURATION = {
  425. 'rowBoat': 3
  426. , 'canoe': 5
  427. , 'sailBoat': 7
  428. , 'steamBoat': 10
  429. };
  430. var MAX_ROCKET_MOON_KM = 384400;
  431. var MAX_ROCKET_MARS_KM = 54600000;
  432. var MAX_ROCKET_INTERSTELLAR_KM = 15000000000;
  433. var format;
  434. (function (format)
  435. {
  436. var UNITS = [
  437. {
  438. threshold: 10e3
  439. , factor: 1e3
  440. , token: 'k'
  441. }
  442. , {
  443. threshold: 1e6
  444. , factor: 1e6
  445. , token: 'M'
  446. }
  447. , {
  448. threshold: 1e9
  449. , factor: 1e9
  450. , token: 'B'
  451. }
  452. , {
  453. threshold: 1e12
  454. , factor: 1e12
  455. , token: 'T'
  456. }
  457. , {
  458. threshold: 1e15
  459. , factor: 1e15
  460. , token: 'Q'
  461. }];
  462. var TIME_STEPS = [
  463. {
  464. threshold: 1
  465. , name: 'second'
  466. , short: 'sec'
  467. , padp: 0
  468. }
  469. , {
  470. threshold: 60
  471. , name: 'minute'
  472. , short: 'min'
  473. , padp: 0
  474. }
  475. , {
  476. threshold: 3600
  477. , name: 'hour'
  478. , short: 'h'
  479. , padp: 1
  480. }
  481. , {
  482. threshold: 86400
  483. , name: 'day'
  484. , short: 'd'
  485. , padp: 2
  486. }];
  487.  
  488. function ensureNumber(num)
  489. {
  490. return (typeof num === 'number' ? num : Number(num));
  491. }
  492.  
  493. function number(num, shorten)
  494. {
  495. if (shorten === void 0)
  496. {
  497. shorten = false;
  498. }
  499. num = ensureNumber(num);
  500. if (shorten)
  501. {
  502. for (var i = UNITS.length - 1; i >= 0; i--)
  503. {
  504. var unit = UNITS[i];
  505. if (num >= unit.threshold)
  506. {
  507. return number(Math.round(num / unit.factor)) + unit.token;
  508. }
  509. }
  510. }
  511. return num.toLocaleString('en');
  512. }
  513. format.number = number;
  514.  
  515. function numbersInText(text)
  516. {
  517. return text.replace(/\d(?:[\d',\.]*\d)?/g, function (numStr)
  518. {
  519. return number(numStr.replace(/\D/g, ''));
  520. });
  521. }
  522. format.numbersInText = numbersInText;
  523. // use time format established in DHQoL (https://greasyfork.org/scripts/16041-dhqol)
  524. function timer(timer, shorten)
  525. {
  526. if (shorten === void 0)
  527. {
  528. shorten = true;
  529. }
  530. if (typeof timer === 'string')
  531. {
  532. timer = parseInt(timer, 10);
  533. }
  534. timer = Math.max(timer, 0);
  535. var days = Math.floor(timer / 86400); // 24 * 60 * 60
  536. var hours = Math.floor((timer % 86400) / 3600); // 60 * 60
  537. var minutes = Math.floor((timer % 3600) / 60);
  538. var seconds = timer % 60;
  539. return (shorten && days === 0 ? '' : days + 'd ')
  540. + (shorten && days === 0 && hours === 0 ? '' : zeroPadLeft(hours) + ':')
  541. + zeroPadLeft(minutes) + ':'
  542. + zeroPadLeft(seconds);
  543. }
  544. format.timer = timer;
  545.  
  546. function time2NearestUnit(time, long)
  547. {
  548. if (long === void 0)
  549. {
  550. long = false;
  551. }
  552. var step = TIME_STEPS[0];
  553. for (var i = TIME_STEPS.length - 1; i > 0; i--)
  554. {
  555. if (time >= TIME_STEPS[i].threshold)
  556. {
  557. step = TIME_STEPS[i];
  558. break;
  559. }
  560. }
  561. var factor = Math.pow(10, step.padp);
  562. var num = Math.round(time / step.threshold * factor) / factor;
  563. var unit = long ? step.name + (num === 1 ? '' : 's') : step.short;
  564. return num + ' ' + unit;
  565. }
  566. format.time2NearestUnit = time2NearestUnit;
  567.  
  568. function sec2Str(seconds)
  569. {
  570. seconds = Number(seconds);
  571. if (seconds < 0)
  572. {
  573. return seconds.toString();
  574. }
  575. var s = seconds % 60;
  576. var m = Math.floor(seconds / 60) % 60;
  577. var h = Math.floor(seconds / 3600);
  578. var strs = [];
  579. if (h > 0)
  580. {
  581. strs.push(h + ' hour' + (h == 1 ? '' : 's'));
  582. }
  583. if (m > 0)
  584. {
  585. strs.push(m + ' minute' + (m == 1 ? '' : 's'));
  586. }
  587. if (s > 0)
  588. {
  589. strs.push(s + ' second' + (s == 1 ? '' : 's'));
  590. }
  591. if (strs.length > 1)
  592. {
  593. var glue = ' and ';
  594. for (var i = strs.length - 2; i >= 0; i--)
  595. {
  596. strs[i] = strs[i] + glue + strs[i + 1];
  597. glue = ', ';
  598. }
  599. return strs[0];
  600. }
  601. else
  602. {
  603. return strs[0] || '';
  604. }
  605. }
  606. format.sec2Str = sec2Str;
  607.  
  608. function min2Str(minutes)
  609. {
  610. return sec2Str(Number(minutes) * 60);
  611. }
  612. format.min2Str = min2Str;
  613. })(format || (format = {}));
  614.  
  615. /**
  616. * general functions
  617. */
  618. function getStyle(elId)
  619. {
  620. var id = elId != null ? 'style-' + elId : null;
  621. var styleElement = id != null ? document.getElementById(id) : null;
  622. if (styleElement == null)
  623. {
  624. styleElement = document.createElement('style');
  625. if (id != null)
  626. {
  627. styleElement.id = id;
  628. }
  629. styleElement.type = 'text/css';
  630. document.head.appendChild(styleElement);
  631. }
  632. return styleElement;
  633. }
  634.  
  635. function addStyle(styleCode, elId)
  636. {
  637. var styleElement = getStyle(elId);
  638. styleElement.innerHTML += styleCode;
  639. }
  640.  
  641. function zeroPadLeft(num)
  642. {
  643. return (num < 10 ? '0' : '') + num;
  644. }
  645.  
  646. function capitalize(str)
  647. {
  648. return str[0].toUpperCase() + str.substr(1);
  649. }
  650.  
  651. function key2Name(key, lowerCase)
  652. {
  653. if (lowerCase === void 0)
  654. {
  655. lowerCase = false;
  656. }
  657. var name = key.replace(/[A-Z]/g, function (c)
  658. {
  659. return ' ' + (lowerCase ? c.toLowerCase() : c);
  660. });
  661. return lowerCase ? name : capitalize(name);
  662. }
  663.  
  664. function pluralize(name)
  665. {
  666. return name.replace(/([^aeiou])y$/, '$1ie').replace(/s?$/, '') + 's';
  667. }
  668.  
  669. function split2Words(str, char)
  670. {
  671. if (char === void 0)
  672. {
  673. char = ' ';
  674. }
  675. return str.replace(/[A-Z]/g, char + '$&');
  676. }
  677.  
  678. function getBoundKey(key)
  679. {
  680. return 'bound' + capitalize(key);
  681. }
  682.  
  683. function getTierKey(key, tierLevel)
  684. {
  685. return TIER_LEVELS[tierLevel] + capitalize(key);
  686. }
  687.  
  688. function getWikiaKey(key)
  689. {
  690. return key2Name(key.replace(/^bound-?|^special-case-/i, '').replace(/\d+[km]?$/i, ''))
  691. .replace(/^\s/, '').replace(/[ -]/g, '_')
  692. .replace(/^(?:Empty|Sapphire|Emerald|Ruby|Diamond|Raw|Uncooked|Filled)_/, '')
  693. .replace(/^(?:Bronze|Iron|Silver|Gold|Promethium|Runite)_(?!Bar)/, '')
  694. .replace(/^Npc_/, 'Monster_')
  695. .replace(/_(?:Unlocked|Quest)$/, '');
  696. }
  697.  
  698. function getWikiaLink(key)
  699. {
  700. return 'http://diamondhuntonline.wikia.com/wiki/' + getWikiaKey(key);
  701. }
  702.  
  703. function now()
  704. {
  705. return (new Date()).getTime();
  706. }
  707.  
  708. function ensureTooltip(id, target)
  709. {
  710. var tooltipId = 'tooltip-' + id;
  711. var tooltipEl = document.getElementById(tooltipId);
  712. if (!tooltipEl)
  713. {
  714. tooltipEl = document.createElement('div');
  715. tooltipEl.id = tooltipId;
  716. tooltipEl.style.display = 'none';
  717. var tooltipList = document.getElementById('tooltip-list');
  718. tooltipList.appendChild(tooltipEl);
  719. }
  720. // ensure binded events to show the tooltip
  721. if (target.dataset.tooltipId == null)
  722. {
  723. target.dataset.tooltipId = tooltipId;
  724. win.$(target).bind(
  725. {
  726. mousemove: win.changeTooltipPosition
  727. , mouseenter: win.showTooltip
  728. , mouseleave: function (event)
  729. {
  730. var target = event.target;
  731. var parent = target.parentElement;
  732. // ensure tooltips inside an tooltip element is possible
  733. if (!!target.dataset.tooltipId && parent && !!parent.dataset.tooltipId)
  734. {
  735. win.showTooltip.call(parent, event);
  736. }
  737. else
  738. {
  739. win.hideTooltip(event);
  740. }
  741. }
  742. });
  743. }
  744. return tooltipEl;
  745. }
  746. var timeStr2Sec = (function ()
  747. {
  748. var unitFactors = {
  749. 'd': 24 * 60 * 60
  750. , 'h': 60 * 60
  751. , 'm': 60
  752. , 's': 1
  753. };
  754. return function timeStr2Sec(str)
  755. {
  756. return str
  757. .replace(/(\d+)([hms])/g, function (wholeMatch, num, unit)
  758. {
  759. return parseInt(num) * (unitFactors[unit] || 1) + '+';
  760. })
  761. .split('+')
  762. .map(function (s)
  763. {
  764. return parseInt(s, 10);
  765. })
  766. .filter(function (n)
  767. {
  768. return !isNaN(n);
  769. })
  770. .reduce(function (p, c)
  771. {
  772. return p + c;
  773. }, 0);
  774. };
  775. })();
  776.  
  777. function getGameValue(key)
  778. {
  779. return win[key];
  780. }
  781.  
  782. function getFurnaceLevel()
  783. {
  784. for (var i = FURNACE_LEVELS.length - 1; i >= 0; i--)
  785. {
  786. if (getGameValue(getBoundKey(FURNACE_LEVELS[i] + 'Furnace')) > 0)
  787. {
  788. return i;
  789. }
  790. }
  791. return -1;
  792. }
  793.  
  794. function getFurnaceLevelName()
  795. {
  796. return FURNACE_LEVELS[getFurnaceLevel()] || '';
  797. }
  798.  
  799. function getPrice(item)
  800. {
  801. var price = win.getPrice(item);
  802. if (typeof price === 'number')
  803. {
  804. return price;
  805. }
  806. var match = price.match(/(\d+)([kM])/);
  807. if (!match)
  808. {
  809. return parseInt(price, 10);
  810. }
  811. var FACTORS = {
  812. 'k': 1e3
  813. , 'M': 1e6
  814. };
  815. return parseInt(match[1], 10) * (FACTORS[match[2]] || 1);
  816. }
  817.  
  818. function doGet(url)
  819. {
  820. return new Promise(function (resolve, reject)
  821. {
  822. var request = new XMLHttpRequest();
  823. request.onreadystatechange = function (event)
  824. {
  825. if (request.readyState != XMLHttpRequest.DONE)
  826. {
  827. return;
  828. }
  829. if (request.status != 200)
  830. {
  831. return reject(event);
  832. }
  833. resolve(request.responseText);
  834. };
  835. request.open('GET', url);
  836. request.send();
  837. });
  838. }
  839.  
  840. function removeWhitespaceChildNodes(el)
  841. {
  842. for (var i = 0; i < el.childNodes.length; i++)
  843. {
  844. var child = el.childNodes.item(i);
  845. if (child.nodeType === Node.TEXT_NODE && /^\s*$/.test(child.textContent || ''))
  846. {
  847. el.removeChild(child);
  848. i--;
  849. }
  850. }
  851. }
  852.  
  853. function debounce(func, wait, immediate)
  854. {
  855. var timeout;
  856. return function ()
  857. {
  858. var _this = this;
  859. var args = [];
  860. for (var _i = 0; _i < arguments.length; _i++)
  861. {
  862. args[_i] = arguments[_i];
  863. }
  864. var callNow = immediate && !timeout;
  865. timeout && clearTimeout(timeout);
  866. timeout = setTimeout(function ()
  867. {
  868. timeout = null;
  869. if (!immediate)
  870. {
  871. func.apply(_this, args);
  872. }
  873. }, wait);
  874. if (callNow)
  875. {
  876. func.apply(this, args);
  877. }
  878. };
  879. }
  880.  
  881. function passThis(fn)
  882. {
  883. return function ()
  884. {
  885. var args = [];
  886. for (var _i = 0; _i < arguments.length; _i++)
  887. {
  888. args[_i] = arguments[_i];
  889. }
  890. return fn.apply(void 0, [this].concat(args));
  891. };
  892. }
  893. /**
  894. * persistence store
  895. */
  896. var store;
  897. (function (store)
  898. {
  899. var oldPrefix = 'dh2-';
  900. var storePrefix = 'dh2.';
  901.  
  902. function update(key, keepOldValue)
  903. {
  904. if (keepOldValue === void 0)
  905. {
  906. keepOldValue = true;
  907. }
  908. if (localStorage.hasOwnProperty(oldPrefix + key))
  909. {
  910. if (keepOldValue)
  911. {
  912. localStorage.setItem(storePrefix + key, localStorage.getItem(oldPrefix + key));
  913. }
  914. localStorage.removeItem(oldPrefix + key);
  915. }
  916. }
  917. var changeListener = new Map();
  918.  
  919. function changeDetected(key, oldValue, newValue)
  920. {
  921. if (changeListener.has(key))
  922. {
  923. setTimeout(function ()
  924. {
  925. changeListener.get(key).forEach(function (fn)
  926. {
  927. return fn(key, oldValue, newValue);
  928. });
  929. });
  930. }
  931. }
  932.  
  933. function watchFn(fnName)
  934. {
  935. var _fn = localStorage[fnName];
  936. localStorage[fnName] = function (key)
  937. {
  938. var args = [];
  939. for (var _i = 1; _i < arguments.length; _i++)
  940. {
  941. args[_i - 1] = arguments[_i];
  942. }
  943. var oldValue = localStorage.getItem(key);
  944. _fn.apply(localStorage, [key].concat(args));
  945. var newValue = localStorage.getItem(key);
  946. if (oldValue !== newValue)
  947. {
  948. changeDetected(key, oldValue, newValue);
  949. }
  950. };
  951. }
  952. watchFn('setItem');
  953. watchFn('removeItem');
  954. var _clear = localStorage.clear;
  955. localStorage.clear = function ()
  956. {
  957. var oldValues = new Map();
  958. for (var i = 0; i < localStorage.length; i++)
  959. {
  960. var key = localStorage.key(i);
  961. oldValues.set(key, localStorage.getItem(key));
  962. }
  963. _clear();
  964. for (let key in oldValues)
  965. {
  966. var newValue = localStorage.getItem(key);
  967. if (oldValues.get(key) !== newValue)
  968. {
  969. changeDetected(key, oldValues.get(key), newValue);
  970. }
  971. }
  972. };
  973.  
  974. function addChangeListener(key, fn)
  975. {
  976. if (!changeListener.has(key))
  977. {
  978. changeListener.set(key, new Set());
  979. }
  980. changeListener.get(key).add(fn);
  981. }
  982. store.addChangeListener = addChangeListener;
  983.  
  984. function removeChangeListener(key, fn)
  985. {
  986. if (changeListener.has(key))
  987. {
  988. changeListener.get(key).delete(fn);
  989. }
  990. }
  991. store.removeChangeListener = removeChangeListener;
  992.  
  993. function get(key)
  994. {
  995. update(key);
  996. var value = localStorage.getItem(storePrefix + key);
  997. if (value != null)
  998. {
  999. try
  1000. {
  1001. return JSON.parse(value);
  1002. }
  1003. catch (e)
  1004. {}
  1005. }
  1006. return value;
  1007. }
  1008. store.get = get;
  1009.  
  1010. function has(key)
  1011. {
  1012. update(key);
  1013. return localStorage.hasOwnProperty(storePrefix + key);
  1014. }
  1015. store.has = has;
  1016.  
  1017. function remove(key)
  1018. {
  1019. update(key, false);
  1020. localStorage.removeItem(storePrefix + key);
  1021. }
  1022. store.remove = remove;
  1023.  
  1024. function set(key, value)
  1025. {
  1026. update(key, false);
  1027. localStorage.setItem(storePrefix + key, JSON.stringify(value));
  1028. }
  1029. store.set = set;
  1030. })(store || (store = {}));
  1031.  
  1032. var settings;
  1033. (function (settings)
  1034. {
  1035. settings.name = 'settings';
  1036. var DIALOG_WIDTH = 450;
  1037. var KEY;
  1038. (function (KEY)
  1039. {
  1040. KEY[KEY["hideCraftingRecipes"] = 0] = "hideCraftingRecipes";
  1041. KEY[KEY["hideUselessItems"] = 1] = "hideUselessItems";
  1042. KEY[KEY["useNewChat"] = 2] = "useNewChat";
  1043. KEY[KEY["colorizeChat"] = 3] = "colorizeChat";
  1044. KEY[KEY["intelligentScrolling"] = 4] = "intelligentScrolling";
  1045. KEY[KEY["showTimestamps"] = 5] = "showTimestamps";
  1046. KEY[KEY["showIcons"] = 6] = "showIcons";
  1047. KEY[KEY["showTags"] = 7] = "showTags";
  1048. KEY[KEY["enableSpamDetection"] = 8] = "enableSpamDetection";
  1049. KEY[KEY["useTombNotif"] = 9] = "useTombNotif";
  1050. KEY[KEY["useWorkerNotif"] = 10] = "useWorkerNotif";
  1051. KEY[KEY["useBobsUncleNotif"] = 11] = "useBobsUncleNotif";
  1052. KEY[KEY["showNotifications"] = 12] = "showNotifications";
  1053. KEY[KEY["wikiaLinks"] = 13] = "wikiaLinks";
  1054. KEY[KEY["newXpAnimation"] = 14] = "newXpAnimation";
  1055. KEY[KEY["amountSymbol"] = 15] = "amountSymbol";
  1056. KEY[KEY["showTabTimer"] = 16] = "showTabTimer";
  1057. KEY[KEY["showLootTab"] = 17] = "showLootTab";
  1058. KEY[KEY["useEfficiencyStyle"] = 18] = "useEfficiencyStyle";
  1059. KEY[KEY["makeNumberInputs"] = 19] = "makeNumberInputs";
  1060. KEY[KEY["addKeepInput"] = 20] = "addKeepInput";
  1061. KEY[KEY["addMaxBtn"] = 21] = "addMaxBtn";
  1062. KEY[KEY["highlightUnplantableSeed"] = 22] = "highlightUnplantableSeed";
  1063. KEY[KEY["showSdChange"] = 23] = "showSdChange";
  1064. KEY[KEY["usePotionWarning"] = 24] = "usePotionWarning";
  1065. KEY[KEY["showCaptions"] = 25] = "showCaptions";
  1066. KEY[KEY["syncPriceHistory"] = 26] = "syncPriceHistory";
  1067. KEY[KEY["useNewToolbar"] = 27] = "useNewToolbar";
  1068. KEY[KEY["changeMachineDialog"] = 28] = "changeMachineDialog";
  1069. KEY[KEY["skillBars"] = 29] = "skillBars";
  1070. })(KEY = settings.KEY || (settings.KEY = {}));;
  1071. var CFG = (_a = {}
  1072. , _a[KEY.hideCraftingRecipes] = {
  1073. name: 'Hide crafting recipes of finished items'
  1074. , 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>"
  1075. , defaultValue: true
  1076. }
  1077. , _a[KEY.hideUselessItems] = {
  1078. name: 'Hide useless items'
  1079. , 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>"
  1080. , defaultValue: false
  1081. }
  1082. , _a[KEY.useNewChat] = {
  1083. name: 'Use the new chat'
  1084. , 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"
  1085. , defaultValue: true
  1086. }
  1087. , _a[KEY.colorizeChat] = {
  1088. name: 'Colorize chat messages'
  1089. , description: "Colorize chat messages according to a unique color for each user"
  1090. , defaultValue: false
  1091. , sub:
  1092. {
  1093. 'colorizer':
  1094. {
  1095. defaultValue: 0
  1096. , label: ['Equally Distributed', 'Random (light colors)', 'Random (dark colors)']
  1097. , options: ['equallyDistributed', 'random1', 'random2']
  1098. }
  1099. }
  1100. }
  1101. , _a[KEY.intelligentScrolling] = {
  1102. name: 'Intelligent scrolling'
  1103. , 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."
  1104. , defaultValue: true
  1105. }
  1106. , _a[KEY.showTimestamps] = {
  1107. name: 'Show timestamps'
  1108. , description: "Enables showing timestamps in chat"
  1109. , defaultValue: true
  1110. }
  1111. , _a[KEY.showIcons] = {
  1112. name: 'Show user-icons'
  1113. , description: "Enables showing icons (formerly sigils) for each user in chat"
  1114. , defaultValue: true
  1115. }
  1116. , _a[KEY.showTags] = {
  1117. name: 'Show user-tags'
  1118. , description: "Enables showing tags (Dev, Mod, Contributor) and colors for messages in chat"
  1119. , defaultValue: true
  1120. }
  1121. , _a[KEY.enableSpamDetection] = {
  1122. name: 'Enable spam detection'
  1123. , description: "Enables simple spam detection"
  1124. , defaultValue: true
  1125. }
  1126. , _a[KEY.useTombNotif] = {
  1127. name: 'Use Tomb notification'
  1128. , description: "Shows notification when Faradox's tomb is ready to fight"
  1129. , defaultValue: false
  1130. }
  1131. , _a[KEY.useBobsUncleNotif] = {
  1132. name: 'Use Bobs uncle notification'
  1133. , description: "Shows notification when Bob's uncle farm is ready to harvest"
  1134. , defaultValue: true
  1135. }
  1136. , _a[KEY.showNotifications] = {
  1137. name: 'Show browser notifications'
  1138. , description: "Shows browser notifications for enabled events (click the little gear for more options)"
  1139. , defaultValue: true
  1140. , sub:
  1141. {
  1142. 'showType':
  1143. {
  1144. defaultValue: 0
  1145. , label: ['only when window inactive', 'always']
  1146. , options: ['whenInactive', 'always']
  1147. }
  1148. , 'smelting':
  1149. {
  1150. defaultValue: true
  1151. , label: 'Smelting finishes'
  1152. }
  1153. , 'chopping':
  1154. {
  1155. defaultValue: true
  1156. , label: 'A tree is fully grown'
  1157. }
  1158. , 'harvest':
  1159. {
  1160. defaultValue: true
  1161. , label: 'A plant can be harvested'
  1162. }
  1163. , 'potionEffect':
  1164. {
  1165. defaultValue: true
  1166. , label: 'A potion\'s effect ends'
  1167. }
  1168. , 'boatReturned':
  1169. {
  1170. defaultValue: true
  1171. , label: 'A boat returns'
  1172. }
  1173. , 'heroReady':
  1174. {
  1175. defaultValue: true
  1176. , label: 'The hero is fully recovered and ready to fight'
  1177. }
  1178. , 'itemsSold':
  1179. {
  1180. defaultValue: true
  1181. , label: 'Items are sold on the market'
  1182. }
  1183. , 'pirate':
  1184. {
  1185. defaultValue: true
  1186. , label: 'A pirate has found a treasure map'
  1187. }
  1188. , 'rocket':
  1189. {
  1190. defaultValue: true
  1191. , label: 'The rocket has landed on the moon or earth'
  1192. }
  1193. , 'wind':
  1194. {
  1195. defaultValue: true
  1196. , label: 'The wind for the sail boat has changed'
  1197. }
  1198. , 'perk':
  1199. {
  1200. defaultValue: true
  1201. , label: 'A new perk is unlocked (achievement set completed)'
  1202. }
  1203. , 'pm':
  1204. {
  1205. defaultValue: true
  1206. , label: 'A private messages (pm) arrives'
  1207. }
  1208. , 'mention':
  1209. {
  1210. defaultValue: true
  1211. , label: 'The username is mentioned in chat'
  1212. }
  1213. , 'keyword':
  1214. {
  1215. defaultValue: true
  1216. , label: 'A keyword is mentioned in chat'
  1217. }
  1218. , 'serverMsg':
  1219. {
  1220. defaultValue: true
  1221. , label: 'Server messages (like <em>Server is restarting...</em>)'
  1222. }
  1223. }
  1224. }
  1225. , _a[KEY.wikiaLinks] = {
  1226. name: 'Show wikia links'
  1227. , description: "Show wikia links for every item on hover (the little icon in the upper left corner)"
  1228. , defaultValue: true
  1229. }
  1230. , _a[KEY.newXpAnimation] = {
  1231. name: 'New XP-gain animation'
  1232. , description: "Show gained xp on top skill bar instead on the position of the mouse"
  1233. , defaultValue: true
  1234. }
  1235. , _a[KEY.amountSymbol] = {
  1236. name: 'Show \u00D7 on items'
  1237. , description: "Show a tiny \u00D7-symbol before amount numbers of items"
  1238. , defaultValue: true
  1239. }
  1240. , _a[KEY.showTabTimer] = {
  1241. name: 'Show tab timer and info'
  1242. , description: "Show timer on tabs for trees, plants and hero"
  1243. , defaultValue: true
  1244. }
  1245. , _a[KEY.showLootTab] = {
  1246. name: 'Show sub tab for loot table'
  1247. , description: "Show a sub tab for combat drop table in combat"
  1248. , defaultValue: true
  1249. }
  1250. , _a[KEY.useEfficiencyStyle] = {
  1251. name: 'Use space efficient style'
  1252. , description: "Use a space efficient style with less blank space"
  1253. , defaultValue: false
  1254. }
  1255. , _a[KEY.makeNumberInputs] = {
  1256. name: 'Turn text inputs into number inputs'
  1257. , description: "Number inputs allow you to change the amount via arrow buttons"
  1258. , defaultValue: true
  1259. }
  1260. , _a[KEY.addKeepInput] = {
  1261. name: 'Add keep input for selling to npc shop'
  1262. , description: "A keep input allows you to set the amount of items you want to keep when selling"
  1263. , defaultValue: true
  1264. }
  1265. , _a[KEY.addMaxBtn] = {
  1266. name: 'Add max button for some crafting inputs'
  1267. , description: "Add max button for crafting (e.g. vials), brewing potions and cooking food"
  1268. , defaultValue: true
  1269. }
  1270. , _a[KEY.highlightUnplantableSeed] = {
  1271. name: 'Show whether a seed can be planted'
  1272. , description: "Fades the item box of a seed when it's not plantable"
  1273. , defaultValue: true
  1274. }
  1275. , _a[KEY.showSdChange] = {
  1276. name: 'Show stardust change'
  1277. , description: "Shows the amount of stardust earned or spent in the last tick"
  1278. , defaultValue: true
  1279. }
  1280. , _a[KEY.usePotionWarning] = {
  1281. name: 'Use drink warning for active potions'
  1282. , description: "Disable drink button for 3 seconds if the potion is already active"
  1283. , defaultValue: true
  1284. }
  1285. , _a[KEY.showCaptions] = {
  1286. name: 'Show item captions'
  1287. , description: "Show item captions for some items instead of the number of owned items"
  1288. , defaultValue: true
  1289. }
  1290. , _a[KEY.syncPriceHistory] = {
  1291. name: 'Sync price history'
  1292. , description: "Synchronize the local price history"
  1293. , defaultValue: false
  1294. , sub:
  1295. {
  1296. 'url':
  1297. {
  1298. defaultValue: ''
  1299. , label: 'paste url here'
  1300. }
  1301. }
  1302. }
  1303. , _a[KEY.useNewToolbar] = {
  1304. name: 'Use new toolbar'
  1305. , description: "Use new reordered toolbar"
  1306. , defaultValue: true
  1307. , requiresReload: true
  1308. }
  1309. , _a[KEY.changeMachineDialog] = {
  1310. name: 'Use slider for machine dialog'
  1311. , description: "Change buttons in machine dialog into slider"
  1312. , defaultValue: true
  1313. , requiresReload: true
  1314. }
  1315. , _a[KEY.skillBars] = {
  1316. name: 'Show XP bars'
  1317. , description: "Show the XP bars under skills on top"
  1318. , defaultValue: true
  1319. , requiresReload: true
  1320. }
  1321. , _a);
  1322. var SETTINGS_TABLE_ID = 'dh2-settings';
  1323. var SETTING_ID_PREFIX = 'dh2-setting-';
  1324. var settings2Init = Object.keys(CFG);
  1325. /**
  1326. * settings
  1327. */
  1328. function toName(key, subKey)
  1329. {
  1330. var name = typeof key === 'string' ? key : KEY[key];
  1331. if (subKey !== undefined)
  1332. {
  1333. return name + '.' + subKey;
  1334. }
  1335. return name;
  1336. }
  1337.  
  1338. function getStoreKey(key, subKey)
  1339. {
  1340. return 'setting.' + toName(key, subKey);
  1341. }
  1342. var observedSettings = new Map();
  1343. var observedSubSettings = new Map();
  1344.  
  1345. function observe(key, fn)
  1346. {
  1347. var n = toName(key);
  1348. if (!observedSettings.has(n))
  1349. {
  1350. observedSettings.set(n, new Set());
  1351. }
  1352. observedSettings.get(n).add(fn);
  1353. }
  1354. settings.observe = observe;
  1355.  
  1356. function observeSub(key, subKey, fn)
  1357. {
  1358. var n = toName(key, subKey);
  1359. if (!observedSubSettings.has(n))
  1360. {
  1361. observedSubSettings.set(n, new Set());
  1362. }
  1363. observedSubSettings.get(n).add(fn);
  1364. }
  1365. settings.observeSub = observeSub;
  1366.  
  1367. function unobserve(key, fn)
  1368. {
  1369. var n = toName(key);
  1370. if (!observedSettings.has(n))
  1371. {
  1372. return false;
  1373. }
  1374. return observedSettings.get(n).delete(fn);
  1375. }
  1376. settings.unobserve = unobserve;
  1377.  
  1378. function unobserveSub(key, subKey, fn)
  1379. {
  1380. var n = toName(key, subKey);
  1381. if (!observedSubSettings.has(n))
  1382. {
  1383. return false;
  1384. }
  1385. return observedSubSettings.get(n).delete(fn);
  1386. }
  1387. settings.unobserveSub = unobserveSub;
  1388. var settingsProxies = new Map();
  1389.  
  1390. function get(key)
  1391. {
  1392. if (!CFG.hasOwnProperty(key))
  1393. {
  1394. return false;
  1395. }
  1396. if (settingsProxies.has(key))
  1397. {
  1398. var proxy = settingsProxies.get(key);
  1399. return proxy.get(key);
  1400. }
  1401. var name = getStoreKey(key);
  1402. return store.has(name) ? store.get(name) : CFG[key].defaultValue;
  1403. }
  1404. settings.get = get;
  1405.  
  1406. function getSub(key, subKey)
  1407. {
  1408. if (!CFG.hasOwnProperty(key))
  1409. {
  1410. return null;
  1411. }
  1412. var name = getStoreKey(key, subKey);
  1413. var def = CFG[key].sub[subKey].defaultValue;
  1414. if (store.has(name))
  1415. {
  1416. var stored = store.get(name);
  1417. if (def instanceof Array)
  1418. {
  1419. for (var i = 0; i < def.length; i++)
  1420. {
  1421. if (stored.indexOf(def[i]) === -1)
  1422. {
  1423. stored.push(def[i]);
  1424. }
  1425. }
  1426. for (let i = 0; i < stored.length; i++)
  1427. {
  1428. if (def.indexOf(stored[i]) === -1)
  1429. {
  1430. stored.splice(i, 1);
  1431. i--;
  1432. }
  1433. }
  1434. }
  1435. return stored;
  1436. }
  1437. else
  1438. {
  1439. return def;
  1440. }
  1441. }
  1442. settings.getSub = getSub;
  1443.  
  1444. function set(key, newValue)
  1445. {
  1446. if (!CFG.hasOwnProperty(key))
  1447. {
  1448. return;
  1449. }
  1450. var oldValue = get(key);
  1451. var n = toName(key);
  1452. if (settingsProxies.has(key))
  1453. {
  1454. var proxy = settingsProxies.get(key);
  1455. proxy.set(key, oldValue, newValue);
  1456. }
  1457. else
  1458. {
  1459. store.set(getStoreKey(key), newValue);
  1460. }
  1461. if (oldValue !== newValue && observedSettings.has(n))
  1462. {
  1463. observedSettings.get(n).forEach(function (fn)
  1464. {
  1465. return fn(key, oldValue, newValue);
  1466. });
  1467. }
  1468. }
  1469. settings.set = set;
  1470.  
  1471. function setSub(key, subKey, newValue)
  1472. {
  1473. if (!CFG.hasOwnProperty(key))
  1474. {
  1475. return;
  1476. }
  1477. var oldValue = getSub(key, subKey);
  1478. var n = toName(key, subKey);
  1479. store.set(getStoreKey(key, subKey), newValue);
  1480. if (oldValue !== newValue && observedSubSettings.has(n))
  1481. {
  1482. observedSubSettings.get(n).forEach(function (fn)
  1483. {
  1484. return fn(key, subKey, oldValue, newValue);
  1485. });
  1486. }
  1487. }
  1488. settings.setSub = setSub;
  1489.  
  1490. function getSubCfg(key)
  1491. {
  1492. if (!CFG.hasOwnProperty(key))
  1493. {
  1494. return;
  1495. }
  1496. return CFG[key].sub;
  1497. }
  1498. settings.getSubCfg = getSubCfg;
  1499.  
  1500. function initSettingsStyle()
  1501. {
  1502. 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");
  1503. }
  1504.  
  1505. function getSettingId(key, subKey)
  1506. {
  1507. var name = toName(key) + (subKey !== undefined ? '-' + subKey : '');
  1508. return SETTING_ID_PREFIX + split2Words(name, '-').toLowerCase();
  1509. }
  1510.  
  1511. function initSettingTable()
  1512. {
  1513. function insertAfter(newChild, oldChild)
  1514. {
  1515. var parent = oldChild.parentElement;
  1516. if (oldChild.nextElementSibling == null)
  1517. {
  1518. parent.appendChild(newChild);
  1519. }
  1520. else
  1521. {
  1522. parent.insertBefore(newChild, oldChild.nextElementSibling);
  1523. }
  1524. }
  1525.  
  1526. function getCheckImageSrc(value)
  1527. {
  1528. return 'images/icons/' + (value ? 'check' : 'x') + '.png';
  1529. }
  1530. var profileTable = document.getElementById('profile-toggleTable');
  1531. if (!profileTable)
  1532. {
  1533. return;
  1534. }
  1535. var settingsHeader = document.createElement('h2');
  1536. settingsHeader.className = 'section-title';
  1537. 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>";
  1538. var requiresReloadNote = settingsHeader.querySelector('.note');
  1539. insertAfter(settingsHeader, profileTable);
  1540. var settingsTable = document.createElement('table');
  1541. settingsTable.id = SETTINGS_TABLE_ID;
  1542. settingsTable.className = 'table-style1';
  1543. settingsTable.width = '40%';
  1544. 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";
  1545.  
  1546. function addRowClickListener(row, key, settingId)
  1547. {
  1548. row.addEventListener('click', function ()
  1549. {
  1550. var newValue = !get(key);
  1551. set(key, newValue);
  1552. document.getElementById(settingId).src = getCheckImageSrc(newValue);
  1553. });
  1554. }
  1555.  
  1556. function addSubClickListener(btn, dialog)
  1557. {
  1558. btn.addEventListener('click', function (event)
  1559. {
  1560. initJQueryDialog(dialog);
  1561. event.stopPropagation();
  1562. event.preventDefault();
  1563. });
  1564. }
  1565. for (var _i = 0, settings2Init_1 = settings2Init; _i < settings2Init_1.length; _i++)
  1566. {
  1567. var k = settings2Init_1[_i];
  1568. // convert it into a KEY
  1569. var key = parseInt(k, 10);
  1570. var setting = CFG[key];
  1571. if (setting == null)
  1572. {
  1573. console.error('missing setting entry:', key, toName(key));
  1574. continue;
  1575. }
  1576. var settingId = getSettingId(key);
  1577. var row = settingsTable.insertRow(-1);
  1578. row.classList.add('setting');
  1579. if (setting.requiresReload)
  1580. {
  1581. row.classList.add('reload');
  1582. requiresReloadNote.style.display = '';
  1583. }
  1584. row.setAttribute('onclick', '');
  1585. 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";
  1586. if (setting.sub)
  1587. {
  1588. row.classList.add('sub');
  1589. var subBtn = document.createElement('button');
  1590. subBtn.innerHTML = "<img src=\"images/icons/gearOff.gif\" class=\"image-icon-15\">";
  1591. row.cells.item(0).appendChild(subBtn);
  1592. var dialog = createSubSettingDialog(key);
  1593. addSubClickListener(subBtn, dialog);
  1594. }
  1595. var tooltipEl = ensureTooltip(settingId, row);
  1596. tooltipEl.innerHTML = setting.description;
  1597. if (setting.requiresReload)
  1598. {
  1599. 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>";
  1600. }
  1601. addRowClickListener(row, key, settingId);
  1602. }
  1603. insertAfter(settingsTable, settingsHeader);
  1604. }
  1605.  
  1606. function initProxies()
  1607. {
  1608. var row = document.querySelector('tr[data-tooltip-id="tooltip-profile-removeCraftingFilter"]');
  1609. if (row)
  1610. {
  1611. var valueCache_1 = getGameValue('profileRemoveCraftingFilter') != 1;
  1612. settingsProxies.set(KEY.hideCraftingRecipes
  1613. , {
  1614. get: function (key)
  1615. {
  1616. return getGameValue('profileRemoveCraftingFilter') != 1;
  1617. }
  1618. , set: function (key, oldValue, newValue)
  1619. {
  1620. if (valueCache_1 != newValue)
  1621. {
  1622. row.click();
  1623. valueCache_1 = newValue;
  1624. }
  1625. }
  1626. });
  1627. observer.add('profileRemoveCraftingFilter', function ()
  1628. {
  1629. set(KEY.hideCraftingRecipes, getGameValue('profileRemoveCraftingFilter') != 1);
  1630. });
  1631. }
  1632. }
  1633. var subDialog;
  1634. (function (subDialog)
  1635. {
  1636. function defaultHandler(key, dialog)
  1637. {
  1638. var setting = CFG[key];
  1639. var subSettings = setting.sub;
  1640. var settingContainer = createSubSettingsContainer(key, subSettings);
  1641. dialog.appendChild(settingContainer);
  1642. }
  1643.  
  1644. function colorizeChat(dialog)
  1645. {
  1646. defaultHandler(KEY.colorizeChat, dialog);
  1647. }
  1648. subDialog.colorizeChat = colorizeChat;
  1649.  
  1650. function showNotifications(dialog)
  1651. {
  1652. dialog.appendChild(document.createTextNode('Show notifications\u2026'));
  1653. defaultHandler(KEY.showNotifications, dialog);
  1654. dialog.appendChild(document.createTextNode('Events for which notifications are shown:'));
  1655. var ulNotifType = dialog.lastElementChild;
  1656. var ulEvents = ulNotifType.cloneNode(false);
  1657. while (ulNotifType.children.length > 1)
  1658. {
  1659. ulEvents.appendChild(ulNotifType.children.item(1));
  1660. }
  1661. dialog.appendChild(ulEvents);
  1662. }
  1663. subDialog.showNotifications = showNotifications;
  1664.  
  1665. function syncPriceHistory(dialog)
  1666. {
  1667. var setting = CFG[KEY.syncPriceHistory];
  1668. var subSettings = setting.sub;
  1669. var instructionEl = document.createElement('div');
  1670. instructionEl.className = 'instruction';
  1671. 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:";
  1672. dialog.appendChild(instructionEl);
  1673. var settingContainer = createSubSettingsContainer(KEY.syncPriceHistory, subSettings);
  1674. dialog.appendChild(settingContainer);
  1675. }
  1676. subDialog.syncPriceHistory = syncPriceHistory;
  1677. })(subDialog || (subDialog = {}));
  1678.  
  1679. function createSubSettingDialog(key)
  1680. {
  1681. var settingId = getSettingId(key);
  1682. var setting = CFG[key];
  1683. var dialog = document.createElement('div');
  1684. dialog.id = 'dialog-' + settingId;
  1685. dialog.style.display = 'none';
  1686. dialog.innerHTML = "<h2>" + setting.name + "</h2>";
  1687. var name = toName(key);
  1688. if (subDialog.hasOwnProperty(name))
  1689. {
  1690. subDialog[name](dialog);
  1691. }
  1692. else
  1693. {
  1694. console.warn('missing setting handler for "%s"', name);
  1695. var todoEl = document.createElement('span');
  1696. todoEl.textContent = 'TODO';
  1697. dialog.appendChild(todoEl);
  1698. }
  1699. document.body.appendChild(dialog);
  1700. return dialog;
  1701. }
  1702.  
  1703. function createSubSettingsContainer(parentKey, subSettings)
  1704. {
  1705. var settingsContainer = document.createElement('ul');
  1706. settingsContainer.className = 'settings-container';
  1707.  
  1708. function addCheckbox(listEl, subKey, id, setting)
  1709. {
  1710. var checkbox = document.createElement('input');
  1711. checkbox.type = 'checkbox';
  1712. checkbox.id = id;
  1713. checkbox.name = id;
  1714. checkbox.checked = getSub(parentKey, subKey);
  1715. var label = document.createElement('label');
  1716. label.htmlFor = id;
  1717. label.innerHTML = setting.label;
  1718. checkbox.addEventListener('change', function ()
  1719. {
  1720. return setSub(parentKey, subKey, checkbox.checked);
  1721. });
  1722. listEl.appendChild(checkbox);
  1723. listEl.appendChild(label);
  1724. }
  1725.  
  1726. function addSelectmenu(listEl, subKey, id, setting)
  1727. {
  1728. var select = document.createElement('select');
  1729. select.id = id;
  1730. select.name = id;
  1731. var options = setting.options;
  1732. var selectedIndex = getSub(parentKey, subKey);
  1733. for (var i = 0; i < options.length; i++)
  1734. {
  1735. var option = document.createElement('option');
  1736. option.value = options[i];
  1737. if (setting.label)
  1738. {
  1739. option.innerHTML = setting.label[i];
  1740. }
  1741. else
  1742. {
  1743. option.innerHTML = key2Name(options[i]);
  1744. }
  1745. option.selected = i == selectedIndex;
  1746. select.appendChild(option);
  1747. }
  1748. select.addEventListener('change', function ()
  1749. {
  1750. return setSub(parentKey, subKey, select.selectedIndex);
  1751. });
  1752. listEl.appendChild(select);
  1753. }
  1754.  
  1755. function addInput(listEl, subKey, id, setting)
  1756. {
  1757. var input = document.createElement('input');
  1758. input.type = 'text';
  1759. input.placeholder = setting.label || '';
  1760. input.value = getSub(parentKey, subKey);
  1761. var onChange = function ()
  1762. {
  1763. return setSub(parentKey, subKey, input.value);
  1764. };
  1765. input.addEventListener('click', onChange);
  1766. input.addEventListener('change', onChange);
  1767. input.addEventListener('keyup', onChange);
  1768. listEl.appendChild(input);
  1769. }
  1770. var keyList = Object.keys(subSettings);
  1771. var orderIndex = keyList.findIndex(function (k)
  1772. {
  1773. return subSettings[k].defaultValue instanceof Array;
  1774. });
  1775. var isSortable = orderIndex != -1;
  1776. if (isSortable)
  1777. {
  1778. keyList = getSub(parentKey, keyList[orderIndex]);
  1779. }
  1780. for (var _i = 0, keyList_1 = keyList; _i < keyList_1.length; _i++)
  1781. {
  1782. var subKey = keyList_1[_i];
  1783. var settingId = getSettingId(parentKey, subKey);
  1784. var setting = subSettings[subKey];
  1785. var listEl = document.createElement('li');
  1786. listEl.classList.add('setting');
  1787. if (isSortable)
  1788. {
  1789. listEl.dataset.subKey = subKey;
  1790. var sortableIcon = document.createElement('span');
  1791. sortableIcon.className = 'ui-icon ui-icon-arrowthick-2-n-s handle';
  1792. listEl.appendChild(sortableIcon);
  1793. }
  1794. if (setting.options)
  1795. {
  1796. addSelectmenu(listEl, subKey, settingId, setting);
  1797. }
  1798. else if (typeof setting.defaultValue === 'boolean')
  1799. {
  1800. addCheckbox(listEl, subKey, settingId, setting);
  1801. }
  1802. else if (typeof setting.defaultValue === 'string')
  1803. {
  1804. addInput(listEl, subKey, settingId, setting);
  1805. }
  1806. settingsContainer.appendChild(listEl);
  1807. }
  1808. return settingsContainer;
  1809. }
  1810.  
  1811. function initJQueryDialog(dialog)
  1812. {
  1813. var $dialog = win.$(dialog);
  1814. $dialog.dialog(
  1815. {
  1816. width: DIALOG_WIDTH + 'px'
  1817. });
  1818. $dialog.find('input[type="checkbox"]').checkboxradio()
  1819. .next().children(':first-child').removeClass('ui-state-hover');
  1820. $dialog.find('button:not(.sub)').button();
  1821. $dialog.find('input:text').button()
  1822. .addClass('ui-textfield')
  1823. .off('mouseenter').off('mousedown').off('keydown');
  1824. $dialog.find('select').selectmenu(
  1825. {
  1826. change: function (event, ui)
  1827. {
  1828. var changeEvent = document.createEvent('HTMLEvents');
  1829. changeEvent.initEvent('change', false, true);
  1830. event.target.dispatchEvent(changeEvent);
  1831. }
  1832. });
  1833. $dialog.find('.sortable').sortable(
  1834. {
  1835. handle: '.handle'
  1836. , update: function (event, ui)
  1837. {
  1838. var newOrder = [];
  1839. var children = event.target.children;
  1840. for (var i = 0; i < children.length; i++)
  1841. {
  1842. var child = children[i];
  1843. newOrder.push(child.dataset.subKey);
  1844. }
  1845. var updateEvent = new CustomEvent('sortupdate'
  1846. , {
  1847. detail: newOrder
  1848. });
  1849. event.target.dispatchEvent(updateEvent);
  1850. }
  1851. });
  1852. return $dialog;
  1853. }
  1854.  
  1855. function createSettingsContainer(settingList)
  1856. {
  1857. var settingsContainer = document.createElement('ul');
  1858. settingsContainer.className = 'settings-container';
  1859.  
  1860. function addOpenDialogClickListener(el, dialog)
  1861. {
  1862. el.addEventListener('click', function (event)
  1863. {
  1864. initJQueryDialog(dialog);
  1865. event.stopPropagation();
  1866. event.preventDefault();
  1867. });
  1868. }
  1869.  
  1870. function addChangeListener(key, checkbox)
  1871. {
  1872. checkbox.addEventListener('change', function ()
  1873. {
  1874. set(key, checkbox.checked);
  1875. });
  1876. }
  1877. for (var _i = 0, settingList_1 = settingList; _i < settingList_1.length; _i++)
  1878. {
  1879. var key = settingList_1[_i];
  1880. var settingId = getSettingId(key);
  1881. var setting = CFG[key];
  1882. var index = settings2Init.indexOf(key.toString());
  1883. if (index != -1)
  1884. {
  1885. settings2Init.splice(index, 1);
  1886. }
  1887. var listEl = document.createElement('li');
  1888. listEl.classList.add('setting');
  1889. if (setting.requiresReload)
  1890. {
  1891. listEl.classList.add('reload');
  1892. }
  1893. var checkbox = document.createElement('input');
  1894. checkbox.type = 'checkbox';
  1895. checkbox.id = settingId;
  1896. checkbox.checked = get(key);
  1897. var label = document.createElement('label');
  1898. label.htmlFor = settingId;
  1899. label.textContent = setting.name;
  1900. addChangeListener(key, checkbox);
  1901. listEl.appendChild(checkbox);
  1902. listEl.appendChild(label);
  1903. if (setting.sub)
  1904. {
  1905. var moreBtn = document.createElement('button');
  1906. moreBtn.className = 'sub';
  1907. moreBtn.innerHTML = "<img src=\"images/icons/gearOff.gif\" class=\"image-icon-20\" />";
  1908. listEl.appendChild(moreBtn);
  1909. var dialog = createSubSettingDialog(key);
  1910. addOpenDialogClickListener(moreBtn, dialog);
  1911. }
  1912. settingsContainer.appendChild(listEl);
  1913. var tooltipEl = ensureTooltip(settingId, listEl);
  1914. tooltipEl.innerHTML = setting.description;
  1915. if (setting.requiresReload)
  1916. {
  1917. 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>";
  1918. }
  1919. }
  1920. return settingsContainer;
  1921. }
  1922.  
  1923. function initCraftingSettings()
  1924. {
  1925. var craftingItems = document.getElementById('tab-sub-container-crafting');
  1926. if (!craftingItems)
  1927. {
  1928. return;
  1929. }
  1930. var br = craftingItems.nextElementSibling;
  1931. var after = br.nextElementSibling;
  1932. var parent = after.parentElement;
  1933. var settingList = [KEY.hideCraftingRecipes, KEY.hideUselessItems];
  1934. var settingsContainer = createSettingsContainer(settingList);
  1935. parent.insertBefore(settingsContainer, after);
  1936. }
  1937.  
  1938. function initMuteDialog(settingsContainer)
  1939. {
  1940. // muted people dialog
  1941. var dialog = document.createElement('div');
  1942. dialog.id = 'dialog-chat-muted-people';
  1943. dialog.style.display = 'none';
  1944. dialog.innerHTML = "<h2>Muted people</h2>";
  1945. var input = document.createElement('input');
  1946. input.type = 'text';
  1947. input.placeholder = 'username';
  1948. dialog.appendChild(input);
  1949. var addBtn = document.createElement('button');
  1950. addBtn.textContent = '+';
  1951. dialog.appendChild(addBtn);
  1952. var listEl = document.createElement('ul');
  1953. listEl.className = 'settings-container list';
  1954. var username2Item = {};
  1955. var username2Btn = {};
  1956.  
  1957. function removeListener(event)
  1958. {
  1959. var target = event.target;
  1960. var username = target.dataset.username || '';
  1961. var index = win.mutedPeople.indexOf(username);
  1962. if (index !== -1)
  1963. {
  1964. win.mutedPeople.splice(index, 1);
  1965. }
  1966. }
  1967.  
  1968. function add2List(username)
  1969. {
  1970. var item = document.createElement('li');
  1971. item.innerHTML = "<span class=\"content\">" + username + "</span>";
  1972. var removeBtn = document.createElement('button');
  1973. removeBtn.dataset.username = username;
  1974. removeBtn.textContent = '-';
  1975. win.$(removeBtn).button();
  1976. removeBtn.addEventListener('click', removeListener);
  1977. username2Btn[username] = removeBtn;
  1978. item.appendChild(removeBtn);
  1979. username2Item[username] = item;
  1980. listEl.appendChild(item);
  1981. }
  1982. var _push = win.mutedPeople.push;
  1983. win.mutedPeople.push = function ()
  1984. {
  1985. var items = [];
  1986. for (var _i = 0; _i < arguments.length; _i++)
  1987. {
  1988. items[_i] = arguments[_i];
  1989. }
  1990. items.forEach(function (username)
  1991. {
  1992. return add2List(username);
  1993. });
  1994. return _push.call.apply(_push, [win.mutedPeople].concat(items));
  1995. };
  1996. var _splice = win.mutedPeople.splice;
  1997. win.mutedPeople.splice = function (start, deleteCount)
  1998. {
  1999. var items = [];
  2000. for (var _i = 2; _i < arguments.length; _i++)
  2001. {
  2002. items[_i - 2] = arguments[_i];
  2003. }
  2004. for (var i = 0; i < deleteCount; i++)
  2005. {
  2006. var username = win.mutedPeople[start + i];
  2007. var item = username2Item[username];
  2008. delete username2Item[username];
  2009. listEl.removeChild(item);
  2010. var btn = username2Btn[username];
  2011. delete username2Btn[username];
  2012. btn.removeEventListener('click', removeListener);
  2013. }
  2014. items.forEach(function (username)
  2015. {
  2016. return add2List(username);
  2017. });
  2018. return _splice.call.apply(_splice, [win.mutedPeople, start, deleteCount].concat(items));
  2019. };
  2020. dialog.appendChild(listEl);
  2021. addBtn.addEventListener('click', function ()
  2022. {
  2023. win.mutedPeople.push(input.value);
  2024. input.value = '';
  2025. });
  2026. document.body.appendChild(dialog);
  2027. var listItem = document.createElement('li');
  2028. listItem.classList.add('setting');
  2029. var dialogBtn = document.createElement('button');
  2030. dialogBtn.innerHTML = "List of muted people";
  2031. dialogBtn.addEventListener('click', function ()
  2032. {
  2033. initJQueryDialog(dialog);
  2034. });
  2035. listItem.appendChild(dialogBtn);
  2036. settingsContainer.appendChild(listItem);
  2037. }
  2038.  
  2039. function initKeywordDialog(settingsContainer)
  2040. {
  2041. // keyword dialog
  2042. var dialog = document.createElement('div');
  2043. dialog.id = 'dialog-chat-keyword-list';
  2044. dialog.style.display = 'none';
  2045. dialog.innerHTML = "<h2>Keywords</h2>";
  2046. var input = document.createElement('input');
  2047. input.type = 'text';
  2048. input.placeholder = 'keyword';
  2049. dialog.appendChild(input);
  2050. var addBtn = document.createElement('button');
  2051. addBtn.textContent = '+';
  2052. dialog.appendChild(addBtn);
  2053. var listEl = document.createElement('ul');
  2054. listEl.className = 'settings-container list';
  2055.  
  2056. function add2List(keyword)
  2057. {
  2058. var item = document.createElement('li');
  2059. item.innerHTML = "<span class=\"content\">" + keyword + "</span>";
  2060. var removeBtn = document.createElement('button');
  2061. removeBtn.textContent = '-';
  2062. win.$(removeBtn).button();
  2063. var remove = function ()
  2064. {
  2065. if (chat.removeKeyword(keyword))
  2066. {
  2067. listEl.removeChild(item);
  2068. removeBtn.removeEventListener('click', remove);
  2069. }
  2070. };
  2071. removeBtn.addEventListener('click', remove);
  2072. item.appendChild(removeBtn);
  2073. listEl.appendChild(item);
  2074. }
  2075. // add all keywords
  2076. chat.keywordList.forEach(function (keyword)
  2077. {
  2078. return add2List(keyword);
  2079. });
  2080. dialog.appendChild(listEl);
  2081. addBtn.addEventListener('click', function ()
  2082. {
  2083. var keyword = input.value;
  2084. if (chat.addKeyword(keyword))
  2085. {
  2086. add2List(keyword);
  2087. input.value = '';
  2088. }
  2089. });
  2090. document.body.appendChild(dialog);
  2091. var listItem = document.createElement('li');
  2092. listItem.classList.add('setting');
  2093. var dialogBtn = document.createElement('button');
  2094. dialogBtn.innerHTML = "Manage list of keywords";
  2095. dialogBtn.addEventListener('click', function ()
  2096. {
  2097. initJQueryDialog(dialog);
  2098. });
  2099. listItem.appendChild(dialogBtn);
  2100. settingsContainer.appendChild(listItem);
  2101. }
  2102.  
  2103. function initChatSettings()
  2104. {
  2105. var controlDiv = document.querySelector('#div-chat > div:first-child');
  2106. if (!controlDiv)
  2107. {
  2108. return;
  2109. }
  2110. var btn = document.createElement('button');
  2111. btn.textContent = 'Chat Settings';
  2112. controlDiv.appendChild(btn);
  2113. var dialog = document.createElement('div');
  2114. dialog.id = 'dialog-chat-settings';
  2115. dialog.style.display = 'none';
  2116. dialog.innerHTML = "<h2>Chat Settings</h2>";
  2117. var settingList = [KEY.useNewChat, KEY.colorizeChat, KEY.intelligentScrolling, KEY.showTimestamps, KEY.showIcons, KEY.showTags, KEY.enableSpamDetection];
  2118. var settingsContainer = createSettingsContainer(settingList);
  2119. initMuteDialog(settingsContainer);
  2120. initKeywordDialog(settingsContainer);
  2121. dialog.appendChild(settingsContainer);
  2122. document.body.appendChild(dialog);
  2123. btn.addEventListener('click', function ()
  2124. {
  2125. initJQueryDialog(dialog);
  2126. });
  2127. }
  2128.  
  2129. function init()
  2130. {
  2131. initProxies();
  2132. initSettingsStyle();
  2133. initCraftingSettings();
  2134. initChatSettings();
  2135. initSettingTable();
  2136. }
  2137. settings.init = init;
  2138. var _a;
  2139. })(settings || (settings = {}));
  2140. /**
  2141. * Code from https://github.com/davidmerfield/randomColor
  2142. */
  2143. var colorGenerator;
  2144. (function (colorGenerator)
  2145. {
  2146. // seed to get repeatable colors
  2147. var seed = null;
  2148. var COLOR_NOT_FOUND = {
  2149. hueRange: []
  2150. , lowerBounds: []
  2151. , saturationRange: []
  2152. , brightnessRange: []
  2153. };
  2154. var COLOR_BOUNDS = {
  2155. 'monochrome':
  2156. {
  2157. hueRange: []
  2158. , lowerBounds: [
  2159. [0, 0]
  2160. , [100, 0]
  2161. ]
  2162. }
  2163. , 'red':
  2164. {
  2165. hueRange: [-26, 18]
  2166. , lowerBounds: [
  2167. [20, 100]
  2168. , [30, 92]
  2169. , [40, 89]
  2170. , [50, 85]
  2171. , [60, 78]
  2172. , [70, 70]
  2173. , [80, 60]
  2174. , [90, 55]
  2175. , [100, 50]
  2176. ]
  2177. }
  2178. , 'orange':
  2179. {
  2180. hueRange: [19, 46]
  2181. , lowerBounds: [
  2182. [20, 100]
  2183. , [30, 93]
  2184. , [40, 88]
  2185. , [50, 86]
  2186. , [60, 85]
  2187. , [70, 70]
  2188. , [100, 70]
  2189. ]
  2190. }
  2191. , 'yellow':
  2192. {
  2193. hueRange: [47, 62]
  2194. , lowerBounds: [
  2195. [25, 100]
  2196. , [40, 94]
  2197. , [50, 89]
  2198. , [60, 86]
  2199. , [70, 84]
  2200. , [80, 82]
  2201. , [90, 80]
  2202. , [100, 75]
  2203. ]
  2204. }
  2205. , 'green':
  2206. {
  2207. hueRange: [63, 178]
  2208. , lowerBounds: [
  2209. [30, 100]
  2210. , [40, 90]
  2211. , [50, 85]
  2212. , [60, 81]
  2213. , [70, 74]
  2214. , [80, 64]
  2215. , [90, 50]
  2216. , [100, 40]
  2217. ]
  2218. }
  2219. , 'blue':
  2220. {
  2221. hueRange: [179, 257]
  2222. , lowerBounds: [
  2223. [20, 100]
  2224. , [30, 86]
  2225. , [40, 80]
  2226. , [50, 74]
  2227. , [60, 60]
  2228. , [70, 52]
  2229. , [80, 44]
  2230. , [90, 39]
  2231. , [100, 35]
  2232. ]
  2233. }
  2234. , 'purple':
  2235. {
  2236. hueRange: [258, 282]
  2237. , lowerBounds: [
  2238. [20, 100]
  2239. , [30, 87]
  2240. , [40, 79]
  2241. , [50, 70]
  2242. , [60, 65]
  2243. , [70, 59]
  2244. , [80, 52]
  2245. , [90, 45]
  2246. , [100, 42]
  2247. ]
  2248. }
  2249. , 'pink':
  2250. {
  2251. hueRange: [283, 334]
  2252. , lowerBounds: [
  2253. [20, 100]
  2254. , [30, 90]
  2255. , [40, 86]
  2256. , [60, 84]
  2257. , [80, 80]
  2258. , [90, 75]
  2259. , [100, 73]
  2260. ]
  2261. }
  2262. };
  2263. // shared color dictionary
  2264. var colorDictionary = {};
  2265.  
  2266. function defineColor(name, hueRange, lowerBounds)
  2267. {
  2268. var _a = lowerBounds[0]
  2269. , sMin = _a[0]
  2270. , bMax = _a[1];
  2271. var _b = lowerBounds[lowerBounds.length - 1]
  2272. , sMax = _b[0]
  2273. , bMin = _b[1];
  2274. colorDictionary[name] = {
  2275. hueRange: hueRange
  2276. , lowerBounds: lowerBounds
  2277. , saturationRange: [sMin, sMax]
  2278. , brightnessRange: [bMin, bMax]
  2279. };
  2280. }
  2281.  
  2282. function loadColorBounds()
  2283. {
  2284. for (var name_1 in COLOR_BOUNDS)
  2285. {
  2286. defineColor(name_1, COLOR_BOUNDS[name_1].hueRange, COLOR_BOUNDS[name_1].lowerBounds);
  2287. }
  2288. }
  2289.  
  2290. function randomWithin(min, max)
  2291. {
  2292. if (min === void 0)
  2293. {
  2294. min = 0;
  2295. }
  2296. if (max === void 0)
  2297. {
  2298. max = 0;
  2299. }
  2300. if (seed === null)
  2301. {
  2302. return Math.floor(min + Math.random() * (max + 1 - min));
  2303. }
  2304. else
  2305. {
  2306. // seeded random algorithm from http://indiegamr.com/generate-repeatable-random-numbers-in-js/
  2307. seed = (seed * 9301 + 49297) % 233280;
  2308. var rnd = seed / 233280.0;
  2309. return Math.floor(min + rnd * (max - min));
  2310. }
  2311. }
  2312.  
  2313. function getColorInfo(hue)
  2314. {
  2315. // maps red colors to make picking hue easier
  2316. if (hue >= 334 && hue <= 360)
  2317. {
  2318. hue -= 360;
  2319. }
  2320. for (var colorName in colorDictionary)
  2321. {
  2322. var color = colorDictionary[colorName];
  2323. if (color.hueRange.length > 0
  2324. && hue >= color.hueRange[0]
  2325. && hue <= color.hueRange[1])
  2326. {
  2327. return colorDictionary[colorName];
  2328. }
  2329. }
  2330. return COLOR_NOT_FOUND;
  2331. }
  2332.  
  2333. function getHueRange(colorInput)
  2334. {
  2335. var number = typeof colorInput === 'undefined' ? Number.NaN : colorInput;
  2336. if (typeof number === 'string')
  2337. {
  2338. number = parseInt(number, 10);
  2339. }
  2340. if (colorInput && isNaN(number) && colorDictionary.hasOwnProperty(colorInput))
  2341. {
  2342. var color = colorDictionary[colorInput];
  2343. if (color.hueRange.length > 0)
  2344. {
  2345. return color.hueRange;
  2346. }
  2347. }
  2348. else if (!isNaN(number) && number < 360 && number > 0)
  2349. {
  2350. return [number, number];
  2351. }
  2352. return [0, 360];
  2353. }
  2354.  
  2355. function pickHue(options)
  2356. {
  2357. var hueRange = getHueRange(options.hue);
  2358. var hue = randomWithin(hueRange[0], hueRange[1]);
  2359. // instead of storing red as two seperate ranges, we group them, using negative numbers
  2360. if (hue < 0)
  2361. {
  2362. return 360 + hue;
  2363. }
  2364. return hue;
  2365. }
  2366.  
  2367. function getSaturationRange(hue)
  2368. {
  2369. return getColorInfo(hue).saturationRange;
  2370. }
  2371.  
  2372. function pickSaturation(hue, options)
  2373. {
  2374. if (options.luminosity === 'random')
  2375. {
  2376. return randomWithin(0, 100);
  2377. }
  2378. if (options.hue === 'monochrome')
  2379. {
  2380. return 0;
  2381. }
  2382. var _a = getSaturationRange(hue)
  2383. , sMin = _a[0]
  2384. , sMax = _a[1];
  2385. switch (options.luminosity)
  2386. {
  2387. case 'bright':
  2388. sMin = 55;
  2389. break;
  2390. case 'dark':
  2391. sMin = sMax - 10;
  2392. break;
  2393. case 'light':
  2394. sMax = 55;
  2395. break;
  2396. }
  2397. return randomWithin(sMin, sMax);
  2398. }
  2399.  
  2400. function getMinimumBrightness(H, S)
  2401. {
  2402. var lowerBounds = getColorInfo(H).lowerBounds;
  2403. for (var i = 0; i < lowerBounds.length - 1; i++)
  2404. {
  2405. var _a = lowerBounds[i]
  2406. , s1 = _a[0]
  2407. , v1 = _a[1];
  2408. var _b = lowerBounds[i + 1]
  2409. , s2 = _b[0]
  2410. , v2 = _b[1];
  2411. if (S >= s1 && S <= s2)
  2412. {
  2413. var m = (v2 - v1) / (s2 - s1);
  2414. var b = v1 - m * s1;
  2415. return m * S + b;
  2416. }
  2417. }
  2418. return 0;
  2419. }
  2420.  
  2421. function pickBrightness(H, S, options)
  2422. {
  2423. var bMin = getMinimumBrightness(H, S);
  2424. var bMax = 100;
  2425. switch (options.luminosity)
  2426. {
  2427. case 'dark':
  2428. bMax = bMin + 20;
  2429. break;
  2430. case 'light':
  2431. bMin = (bMax + bMin) / 2;
  2432. break;
  2433. case 'random':
  2434. bMin = 0;
  2435. bMax = 100;
  2436. break;
  2437. }
  2438. return randomWithin(bMin, bMax);
  2439. }
  2440. var HSVColor = (function ()
  2441. {
  2442. function HSVColor(H, S, V)
  2443. {
  2444. this.H = H;
  2445. this.S = S;
  2446. this.V = V;
  2447. }
  2448. HSVColor.fromHSVArray = function (hsv)
  2449. {
  2450. return new HSVColor(hsv[0], hsv[1], hsv[2]);
  2451. };
  2452. HSVColor.prototype.toHex = function ()
  2453. {
  2454. var rgb = this.toRGB();
  2455. return '#' + this.componentToHex(rgb[0]) + this.componentToHex(rgb[1]) + this.componentToHex(rgb[2]);
  2456. };
  2457. HSVColor.prototype.toHSL = function ()
  2458. {
  2459. var h = this.H;
  2460. var s = this.S / 100;
  2461. var v = this.V / 100;
  2462. var k = (2 - s) * v;
  2463. return [
  2464. h
  2465. , Math.round(s * v / (k < 1 ? k : 2 - k) * 10e3) / 100
  2466. , k / 2 * 100
  2467. ];
  2468. };
  2469. HSVColor.prototype.toHSLString = function (alpha)
  2470. {
  2471. var hsl = this.toHSL();
  2472. if (alpha !== undefined)
  2473. {
  2474. return "hsla(" + hsl[0] + ", " + hsl[1] + "%, " + hsl[2] + "%, " + alpha + ")";
  2475. }
  2476. else
  2477. {
  2478. return "hsl(" + hsl[0] + ", " + hsl[1] + "%, " + hsl[2] + "%)";
  2479. }
  2480. };
  2481. HSVColor.prototype.toRGB = function ()
  2482. {
  2483. // this doesn't work for the values of 0 and 360 here's the hacky fix
  2484. var h = Math.min(Math.max(this.H, 1), 359);
  2485. // Rebase the h,s,v values
  2486. h = h / 360;
  2487. var s = this.S / 100;
  2488. var v = this.V / 100;
  2489. var h_i = Math.floor(h * 6);
  2490. var f = h * 6 - h_i;
  2491. var p = v * (1 - s);
  2492. var q = v * (1 - f * s);
  2493. var t = v * (1 - (1 - f) * s);
  2494. var r = 256;
  2495. var g = 256;
  2496. var b = 256;
  2497. switch (h_i)
  2498. {
  2499. case 0:
  2500. r = v;
  2501. g = t;
  2502. b = p;
  2503. break;
  2504. case 1:
  2505. r = q;
  2506. g = v;
  2507. b = p;
  2508. break;
  2509. case 2:
  2510. r = p;
  2511. g = v;
  2512. b = t;
  2513. break;
  2514. case 3:
  2515. r = p;
  2516. g = q;
  2517. b = v;
  2518. break;
  2519. case 4:
  2520. r = t;
  2521. g = p;
  2522. b = v;
  2523. break;
  2524. case 5:
  2525. r = v;
  2526. g = p;
  2527. b = q;
  2528. break;
  2529. }
  2530. return [Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)];
  2531. };
  2532. HSVColor.prototype.toRGBString = function (alpha)
  2533. {
  2534. var rgb = this.toRGB();
  2535. if (alpha !== undefined)
  2536. {
  2537. return "rgba(" + rgb.join(', ') + ", " + alpha + ")";
  2538. }
  2539. else
  2540. {
  2541. return "rgb(" + rgb.join(', ') + ")";
  2542. }
  2543. };
  2544. HSVColor.prototype.componentToHex = function (c)
  2545. {
  2546. var hex = c.toString(16);
  2547. return hex.length == 1 ? '0' + hex : hex;
  2548. };
  2549. return HSVColor;
  2550. }());
  2551. colorGenerator.HSVColor = HSVColor;
  2552.  
  2553. function setFormat(hsv, options)
  2554. {
  2555. var color = HSVColor.fromHSVArray(hsv);
  2556. switch (options.format)
  2557. {
  2558. case 'object':
  2559. return color;
  2560. case 'hsvArray':
  2561. return hsv;
  2562. case 'hslArray':
  2563. return color.toHSL();
  2564. case 'hsl':
  2565. return color.toHSLString();
  2566. case 'hsla':
  2567. return color.toHSLString(options.alpha || Math.random());
  2568. case 'rgbArray':
  2569. return color.toRGB();
  2570. case 'rgb':
  2571. return color.toRGBString();
  2572. case 'rgba':
  2573. return color.toRGBString(options.alpha || Math.random());
  2574. case 'hex':
  2575. default:
  2576. return color.toHex();
  2577. }
  2578. }
  2579.  
  2580. function generateColor(options)
  2581. {
  2582. // pick a hue (H)
  2583. var H = pickHue(options);
  2584. // use H to determine saturation (S)
  2585. var S = pickSaturation(H, options);
  2586. // use S and H to determine brightness (B)
  2587. var B = pickBrightness(H, S, options);
  2588. // return the HSB color in the desired format
  2589. return setFormat([H, S, B], options);
  2590. }
  2591.  
  2592. function getRandom(options)
  2593. {
  2594. options = options ||
  2595. {};
  2596. seed = options.seed == null ? null : options.seed;
  2597. // check if we need to generate multiple colors
  2598. if (options.count !== null && options.count !== undefined)
  2599. {
  2600. var colors = [];
  2601. while (options.count > colors.length)
  2602. {
  2603. // Since we're generating multiple colors, the seed has to be incrememented.
  2604. // Otherwise we'd just generate the same color each time...
  2605. if (seed !== null)
  2606. {
  2607. seed += 1;
  2608. }
  2609. colors.push(generateColor(options));
  2610. }
  2611. return colors;
  2612. }
  2613. return generateColor(options);
  2614. }
  2615. colorGenerator.getRandom = getRandom;
  2616. var ColorInterval = (function ()
  2617. {
  2618. function ColorInterval(start, end)
  2619. {
  2620. this.start = start;
  2621. this.end = end;
  2622. this.left = null;
  2623. this.right = null;
  2624. this.value = null;
  2625. }
  2626. ColorInterval.prototype.getNextValue = function ()
  2627. {
  2628. if (this.value == null)
  2629. {
  2630. this.value = (this.start + this.end) / 2;
  2631. return this.value;
  2632. }
  2633. if (this.left == null)
  2634. {
  2635. this.left = new ColorInterval(this.start, this.value);
  2636. return this.left.getNextValue();
  2637. }
  2638. if (this.right == null)
  2639. {
  2640. this.right = new ColorInterval(this.value, this.end);
  2641. return this.right.getNextValue();
  2642. }
  2643. if (this.left.getHeight() <= this.right.getHeight())
  2644. {
  2645. return this.left.getNextValue();
  2646. }
  2647. else
  2648. {
  2649. return this.right.getNextValue();
  2650. }
  2651. };
  2652. ColorInterval.prototype.getHeight = function ()
  2653. {
  2654. return 1
  2655. + (this.left == null ? 0 : this.left.getHeight())
  2656. + (this.right == null ? 0 : this.right.getHeight());
  2657. };
  2658. return ColorInterval;
  2659. }());
  2660. colorGenerator.ColorInterval = ColorInterval;
  2661. var defaultRootInterval = new ColorInterval(0, 360);
  2662.  
  2663. function getEquallyDistributed(rootInterval)
  2664. {
  2665. if (rootInterval === void 0)
  2666. {
  2667. rootInterval = defaultRootInterval;
  2668. }
  2669. return 'hsl(' + rootInterval.getNextValue() + ', 100%, 80%)';
  2670. }
  2671. colorGenerator.getEquallyDistributed = getEquallyDistributed;
  2672. var Color = (function ()
  2673. {
  2674. function Color(r, g, b)
  2675. {
  2676. this.r = r;
  2677. this.g = g;
  2678. this.b = b;
  2679. }
  2680. Color.fromHex = function (hex)
  2681. {
  2682. return new Color(parseInt(hex.substr(1, 2), 16), parseInt(hex.substr(3, 2), 16), parseInt(hex.substr(5, 2), 16));
  2683. };
  2684. Color.fromRgb = function (rgb)
  2685. {
  2686. var match = rgb.match(this.rgbRegex);
  2687. return new Color(parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3], 10));
  2688. };
  2689. Color.fromString = function (str)
  2690. {
  2691. if (this.hexRegex.test(str))
  2692. {
  2693. return this.fromHex(str);
  2694. }
  2695. else if (this.rgbRegex.test(str))
  2696. {
  2697. return this.fromRgb(str);
  2698. }
  2699. else
  2700. {
  2701. throw new Error('Unexpected color format: ' + str);
  2702. }
  2703. };
  2704. Color.prototype.toString = function (hex)
  2705. {
  2706. if (hex === void 0)
  2707. {
  2708. hex = true;
  2709. }
  2710. return '#' + this.toHex(this.r) + this.toHex(this.g) + this.toHex(this.b);
  2711. };
  2712. Color.prototype.toHex = function (x)
  2713. {
  2714. var xStr = x.toString(16);
  2715. return (xStr.length == 1 ? '0' : '') + xStr;
  2716. };
  2717. Color.hexRegex = /^#(?:[0-9a-f]{3}){1,2}$/i;
  2718. Color.rgbRegex = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i;
  2719. return Color;
  2720. }());
  2721.  
  2722. function ratioColor(color1, color2, ratio)
  2723. {
  2724. 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));
  2725. return color.toString();
  2726. }
  2727.  
  2728. function getColorTransition(value, colorStrings)
  2729. {
  2730. var smallerValue = -1;
  2731. var biggerValue = Number.MAX_SAFE_INTEGER;
  2732. var colors = {};
  2733. for (var v in colorStrings)
  2734. {
  2735. var vNum = Number(v);
  2736. if (vNum === value)
  2737. {
  2738. return colorStrings[v];
  2739. }
  2740. else if (vNum < value)
  2741. {
  2742. smallerValue = Math.max(smallerValue, vNum);
  2743. }
  2744. else
  2745. {
  2746. biggerValue = Math.min(biggerValue, vNum);
  2747. }
  2748. colors[v] = Color.fromString(colorStrings[v]);
  2749. }
  2750. if (smallerValue === -1)
  2751. {
  2752. return colorStrings[biggerValue];
  2753. }
  2754. if (biggerValue === Number.MAX_SAFE_INTEGER)
  2755. {
  2756. return colorStrings[smallerValue];
  2757. }
  2758. var ratio = (value - smallerValue) / (biggerValue - smallerValue);
  2759. return ratioColor(colors[smallerValue], colors[biggerValue], ratio);
  2760. }
  2761. colorGenerator.getColorTransition = getColorTransition;
  2762. // populate the color dictionary
  2763. loadColorBounds();
  2764. })(colorGenerator || (colorGenerator = {}));
  2765.  
  2766. /**
  2767. * provides icons
  2768. */
  2769. var icons;
  2770. (function (icons)
  2771. {
  2772. 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';
  2773. 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"/>';
  2774.  
  2775. function getSvgAsUrl(svg)
  2776. {
  2777. return "url('data:image/svg+xml;base64," + btoa(svg) + "')";
  2778. }
  2779. icons.getSvgAsUrl = getSvgAsUrl;
  2780.  
  2781. function wrapCodeWithSvg(code, viewBox, width, height)
  2782. {
  2783. return "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"" + width + "\" height=\"" + height + "\" viewBox=\"" + viewBox + "\">" + code + "</svg>";
  2784. }
  2785. icons.wrapCodeWithSvg = wrapCodeWithSvg;
  2786.  
  2787. function getMd(pathDots, color, width, height)
  2788. {
  2789. if (color === void 0)
  2790. {
  2791. color = 'black';
  2792. }
  2793. if (width === void 0)
  2794. {
  2795. width = '30';
  2796. }
  2797. if (height === void 0)
  2798. {
  2799. height = '30';
  2800. }
  2801. return getSvgAsUrl(wrapCodeWithSvg("<path fill=\"" + color + "\" d=\"" + pathDots + "\" />", '0 0 24 24', width, height));
  2802. }
  2803. icons.getMd = getMd;
  2804. })(icons || (icons = {}));
  2805.  
  2806. /**
  2807. * notifications
  2808. */
  2809. var notifications;
  2810. (function (notifications)
  2811. {
  2812. notifications.name = 'notifications';
  2813.  
  2814. function event(title, options)
  2815. {
  2816. if ((!options || options.whenActive !== true)
  2817. && !document.hidden && document.hasFocus()
  2818. && settings.getSub(settings.KEY.showNotifications, 'showType') !== 1)
  2819. {
  2820. return;
  2821. }
  2822. if (!settings.get(settings.KEY.showNotifications))
  2823. {
  2824. // notifications disabled: return stub notification
  2825. return Promise.resolve(
  2826. {
  2827. close: function () {}
  2828. });
  2829. }
  2830. if (!("Notification" in win))
  2831. {
  2832. return Promise.reject('Your browser does not support notifications.');
  2833. }
  2834. return Notification.requestPermission()
  2835. .then(function (permission)
  2836. {
  2837. if (permission === 'granted')
  2838. {
  2839. var n_1 = new Notification(title, options);
  2840. n_1.onclick = function (event)
  2841. {
  2842. if (options && options.autoFocus !== false)
  2843. {
  2844. win.focus();
  2845. }
  2846. if (options && options.autoClose !== false)
  2847. {
  2848. n_1.close();
  2849. }
  2850. if (options && options.onclick)
  2851. {
  2852. options.onclick(n_1, event);
  2853. }
  2854. };
  2855. return Promise.resolve(n_1);
  2856. }
  2857. else
  2858. {
  2859. return Promise.reject('Notification permission denied');
  2860. }
  2861. });
  2862. }
  2863. notifications.event = event;
  2864.  
  2865. function requestPermission()
  2866. {
  2867. if (settings.get(settings.KEY.showNotifications))
  2868. {
  2869. Notification.requestPermission();
  2870. }
  2871. }
  2872.  
  2873. function init()
  2874. {
  2875. requestPermission();
  2876. settings.observe(settings.KEY.showNotifications, function ()
  2877. {
  2878. return requestPermission();
  2879. });
  2880. }
  2881. notifications.init = init;
  2882. })(notifications || (notifications = {}));
  2883.  
  2884. /**
  2885. * process commands
  2886. */
  2887. var commands;
  2888. (function (commands)
  2889. {
  2890. var XP_GAIN_KEY = 'xpGain';
  2891. var MAX_XP_GAIN_HISTORY_LENGTH = 100;
  2892. var IMAGE2SKILL = {
  2893. // mining = #cc0000
  2894. 'icons/pickaxe': 'mining'
  2895. // crafting = #cc0000
  2896. , 'icons/anvil': 'crafting'
  2897. // woodcutting = cyan
  2898. , 'icons/woodcutting': 'woodcutting'
  2899. // farming = green
  2900. , 'icons/watering-can': 'farming'
  2901. // brewing = #800080
  2902. , 'vialOfWater': 'brewing'
  2903. , 'largeVialOfWater': 'brewing'
  2904. , 'hugeVialOfWater': 'brewing'
  2905. // combat = lime
  2906. , 'icons/combat': 'combat'
  2907. // magic = blue
  2908. , 'icons/wizardhat': 'magic'
  2909. // fishing = blue
  2910. , 'tuna': 'fishing'
  2911. // cooking = yellow
  2912. , 'icons/cooking': 'cooking'
  2913. };
  2914. var xpGainHistory = store.has(XP_GAIN_KEY) ? store.get(XP_GAIN_KEY) :
  2915. {};
  2916. addStyle("\n.scroller.xp\n{\n\tfont-size: 18pt;\n\tposition: absolute;\n\ttext-align: center;\n}\n\t");
  2917.  
  2918. function minutes2String(data)
  2919. {
  2920. return data.replace(/Your account has been running for: (\d+) minutes./, function (wholeMatch, minutes)
  2921. {
  2922. return 'Your account has been running for ' + format.min2Str(minutes) + '.';
  2923. });
  2924. }
  2925. var LOOT_MSG_PREFIX = 'SHOW_LOOT_DIAG=';
  2926.  
  2927. function processLoot(data)
  2928. {
  2929. if (!/^SM=Your boat found nothing\.$|^SHOW_LOOT_DIAG=/.test(data))
  2930. {
  2931. return false;
  2932. }
  2933. var loot = {
  2934. type: 'loot'
  2935. , title: ''
  2936. , itemList: []
  2937. };
  2938. if (data.startsWith('SM='))
  2939. {
  2940. loot.title = 'Boat';
  2941. loot.emptyText = 'Your boat found nothing.';
  2942. }
  2943. else if (data.startsWith(LOOT_MSG_PREFIX))
  2944. {
  2945. var split = data.substr(LOOT_MSG_PREFIX.length).split('~');
  2946. loot.title = split[0];
  2947. for (var i = 1; i < split.length; i += 2)
  2948. {
  2949. loot.itemList.push(
  2950. {
  2951. icon: split[i]
  2952. , text: split[i + 1]
  2953. });
  2954. }
  2955. }
  2956. log.add(loot);
  2957. return true;
  2958. }
  2959. var XP_GAIN_REGEX = /^ST=([^~]+)\.png~([^~]+)~\+(\d+)\s*xp(.*)$/;
  2960. var animationQueue = {};
  2961.  
  2962. function queueXpAnimation(skill, cell, color, xpAmount, extraXp)
  2963. {
  2964. if (!settings.get(settings.KEY.newXpAnimation))
  2965. {
  2966. return;
  2967. }
  2968. animationQueue[skill] = animationQueue[skill] || [];
  2969. animationQueue[skill].push(
  2970. {
  2971. cell: cell
  2972. , color: color
  2973. , xpAmount: xpAmount
  2974. , extraXp: extraXp
  2975. });
  2976. if (animationQueue[skill].length === 1)
  2977. {
  2978. nextAnimation(skill);
  2979. }
  2980. }
  2981.  
  2982. function nextAnimation(skill)
  2983. {
  2984. var entry = animationQueue[skill][0];
  2985. if (!entry || !settings.get(settings.KEY.newXpAnimation))
  2986. {
  2987. return;
  2988. }
  2989. var cell = entry.cell
  2990. , color = entry.color
  2991. , xpAmount = entry.xpAmount
  2992. , extraXp = entry.extraXp;
  2993. var rect = cell.getBoundingClientRect();
  2994. var extraXpStr = extraXp > 0 ? " (+" + extraXp + ")" : '';
  2995. 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>")
  2996. .appendTo('body');
  2997. // ensure the existence of $el, so the complete-function can be called instantly if the window is hidden
  2998. $el
  2999. .animate(
  3000. {
  3001. top: '-=15px'
  3002. }
  3003. , {
  3004. duration: 1500
  3005. , easing: 'easeOutQuad'
  3006. , complete: function ()
  3007. {
  3008. animationQueue[skill].shift();
  3009. nextAnimation(skill);
  3010. }
  3011. })
  3012. .fadeOut(
  3013. {
  3014. duration: 2500
  3015. , queue: false
  3016. , complete: function ()
  3017. {
  3018. return $el.remove();
  3019. }
  3020. });
  3021. }
  3022.  
  3023. function processXpGain(data)
  3024. {
  3025. var match = data.match(XP_GAIN_REGEX);
  3026. if (!match)
  3027. {
  3028. return false;
  3029. }
  3030. var icon = match[1];
  3031. var skill = IMAGE2SKILL[icon] || '';
  3032. var color = match[2];
  3033. var xpAmount = Number(match[3]);
  3034. var extra = match[4];
  3035. var cell = document.getElementById('top-bar-level-td-' + skill);
  3036. if (!cell)
  3037. {
  3038. console.debug('match (no cell found):', match);
  3039. return false;
  3040. }
  3041. var entry = {
  3042. time: now()
  3043. , amount: xpAmount
  3044. };
  3045. if (match[4])
  3046. {
  3047. entry.extra = match[4];
  3048. }
  3049. if (skill == 'fishing')
  3050. {
  3051. log.processFishingXpChange(xpAmount);
  3052. }
  3053. var extraXp = 0;
  3054. if (extra && settings.get(settings.KEY.newXpAnimation))
  3055. {
  3056. var extraMatch = extra.match(/^\s*\(<img[^>]+src=(['"])images\/([^']+)\.png\1[^>]+>\s*(.+)\)$/);
  3057. var extraXpMatch = extra.match(/^\s*\(\+(\d+)\s*xp\)\s*$/);
  3058. if (extraMatch)
  3059. {
  3060. var icon_1 = extraMatch[2];
  3061. var text = extraMatch[3];
  3062. if (icon_1 == 'brewingKit')
  3063. {
  3064. text = '+' + text;
  3065. }
  3066. win.scrollText(icon_1, color, text);
  3067. }
  3068. else if (extraXpMatch)
  3069. {
  3070. extraXp = Number(extraXpMatch[1]);
  3071. }
  3072. else
  3073. {
  3074. win.scrollText('none', color, extra);
  3075. }
  3076. }
  3077. // save the xp event
  3078. var list = xpGainHistory[skill] || [];
  3079. list.push(entry);
  3080. xpGainHistory[skill] = list.slice(-MAX_XP_GAIN_HISTORY_LENGTH);
  3081. store.set(XP_GAIN_KEY, xpGainHistory);
  3082. if (settings.get(settings.KEY.newXpAnimation))
  3083. {
  3084. queueXpAnimation(skill, cell, color, xpAmount, extraXp);
  3085. }
  3086. return true;
  3087. }
  3088.  
  3089. function processLevelUp(data)
  3090. {
  3091. if (!data.startsWith('LVL_UP='))
  3092. {
  3093. return false;
  3094. }
  3095. var skill = data.substr('LVL_UP='.length);
  3096. var xp = getGameValue(skill + 'Xp');
  3097. var oldLvl = win.getLevel(xp);
  3098. log.add(
  3099. {
  3100. type: 'lvlup'
  3101. , skill: skill
  3102. , newLevel: oldLvl + 1
  3103. });
  3104. return true;
  3105. }
  3106.  
  3107. function processCombat(data)
  3108. {
  3109. var match = data.match(/^STHS=([^~]+)~([^~]+)~([^~]+)~img-(.+)~(melee|heal)$/);
  3110. if (!match)
  3111. {
  3112. return false;
  3113. }
  3114. // keep track of different battles and add the data to the current battle
  3115. var number = match[3];
  3116. if (!/\D/.test(number))
  3117. {
  3118. number = Number(number);
  3119. }
  3120. log.add(
  3121. {
  3122. type: 'combat'
  3123. , what: match[5]
  3124. , who: match[4]
  3125. , text: number
  3126. });
  3127. return true;
  3128. }
  3129.  
  3130. function processEnergy(data)
  3131. {
  3132. var match = data.match(/^ST=steak\.png~orange~\+([\d',]+)$/);
  3133. if (!match)
  3134. {
  3135. return false;
  3136. }
  3137. log.add(
  3138. {
  3139. type: 'energy'
  3140. , energy: Number(match[1].replace(/\D/g, ''))
  3141. });
  3142. return true;
  3143. }
  3144.  
  3145. function processHeat(data)
  3146. {
  3147. var match = data.match(/^ST=icons\/fire\.png~red~\+([\d',]+)$/);
  3148. if (!match)
  3149. {
  3150. return false;
  3151. }
  3152. log.add(
  3153. {
  3154. type: 'heat'
  3155. , heat: Number(match[1].replace(/\D/g, ''))
  3156. });
  3157. return true;
  3158. }
  3159.  
  3160. function processMarket(data)
  3161. {
  3162. if (data === 'ST=icons/shop.png~orange~Item Purchased')
  3163. {
  3164. log.add(
  3165. {
  3166. type: 'market'
  3167. });
  3168. return true;
  3169. }
  3170. var match = data.match(/^ST=coins\.png~yellow~\+([\d',]+)$/);
  3171. if (!match)
  3172. {
  3173. return false;
  3174. }
  3175. var coins = Number(match[1].replace(/\D/g, ''));
  3176. log.add(
  3177. {
  3178. type: 'market'
  3179. , coins: coins
  3180. });
  3181. return true;
  3182. }
  3183.  
  3184. function processBonemeal(data)
  3185. {
  3186. var match = data.match(/^ST=filledBonemealBin\.png~white~\+([\d',]+)$/);
  3187. if (!match)
  3188. {
  3189. return false;
  3190. }
  3191. var bonemeal = Number(match[1].replace(/\D/g, ''));
  3192. log.add(
  3193. {
  3194. type: 'bonemeal'
  3195. , bonemeal: bonemeal
  3196. });
  3197. return true;
  3198. }
  3199.  
  3200. function processCrafting(data)
  3201. {
  3202. if (data === 'ST=none~#806600~Item Crafted')
  3203. {
  3204. log.add(
  3205. {
  3206. type: 'crafting'
  3207. });
  3208. return true;
  3209. }
  3210. return false;
  3211. }
  3212.  
  3213. function processStardust(data)
  3214. {
  3215. var match = data.match(/^ST=(?:icons\/)?stardust\.png~yellow~\+([\d',]+)$/);
  3216. if (!match)
  3217. {
  3218. return false;
  3219. }
  3220. var stardust = Number(match[1].replace(/\D/g, ''));
  3221. log.add(
  3222. {
  3223. type: 'stardust'
  3224. , stardust: stardust
  3225. });
  3226. return true;
  3227. }
  3228. var RUNNING_ACCOUNT_STR = 'Your account has been running for:';
  3229.  
  3230. function formatData(data)
  3231. {
  3232. if (data.startsWith('STHS=')
  3233. || data.startsWith('STE=')
  3234. || data.startsWith('SM=')
  3235. || data.startsWith('ST=')
  3236. || data.startsWith('SHOW_LOOT_DIAG='))
  3237. {
  3238. if (data.indexOf(RUNNING_ACCOUNT_STR) != -1)
  3239. {
  3240. data = minutes2String(data);
  3241. }
  3242. data = format.numbersInText(data);
  3243. }
  3244. return data;
  3245. }
  3246. commands.formatData = formatData;
  3247.  
  3248. function process(data)
  3249. {
  3250. // prepare for logging events in an activity log
  3251. if (processLoot(data))
  3252. {
  3253. return;
  3254. }
  3255. else if (processXpGain(data))
  3256. {
  3257. // return undefined to let the original function be called
  3258. return settings.get(settings.KEY.newXpAnimation) ? null : void 0;
  3259. }
  3260. else if (processLevelUp(data)
  3261. || processCombat(data)
  3262. || processEnergy(data)
  3263. || processHeat(data)
  3264. || processMarket(data)
  3265. || processBonemeal(data)
  3266. || processCrafting(data)
  3267. || processStardust(data))
  3268. {
  3269. return;
  3270. }
  3271. else if (data.startsWith('SM='))
  3272. {
  3273. log.add(
  3274. {
  3275. data: minutes2String(data.replace(/^[^=]+=/, ''))
  3276. });
  3277. }
  3278. else if (data.startsWith('STHS=') || data.startsWith('STE=') || data.startsWith('ST='))
  3279. {}
  3280. // notifications for this kind of message: "SM=An update has been scheduled for today."
  3281. if (data.startsWith('SM='))
  3282. {
  3283. if (settings.getSub(settings.KEY.showNotifications, 'serverMsg'))
  3284. {
  3285. var msg = data.substr(3)
  3286. .replace(/<br\s*\/?>/g, '\n')
  3287. .replace(/<img src='images\/(.+?)\.png'.+?\/?> (\d+)/g, function (wholeMatch, key, amount)
  3288. {
  3289. return format.number(amount) + ' ' + split2Words(key) + ', ';
  3290. })
  3291. .replace(/<.+?>/g, '')
  3292. .replace(/(\s)\1+/g, '$1')
  3293. .replace(/, $/, '');
  3294. notifications.event('Message from server'
  3295. , {
  3296. body: minutes2String(msg)
  3297. });
  3298. }
  3299. }
  3300. return;
  3301. }
  3302. commands.process = process;
  3303. })(commands || (commands = {}));
  3304.  
  3305. /**
  3306. * log activities and stuff
  3307. */
  3308. var log;
  3309. (function (log)
  3310. {
  3311. log.name = 'log';
  3312. var LOG_KEY = 'activityLog';
  3313. var MAX_LOG_SIZE = 100;
  3314. var logList = store.has(LOG_KEY) ? store.get(LOG_KEY) : [];
  3315. var currentCombat = null;
  3316. var currentCombatEl = null;
  3317. var LOG_FILTER = {
  3318. 'combat':
  3319. {
  3320. title: 'Combat'
  3321. , img: 'images/icons/combat.png'
  3322. }
  3323. , 'loot':
  3324. {
  3325. title: 'Loot'
  3326. , img: 'images/npcLoot0.png'
  3327. }
  3328. , 'fish':
  3329. {
  3330. title: 'Caught fish'
  3331. , img: 'images/tuna.png'
  3332. }
  3333. , 'skill':
  3334. {
  3335. title: 'Skill advance'
  3336. , img: 'images/icons/skills.png'
  3337. }
  3338. , 'other':
  3339. {
  3340. title: 'All other'
  3341. , label: 'Other'
  3342. }
  3343. };
  3344. var logEl;
  3345.  
  3346. function isFightStarted()
  3347. {
  3348. return win.fightMonsterId !== 0;
  3349. }
  3350.  
  3351. function saveLog()
  3352. {
  3353. store.set(LOG_KEY, logList);
  3354. }
  3355.  
  3356. function createLi(entry)
  3357. {
  3358. var entryEl = document.createElement('li');
  3359. entryEl.dataset.time = (new Date(entry.time || 0)).toLocaleString();
  3360. entryEl.dataset.type = entry.type;
  3361. return entryEl;
  3362. }
  3363.  
  3364. function appendLi(entryEl)
  3365. {
  3366. var filterEl = logEl.firstElementChild;
  3367. var next = filterEl && filterEl.nextElementSibling;
  3368. if (next)
  3369. {
  3370. logEl.insertBefore(entryEl, next);
  3371. }
  3372. else
  3373. {
  3374. logEl.appendChild(entryEl);
  3375. }
  3376. logEl.classList.remove('empty');
  3377. }
  3378.  
  3379. function setGenericEntry(entry, init)
  3380. {
  3381. var el = createLi(entry);
  3382. el.innerHTML = typeof entry.data === 'string' ? format.numbersInText(entry.data) : JSON.stringify(entry.data);
  3383. appendLi(el);
  3384. }
  3385. var chest = '';
  3386. function getChestType(){
  3387. $("#dialogue-chestmenu-open :input[type='image']").click(function(){
  3388. chest = 'Normal ';
  3389. });
  3390. $("#dialogue-promethiumChestmenu-open :input[type='image']").click(function(){
  3391. chest = 'Green ';
  3392. });
  3393. $("#dialogue-runiteChestmenu-open :input[type='image']").click(function(){
  3394. chest = 'Red ';
  3395. });
  3396. }
  3397. function setLootEntry(entry, init)
  3398. {
  3399. var el = createLi(entry);
  3400. var header = document.createElement('h1');
  3401. header.className = 'container-title';
  3402. header.textContent = entry.title;
  3403. el.appendChild(header);
  3404. var itemContainer = document.createElement('span');
  3405. if (entry.itemList.length === 0)
  3406. {
  3407. itemContainer.innerHTML = "<span class=\"dialogue-loot\">" + entry.emptyText + "</span>";
  3408. }
  3409. else
  3410. {
  3411. var update = false;
  3412. for (var _i = 0, _a = entry.itemList; _i < _a.length; _i++)
  3413. {
  3414. var item = _a[_i];
  3415. if (item.hasOwnProperty('key'))
  3416. {
  3417. item.icon = item.key;
  3418. delete item.key;
  3419. update = true;
  3420. }
  3421. if (item.hasOwnProperty('amount'))
  3422. {
  3423. item.text = (item.amount || Number.NaN).toString();
  3424. delete item.amount;
  3425. update = true;
  3426. }
  3427. var itemEl = document.createElement('span');
  3428. itemEl.className = 'dialogue-loot';
  3429. itemEl.innerHTML = "<img src=\"" + item.icon + "\" class=\"image-icon-50\"> " + format.numbersInText(item.text);
  3430. itemContainer.appendChild(itemEl);
  3431. itemContainer.appendChild(document.createTextNode(' '));
  3432. }
  3433. // Chest loot:
  3434. if (entry.title == "Chest loot:"){
  3435. header.textContent = chest + "Chest loot:";
  3436. }
  3437.  
  3438. if (update)
  3439. {
  3440. saveLog();
  3441. }
  3442. }
  3443. el.appendChild(itemContainer);
  3444. var valueContainer = document.createElement('div');
  3445. valueContainer.className = 'total-value';
  3446. valueContainer.appendChild(document.createTextNode('Total value: '));
  3447. var totalValue = document.createElement('span');
  3448. totalValue.style.cursor = 'pointer';
  3449. totalValue.textContent = 'Click to calculate';
  3450. valueContainer.appendChild(totalValue);
  3451. totalValue.addEventListener('click', function ()
  3452. {
  3453. var items = {};
  3454. for (var _i = 0, _a = entry.itemList; _i < _a.length; _i++)
  3455. {
  3456. var item = _a[_i];
  3457. if (item.text.indexOf('xp') === -1)
  3458. {
  3459. var key = item.icon.replace(/^.+\/([^\/]+)\.png$/, '$1');
  3460. var num = Number(item.text.replace(/\D/g, ''));
  3461. items[key] = (items[key] || 0) + num;
  3462. }
  3463. }
  3464. market.calcMarketValue(items)
  3465. .then(function (sum)
  3466. {
  3467. 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]);
  3468. });
  3469. });
  3470. el.appendChild(valueContainer);
  3471. appendLi(el);
  3472. }
  3473.  
  3474. function setFishEntry(entry, init)
  3475. {
  3476. var el = createLi(entry);
  3477. el.innerHTML = "You caught a " + key2Name(entry.fish, true) + ".";
  3478. appendLi(el);
  3479. }
  3480.  
  3481. function setEnergyEntry(entry, init)
  3482. {
  3483. var el = createLi(entry);
  3484. el.innerHTML = "Your hero gained " + format.number(entry.energy) + " energy.";
  3485. appendLi(el);
  3486. }
  3487.  
  3488. function setHeatEntry(entry, init)
  3489. {
  3490. var el = createLi(entry);
  3491. el.innerHTML = "You added " + format.number(entry.heat) + " heat to your oven.";
  3492. appendLi(el);
  3493. }
  3494.  
  3495. function setLevelUpEntry(entry, init)
  3496. {
  3497. var el = createLi(entry);
  3498. el.innerHTML = "You advanced your " + entry.skill + " skill to level " + entry.newLevel + ".";
  3499. appendLi(el);
  3500. }
  3501.  
  3502. function getCombatInfo(data, initHp, scaleX, width)
  3503. {
  3504. var points = [];
  3505. var startHp = -1;
  3506. var hp = initHp;
  3507. for (var tick in data)
  3508. {
  3509. hp = data[tick];
  3510. if (startHp === -1)
  3511. {
  3512. startHp = hp;
  3513. }
  3514. points.push((scaleX * Number(tick)) + ' ' + hp);
  3515. }
  3516. if (points.length === 0)
  3517. {
  3518. points.push('0 ' + initHp);
  3519. }
  3520. points.push(width + ' ' + hp, width + ' 0', '0 0');
  3521. return {
  3522. points: points
  3523. , startHp: startHp === -1 ? initHp : startHp
  3524. , endHp: hp
  3525. };
  3526. }
  3527.  
  3528. function getHTMLFromCombatInfo(info, name)
  3529. {
  3530. 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>";
  3531. }
  3532.  
  3533. function setCombatEntry(entry, init)
  3534. {
  3535. var created = init || currentCombatEl == null;
  3536. if (init || currentCombatEl == null)
  3537. {
  3538. currentCombatEl = createLi(entry);
  3539. }
  3540. var HTML = '';
  3541. // support old log format
  3542. if (!entry.hasOwnProperty('ticks'))
  3543. {
  3544. var info = {
  3545. hero:
  3546. {
  3547. heal: 0
  3548. , melee: 0
  3549. }
  3550. , monster:
  3551. {
  3552. heal: 0
  3553. , melee: 0
  3554. }
  3555. };
  3556. for (var i = 0; i < entry.parts.length; i++)
  3557. {
  3558. var part = entry.parts[i];
  3559. info[part.who][part.type] += part.number;
  3560. }
  3561. 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>";
  3562. }
  3563. else
  3564. {
  3565. var currentTick = Math.max(entry.ticks, 0);
  3566. var width = logEl.scrollWidth - 4 * 12.8 - 2;
  3567. var scaleX = currentTick === 0 ? 0 : width / currentTick;
  3568. var hero = getCombatInfo(entry.hero, win.heroHp, scaleX, width);
  3569. var monster = getCombatInfo(entry.monster, win.fightMonsterHp, scaleX, width);
  3570. // TODO: who won?
  3571. 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";
  3572. }
  3573. // map monster name and area name from monster id (the ids are starting at 1)
  3574. var isShiny = entry.monsterId > 1e3;
  3575. var mId = entry.monsterId - (isShiny ? 1001 : 1);
  3576. var monsterName = (isShiny ? 'Shiny ' : '') + (getMonsterName(mId) || '(' + (mId % 3 + 1) + ')');
  3577. var areaId = (mId == 105 || mId == 106) ? 34 : Math.floor(mId / 3);
  3578. var areaName = getAreaName(areaId) || '(' + (areaId + 1) + ')';
  3579. currentCombatEl.innerHTML = "<h2>Combat against " + monsterName + " in " + areaName + "</h2>\n\t\t" + HTML;
  3580. if (created)
  3581. {
  3582. appendLi(currentCombatEl);
  3583. }
  3584. if (!isFightStarted())
  3585. {
  3586. currentCombatEl = null;
  3587. }
  3588. }
  3589.  
  3590. function setMarketEntry(entry, init)
  3591. {
  3592. var el = createLi(entry);
  3593. if (entry.coins)
  3594. {
  3595. el.innerHTML = "You collected " + format.number(entry.coins) + " from market.";
  3596. }
  3597. else
  3598. {
  3599. el.innerHTML = "You purchased an item on market.";
  3600. }
  3601. appendLi(el);
  3602. }
  3603.  
  3604. function setBonemealEntry(entry, init)
  3605. {
  3606. var el = createLi(entry);
  3607. el.innerHTML = "You added " + format.number(entry.bonemeal) + " bonemeal to your bonemeal bin.";
  3608. appendLi(el);
  3609. }
  3610.  
  3611. function setCraftingEntry(entry, init)
  3612. {
  3613. var el = createLi(entry);
  3614. el.innerHTML = "You crafted an item.";
  3615. appendLi(el);
  3616. }
  3617.  
  3618. function setStardustEntry(entry, init)
  3619. {
  3620. var el = createLi(entry);
  3621. el.innerHTML = "You got " + format.number(entry.stardust) + " stardust.";
  3622. appendLi(el);
  3623. }
  3624. var entryType2Fn = {
  3625. 'loot': setLootEntry
  3626. , 'fish': setFishEntry
  3627. , 'energy': setEnergyEntry
  3628. , 'heat': setHeatEntry
  3629. , 'lvlup': setLevelUpEntry
  3630. , 'combat': setCombatEntry
  3631. , 'market': setMarketEntry
  3632. , 'bonemeal': setBonemealEntry
  3633. , 'crafting': setCraftingEntry
  3634. , 'stardust': setStardustEntry
  3635. };
  3636.  
  3637. function updateLog(entry, init)
  3638. {
  3639. if (init === void 0)
  3640. {
  3641. init = false;
  3642. }
  3643. if (!logEl)
  3644. {
  3645. return;
  3646. }
  3647. if (entry.type && entryType2Fn.hasOwnProperty(entry.type))
  3648. {
  3649. entryType2Fn[entry.type](entry, init);
  3650. }
  3651. else
  3652. {
  3653. setGenericEntry(entry, init);
  3654. }
  3655. }
  3656.  
  3657. function add2Log(entry)
  3658. {
  3659. logList.push(entry);
  3660. logList = logList.slice(-MAX_LOG_SIZE);
  3661. saveLog();
  3662. }
  3663. // 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
  3664. function findCurrentCombat()
  3665. {
  3666. for (var i = logList.length - 1; i >= 0; i--)
  3667. {
  3668. if (logList[i].type == 'combat')
  3669. {
  3670. var entry = logList[i];
  3671. if (entry.monsterId == win.fightMonsterId
  3672. && entry.hero[entry.ticks] !== 0
  3673. && entry.hero[entry.ticks] !== 0)
  3674. {
  3675. return entry;
  3676. }
  3677. break;
  3678. }
  3679. }
  3680. return null;
  3681. }
  3682.  
  3683. function add(entry)
  3684. {
  3685. if (!entry.time)
  3686. {
  3687. entry.time = now();
  3688. }
  3689. if (entry.type == 'combat')
  3690. {
  3691. currentCombat = currentCombat || findCurrentCombat();
  3692. if (!currentCombat)
  3693. {
  3694. return;
  3695. }
  3696. // skip entries without further information
  3697. if (typeof entry.text !== 'number' || entry.text === 0)
  3698. {
  3699. return;
  3700. }
  3701. var hp = entry.who == 'hero' ? win.heroHp : win.fightMonsterHp;
  3702. // the hp values are updated after this event, so I have to calculate the new value by myself
  3703. hp += (entry.what == 'heal' ? 1 : -1) * entry.text;
  3704. currentCombat[entry.who][currentCombat.ticks] = hp;
  3705. saveLog();
  3706. updateLog(currentCombat);
  3707. }
  3708. else
  3709. {
  3710. add2Log(entry);
  3711. updateLog(entry);
  3712. }
  3713. }
  3714. log.add = add;
  3715.  
  3716. function addLogEl()
  3717. {
  3718. 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");
  3719. // add new tab "Activity Log"
  3720. var checkboxId = 'show-activity-log';
  3721. var activityLogLabel = document.createElement('label');
  3722. activityLogLabel.id = 'activity-log-label';
  3723. activityLogLabel.htmlFor = checkboxId;
  3724. activityLogLabel.textContent = 'Activity Log';
  3725. newTopbar.addTabEntry(activityLogLabel);
  3726. var checkbox = document.createElement('input');
  3727. checkbox.id = checkboxId;
  3728. checkbox.type = 'checkbox';
  3729. checkbox.style.display = 'none';
  3730. document.body.insertBefore(checkbox, document.body.firstChild);
  3731. var label = document.createElement('label');
  3732. label.id = 'activity-log-overlay';
  3733. label.htmlFor = checkboxId;
  3734. document.body.appendChild(label);
  3735. logEl = document.createElement('ul');
  3736. logEl.id = 'activity-log';
  3737. var classList = [];
  3738. var html = '';
  3739. for (var key in LOG_FILTER)
  3740. {
  3741. // TODO: load saved filter
  3742. var checked = true;
  3743. classList.push(key);
  3744. 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' : '') + ">";
  3745. }
  3746. logEl.className = 'empty ' + classList.join(' ');
  3747. logEl.innerHTML = "<li class=\"filter\">\n\t\t\t" + html + "\n\t\t</li>";
  3748. document.body.appendChild(logEl);
  3749. var $checkboxes = win.$('li.filter > input[id^="log-filter-"]');
  3750. $checkboxes.checkboxradio(
  3751. {
  3752. icon: false
  3753. });
  3754. $checkboxes.change(function (event)
  3755. {
  3756. var id = event.target.id;
  3757. var key = id.replace('log-filter-', '');
  3758. var checked = document.getElementById(id).checked;
  3759. logEl.classList[checked ? 'add' : 'remove'](key);
  3760. // TODO: save current state
  3761. });
  3762. // add all stored elements
  3763. logList.forEach(function (e)
  3764. {
  3765. return updateLog(e, true);
  3766. });
  3767. }
  3768.  
  3769. function observeCombat()
  3770. {
  3771. observer.add('fightMonsterId', function (key, oldValue, newValue)
  3772. {
  3773. if (isFightStarted())
  3774. {
  3775. currentCombat = {
  3776. type: 'combat'
  3777. , time: now()
  3778. , monsterId: newValue
  3779. , ticks: -5
  3780. , hero:
  3781. {}
  3782. , monster:
  3783. {}
  3784. };
  3785. add2Log(currentCombat);
  3786. updateLog(currentCombat);
  3787. }
  3788. else
  3789. {
  3790. if (currentCombat)
  3791. {
  3792. currentCombat.ticks--;
  3793. saveLog();
  3794. }
  3795. currentCombat = null;
  3796. currentCombatEl = null;
  3797. }
  3798. });
  3799. observer.addTick(function ()
  3800. {
  3801. if (currentCombat !== null)
  3802. {
  3803. currentCombat.ticks++;
  3804. if (currentCombat.ticks === 0)
  3805. {
  3806. currentCombat.hero[0] = win.heroHp;
  3807. currentCombat.monster[0] = win.fightMonsterHp;
  3808. }
  3809. updateLog(currentCombat);
  3810. }
  3811. });
  3812. }
  3813. var possiblyCaughtFish;
  3814. var lastFishingXpChange = 0;
  3815.  
  3816. function fishObserver(key, oldValue, newValue)
  3817. {
  3818. if (oldValue < newValue && lastFishingXpChange >= now() - 5e3)
  3819. {
  3820. var idx = possiblyCaughtFish.indexOf(key);
  3821. if (idx !== -1)
  3822. {
  3823. add(
  3824. {
  3825. type: 'fish'
  3826. , fish: key
  3827. });
  3828. possiblyCaughtFish = [];
  3829. lastFishingXpChange = 0;
  3830. }
  3831. }
  3832. }
  3833.  
  3834. function processFishingXpChange(xp)
  3835. {
  3836. lastFishingXpChange = now();
  3837. possiblyCaughtFish = [];
  3838. for (var fish in FISH_XP)
  3839. {
  3840. if (FISH_XP[fish] == xp)
  3841. {
  3842. possiblyCaughtFish.push(fish);
  3843. }
  3844. }
  3845. }
  3846. log.processFishingXpChange = processFishingXpChange;
  3847.  
  3848. function observeFishing()
  3849. {
  3850. for (var fish in FISH_XP)
  3851. {
  3852. observer.add(fish, fishObserver);
  3853. }
  3854. }
  3855.  
  3856. function init()
  3857. {
  3858. getChestType();
  3859. addLogEl();
  3860. observeCombat();
  3861. observeFishing();
  3862. }
  3863. log.init = init;
  3864. })(log || (log = {}));
  3865.  
  3866. /**
  3867. * game events
  3868. */
  3869. var gameEvents;
  3870. (function (gameEvents)
  3871. {
  3872. gameEvents.name = 'gameEvents';
  3873. // min time difference between two notifications with the same title (10 seconds)
  3874. var MIN_TIME_DIFFERENCE = 10;
  3875. gameEvents.enabled = {
  3876. smelting: true
  3877. , chopping: true
  3878. , harvest: true
  3879. , boat: true
  3880. , battle: true
  3881. , brewing: true
  3882. , market: true
  3883. , map: true
  3884. //, essence: true
  3885. , rocket: true
  3886. , wind: true
  3887. , perk: true
  3888. };
  3889. var lastTimestamp = new Map();
  3890.  
  3891. function notifyTabClickable(title, body, icon, tabKey, whenActive)
  3892. {
  3893. if (whenActive === void 0)
  3894. {
  3895. whenActive = false;
  3896. }
  3897. var now = (new Date).getTime();
  3898. var timeDiff = now - (lastTimestamp.get(title) || 0);
  3899. if (timeDiff < MIN_TIME_DIFFERENCE * 1e3)
  3900. {
  3901. return;
  3902. }
  3903. var promise = notifications.event(title
  3904. , {
  3905. body: body
  3906. , icon: 'images/' + icon
  3907. , whenActive: whenActive
  3908. , onclick: function ()
  3909. {
  3910. var tabNames = tabKey.split('.');
  3911. win.openTab(tabNames[0]);
  3912. if (tabNames.length > 1)
  3913. {
  3914. win.openSubTab(tabNames[1]);
  3915. }
  3916. }
  3917. });
  3918. if (promise)
  3919. {
  3920. lastTimestamp.set(title, now);
  3921. }
  3922. }
  3923.  
  3924. function observeTimer(k, fn)
  3925. {
  3926. observer.add(k, function (key, oldValue, newValue)
  3927. {
  3928. if (oldValue > 0 && newValue == 0)
  3929. {
  3930. fn(key, oldValue, newValue);
  3931. }
  3932. });
  3933. }
  3934.  
  3935. function smelting()
  3936. {
  3937. observeTimer('smeltingPercD', function (key, oldValue, newValue)
  3938. {
  3939. if (!gameEvents.enabled.smelting || !settings.getSub(settings.KEY.showNotifications, 'smelting'))
  3940. {
  3941. return;
  3942. }
  3943. notifyTabClickable('Hot topic', 'Your smelting has finished.', getFurnaceLevelName() + 'Furnace.png', 'crafting');
  3944. });
  3945. }
  3946.  
  3947. function chopping()
  3948. {
  3949. observer.add([
  3950. 'treeStage1'
  3951. , 'treeStage2'
  3952. , 'treeStage3'
  3953. , 'treeStage4'
  3954. , 'treeStage5'
  3955. , 'treeStage6'
  3956. ], function (key, oldValue, newValue)
  3957. {
  3958. if (!gameEvents.enabled.chopping || !settings.getSub(settings.KEY.showNotifications, 'chopping'))
  3959. {
  3960. return;
  3961. }
  3962. if (newValue == 4)
  3963. {
  3964. notifyTabClickable('Wood you be mine?', 'One or more of your trees are fully grown and can be chopped.', 'icons/woodcutting.png', 'woodcutting');
  3965. }
  3966. });
  3967. }
  3968.  
  3969. function harvest()
  3970. {
  3971. observer.add([
  3972. 'farmingPatchStage1'
  3973. , 'farmingPatchStage2'
  3974. , 'farmingPatchStage3'
  3975. , 'farmingPatchStage4'
  3976. , 'farmingPatchStage5'
  3977. , 'farmingPatchStage6'
  3978. ], function (key, oldValue, newValue)
  3979. {
  3980. if (!gameEvents.enabled.harvest || !settings.getSub(settings.KEY.showNotifications, 'harvest'))
  3981. {
  3982. return;
  3983. }
  3984. if (newValue == 4)
  3985. {
  3986. notifyTabClickable('Green thumb', 'One or more of your crops is ready for harvest.', 'icons/watering-can.png', 'farming');
  3987. }
  3988. else if (newValue > 4)
  3989. {
  3990. notifyTabClickable('I didn\'t plant this', 'One or more of your crops died.', 'icons/watering-can.png', 'farming');
  3991. }
  3992. });
  3993. }
  3994.  
  3995. function boat()
  3996. {
  3997. var timerKeys = BOAT_LIST.map(function (boatKey)
  3998. {
  3999. return boatKey + 'Timer';
  4000. });
  4001. observeTimer(timerKeys, function (key, oldValue, newValue)
  4002. {
  4003. if (!gameEvents.enabled.boat || !settings.getSub(settings.KEY.showNotifications, 'boatReturned'))
  4004. {
  4005. return;
  4006. }
  4007. var boatKey = key.replace(/Timer$/, '');
  4008. notifyTabClickable('Fishy business', 'Your ' + split2Words(boatKey).toLowerCase() + ' returned from its trip.', boatKey + '.png',
  4009. (win.profileCookingTab)? 'cooking' : 'combat');
  4010. });
  4011. }
  4012.  
  4013. function battle()
  4014. {
  4015. observeTimer('combatGlobalCooldown', function (key, oldValue, newValue)
  4016. {
  4017. if (!gameEvents.enabled.battle || !settings.getSub(settings.KEY.showNotifications, 'heroReady'))
  4018. {
  4019. return;
  4020. }
  4021. notifyTabClickable('Ready to work', 'Your hero is eager to fight.', 'icons/combat.png', 'combat');
  4022. });
  4023. }
  4024.  
  4025. function brewing()
  4026. {
  4027. observeTimer([
  4028. 'barPotionTimer'
  4029. , 'seedPotionTimer'
  4030. , 'stardustPotionTimer'
  4031. , 'superStardustPotionTimer'
  4032. ], function (key, oldValue, newValue)
  4033. {
  4034. if (!gameEvents.enabled.brewing || !settings.getSub(settings.KEY.showNotifications, 'potionEffect'))
  4035. {
  4036. return;
  4037. }
  4038. var potionKey = key.replace(/Timer$/, '');
  4039. if (getGameValue(potionKey) > 0)
  4040. {
  4041. notifyTabClickable('Cheers!', 'You can drink another ' + split2Words(potionKey) + '.', key.replace(/Timer$/, '') + '.png', 'brewing');
  4042. }
  4043. });
  4044. }
  4045.  
  4046. function market()
  4047. {
  4048. var _refreshMarketSlot = win.refreshMarketSlot;
  4049. var lastCollectText = 0;
  4050. win.refreshMarketSlot = function (offerId, itemKey, amount, price, collectText, slotId, timeLeft)
  4051. {
  4052. var diff = collectText - lastCollectText;
  4053. lastCollectText = collectText;
  4054. if (gameEvents.enabled.market && settings.getSub(settings.KEY.showNotifications, 'itemsSold') && collectText > 0)
  4055. {
  4056. var soldAmount = diff / price;
  4057. var amountText = ['one (1)', 'two (2)', 'three (3)'][soldAmount - 1] || format.number(soldAmount);
  4058. var itemName = split2Words(itemKey).toLowerCase();
  4059. if (soldAmount > 1)
  4060. {
  4061. itemName = pluralize(itemName);
  4062. }
  4063. var textTemplate = function (itemText)
  4064. {
  4065. return "You've sold " + itemText + " to the market.";
  4066. };
  4067. if (amount > 0)
  4068. {
  4069. notifyTabClickable('Ka-ching', textTemplate(amountText + ' ' + itemName), 'icons/shop.png', 'playermarket');
  4070. }
  4071. else
  4072. {
  4073. notifyTabClickable('Sold out', textTemplate((soldAmount === 1 ? 'your' : 'all') + ' ' + amountText + ' ' + itemName), 'icons/shop.png', 'playermarket');
  4074. }
  4075. }
  4076. _refreshMarketSlot(offerId, itemKey, amount, price, collectText, slotId, timeLeft);
  4077. };
  4078. }
  4079.  
  4080. function gameValues()
  4081. {
  4082. observer.add('treasureMap', function (key, oldValue, newValue)
  4083. {
  4084. if (gameEvents.enabled.map && settings.getSub(settings.KEY.showNotifications, 'pirate') && oldValue < newValue)
  4085. {
  4086. notifyTabClickable('Arrrr!', 'Your pirate found a treasure map.', 'treasureMap.png', 'items');
  4087. }
  4088. });
  4089. observer.add('rocketMoonId', function (key, oldValue, newValue)
  4090. {
  4091. if (gameEvents.enabled.rocket && settings.getSub(settings.KEY.showNotifications, 'rocket'))
  4092. {
  4093. if (newValue > 0)
  4094. {
  4095. notifyTabClickable('One small step for a man...', 'Your rocket landed on the moon.', 'rocket.png', 'mining');
  4096. }
  4097. else if (oldValue < 0 && newValue === 0)
  4098. {
  4099. notifyTabClickable('Back home', 'Your rocket returned to earth.', 'rocket.png', 'mining');
  4100. }
  4101. }
  4102. });
  4103. var WIND_DESCRIPTION = [
  4104. 'The sea is sleeping like a baby'
  4105. , 'There is a slight breeze'
  4106. , 'A normal day on the sea'
  4107. , 'There is a storm coming'
  4108. , 'The sea is raging'
  4109. ];
  4110. var WIND_CATEGORY = ['none', 'low', 'medium', 'high', 'very high'];
  4111. var _setSailBoatWind = win.setSailBoatWind;
  4112. var oldValue = -1;
  4113. win.setSailBoatWind = function (windLevel)
  4114. {
  4115. _setSailBoatWind(windLevel);
  4116. var newValue = win.sailBoatWindGlobal;
  4117. if (oldValue !== -1
  4118. && oldValue !== newValue
  4119. && win.boundSailBoat > 0
  4120. && gameEvents.enabled.wind
  4121. && settings.getSub(settings.KEY.showNotifications, 'wind'))
  4122. {
  4123. var windText = (WIND_DESCRIPTION[win.sailBoatWindGlobal] || 'The wind is turning')
  4124. + ' (' + (WIND_CATEGORY[win.sailBoatWindGlobal] || 'level ' + win.sailBoatWindGlobal) + ' wind).';
  4125. notifyTabClickable('Wind of change', windText, 'sailBoat.png', 'combat');
  4126. }
  4127. oldValue = newValue;
  4128. };
  4129. // trigger getting the wind level once at page load
  4130. // so the script can distinguish between getting the wind initially and an actual wind change
  4131. win.processTab('combat');
  4132. // achievements (e.g. achBrewingEasyCompleted)
  4133. var achRegex = /^ach([A-Z][a-z]+)([A-Z][a-z]+)Completed$/;
  4134.  
  4135. function checkAchievement(key, oldValue, newValue)
  4136. {
  4137. if (gameEvents.enabled.perk && settings.getSub(settings.KEY.showNotifications, 'perk') && oldValue < newValue)
  4138. {
  4139. var match = key.match(/^ach([A-Z][a-z]+)([A-Z][a-z]+)Completed$/);
  4140. var skillName = match[1].toLowerCase();
  4141. var difficulty = match[2].toLowerCase();
  4142. notifyTabClickable('New perk unlocked', 'You completed the ' + difficulty + ' ' + skillName + ' achievement set.', 'achievementBook.png', 'achievements');
  4143. }
  4144. }
  4145. for (var _i = 0, _a = win.jsItemArray; _i < _a.length; _i++)
  4146. {
  4147. var key = _a[_i];
  4148. if (achRegex.test(key))
  4149. {
  4150. observer.add(key, checkAchievement);
  4151. }
  4152. }
  4153. var stardustEl = document.querySelector('span[data-item-display="stardust"]');
  4154. var parent = stardustEl && stardustEl.parentElement;
  4155. if (stardustEl && parent)
  4156. {
  4157. 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");
  4158. var changeEl_1 = document.createElement('span');
  4159. changeEl_1.className = 'hide';
  4160. changeEl_1.id = 'stardust-change';
  4161. parent.appendChild(changeEl_1);
  4162. var HIDE_AFTER_TICKS_1 = 5;
  4163. var ticksSinceSdChange_1 = HIDE_AFTER_TICKS_1;
  4164. var sdDiff_1 = 0;
  4165. observer.add('stardust', function (key, oldValue, newValue)
  4166. {
  4167. sdDiff_1 = Math.max(newValue - oldValue, 0);
  4168. if (sdDiff_1 > 0)
  4169. {
  4170. ticksSinceSdChange_1 = 0;
  4171. }
  4172. });
  4173. observer.addTick(function ()
  4174. {
  4175. var show = settings.get(settings.KEY.showSdChange) && ticksSinceSdChange_1 < HIDE_AFTER_TICKS_1;
  4176. changeEl_1.classList[show ? 'remove' : 'add']('hide');
  4177. ticksSinceSdChange_1++;
  4178. var diff = ticksSinceSdChange_1 > 1 ? 0 : sdDiff_1;
  4179. var sign = diff > 0 ? '+' : PLUS_MINUS_SIGN;
  4180. changeEl_1.textContent = '(' + sign + format.number(diff) + ')';
  4181. });
  4182. }
  4183. }
  4184. function getAvgKMRocket(){
  4185. var arr = [];
  4186. var ticksSinceSdChange_1 = 5;
  4187. var sdDiff_1 = 0;
  4188. observer.add('rocketKm', function (key, oldValue, newValue)
  4189. {
  4190. sdDiff_1 = Math.max(newValue - oldValue, 0);
  4191. if (sdDiff_1 > 0)
  4192. {
  4193. ticksSinceSdChange_1 = 0;
  4194. }
  4195. });
  4196. observer.addTick(function (){
  4197. ticksSinceSdChange_1++;
  4198. var diff = ticksSinceSdChange_1 > 1 ? 0 : sdDiff_1;
  4199. arr.push(diff);
  4200. });
  4201. window.getrocketkm = function(){
  4202. var min = Math.min( ...arr);
  4203. var max = Math.max( ...arr);
  4204.  
  4205. console.log(min);
  4206. console.log(max);
  4207. };
  4208.  
  4209. }
  4210.  
  4211. function init()
  4212. {
  4213. smelting();
  4214. chopping();
  4215. harvest();
  4216. boat();
  4217. battle();
  4218. brewing();
  4219. market();
  4220. gameValues();
  4221. //getAvgKMRocket();
  4222. }
  4223. gameEvents.init = init;
  4224. })(gameEvents || (gameEvents = {}));
  4225.  
  4226. /**
  4227. * hide crafting recipes of lower tiers or of maxed machines
  4228. */
  4229. var crafting;
  4230. (function (crafting)
  4231. {
  4232. crafting.name = 'crafting';
  4233. /**
  4234. * hide crafted recipes
  4235. */
  4236. function setRecipeVisibility(key, visible)
  4237. {
  4238. var recipeRow = document.getElementById('crafting-' + key);
  4239. if (recipeRow)
  4240. {
  4241. recipeRow.style.display = (!settings.get(settings.KEY.hideCraftingRecipes) || visible) ? '' : 'none';
  4242. }
  4243. }
  4244.  
  4245. function hideLeveledRecipes(max, getKey, init)
  4246. {
  4247. if (init === void 0)
  4248. {
  4249. init = false;
  4250. }
  4251. var keys2Observe = [];
  4252. var maxLevel = 0;
  4253. for (var i = max - 1; i >= 0; i--)
  4254. {
  4255. var level = i + 1;
  4256. var key = getKey(i);
  4257. var boundKey = getBoundKey(key);
  4258. keys2Observe.push(key);
  4259. keys2Observe.push(boundKey);
  4260. if (getGameValue(key) > 0 || getGameValue(boundKey) > 0)
  4261. {
  4262. maxLevel = Math.max(maxLevel, level);
  4263. }
  4264. setRecipeVisibility(key, level > maxLevel);
  4265. }
  4266. if (init)
  4267. {
  4268. observer.add(keys2Observe, function ()
  4269. {
  4270. return hideLeveledRecipes(max, getKey, false);
  4271. });
  4272. }
  4273. }
  4274.  
  4275. function hideToolRecipe(key, init)
  4276. {
  4277. if (init === void 0)
  4278. {
  4279. init = false;
  4280. }
  4281. var emptyKey = getTierKey(key, 0);
  4282. var keys2Observe = [emptyKey];
  4283. var hasTool = getGameValue(emptyKey) > 0;
  4284. for (var i = 0; i < TIER_LEVELS.length; i++)
  4285. {
  4286. var boundKey = getBoundKey(getTierKey(key, i));
  4287. hasTool = hasTool || getGameValue(boundKey) > 0;
  4288. keys2Observe.push(boundKey);
  4289. }
  4290. setRecipeVisibility(emptyKey, !hasTool);
  4291. if (init)
  4292. {
  4293. observer.add(keys2Observe, function ()
  4294. {
  4295. return hideToolRecipe(key, false);
  4296. });
  4297. }
  4298. }
  4299.  
  4300. function hideRecipe(key, init)
  4301. {
  4302. if (init === void 0)
  4303. {
  4304. init = false;
  4305. }
  4306. var info = RECIPE_MAX.crafting[key];
  4307. var maxValue = typeof info.max === 'function' ? info.max() : info.max;
  4308. var boundKey = getBoundKey(key);
  4309. var unbound = getGameValue(key);
  4310. var bound = getGameValue(boundKey);
  4311. var extra = (info.extraKeys || []).map(function (k)
  4312. {
  4313. return getGameValue(k);
  4314. }).reduce(function (p, c)
  4315. {
  4316. return p + c;
  4317. }, 0);
  4318. setRecipeVisibility(key, maxValue - (bound + unbound + extra) > 0);
  4319. if (init)
  4320. {
  4321. observer.add([key, boundKey], function ()
  4322. {
  4323. return hideRecipe(key, false);
  4324. });
  4325. }
  4326. }
  4327. /**
  4328. * hide useless items
  4329. */
  4330. function setItemVisibility(key, visible)
  4331. {
  4332. var itemBox = document.getElementById('item-box-' + key);
  4333. if (itemBox)
  4334. {
  4335. itemBox.style.display = getGameValue(key) > 0 && (!settings.get(settings.KEY.hideUselessItems) || visible) ? '' : 'none';
  4336. }
  4337. }
  4338.  
  4339. function hideLeveledItems(max, getKey, init)
  4340. {
  4341. if (init === void 0)
  4342. {
  4343. init = false;
  4344. }
  4345. var keys2Observe = [];
  4346. var maxLevel = 0;
  4347. for (var i = max - 1; i >= 0; i--)
  4348. {
  4349. var level = i + 1;
  4350. var key = getKey(i);
  4351. var boundKey = getBoundKey(key);
  4352. keys2Observe.push(key);
  4353. keys2Observe.push(boundKey);
  4354. if (getGameValue(boundKey) > 0)
  4355. {
  4356. maxLevel = Math.max(maxLevel, level);
  4357. }
  4358. setItemVisibility(key, level > maxLevel);
  4359. }
  4360. if (init)
  4361. {
  4362. observer.add(keys2Observe, function ()
  4363. {
  4364. return hideLeveledItems(max, getKey, false);
  4365. });
  4366. }
  4367. }
  4368.  
  4369. function hideItem(key, hideInfo, init)
  4370. {
  4371. if (init === void 0)
  4372. {
  4373. init = false;
  4374. }
  4375. var maxValue = typeof hideInfo.max === 'function' ? hideInfo.max() : hideInfo.max;
  4376. var boundKey = getBoundKey(key);
  4377. var bound = getGameValue(boundKey);
  4378. var extra = (hideInfo.extraKeys || []).map(function (k)
  4379. {
  4380. return getGameValue(k);
  4381. }).reduce(function (p, c)
  4382. {
  4383. return p + c;
  4384. }, 0);
  4385. setItemVisibility(key, (bound + extra) < maxValue);
  4386. if (init)
  4387. {
  4388. observer.add([key, boundKey], function ()
  4389. {
  4390. return hideItem(key, hideInfo, false);
  4391. });
  4392. }
  4393. }
  4394.  
  4395. function init()
  4396. {
  4397. function processRecipes(init)
  4398. {
  4399. if (init === void 0)
  4400. {
  4401. init = false;
  4402. }
  4403. // furnace
  4404. hideLeveledRecipes(FURNACE_LEVELS.length, function (i)
  4405. {
  4406. return FURNACE_LEVELS[i] + 'Furnace';
  4407. }, init);
  4408. // oil storage
  4409. hideLeveledRecipes(OIL_STORAGE_SIZES.length, function (i)
  4410. {
  4411. return 'oilStorage' + (i + 1);
  4412. }, init);
  4413. // oven recipes
  4414. hideLeveledRecipes(OVEN_LEVELS.length, function (i)
  4415. {
  4416. return OVEN_LEVELS[i] + 'Oven';
  4417. }, init);
  4418. // tools
  4419. for (var _i = 0, TIER_ITEMS_1 = TIER_ITEMS; _i < TIER_ITEMS_1.length; _i++)
  4420. {
  4421. var tool = TIER_ITEMS_1[_i];
  4422. hideToolRecipe(tool, init);
  4423. }
  4424. // other stuff
  4425. for (var key in RECIPE_MAX.crafting)
  4426. {
  4427. hideRecipe(key, init);
  4428. }
  4429. if (init)
  4430. {
  4431. settings.observe(settings.KEY.hideCraftingRecipes, function ()
  4432. {
  4433. return processRecipes(false);
  4434. });
  4435. }
  4436. }
  4437. processRecipes(true);
  4438. var _processCraftingTab = win.processCraftingTab;
  4439. win.processCraftingTab = function ()
  4440. {
  4441. var reinit = !!win.refreshLoadCraftingTable;
  4442. _processCraftingTab();
  4443. if (reinit)
  4444. {
  4445. processRecipes(false);
  4446. }
  4447. };
  4448.  
  4449. function processItems(init)
  4450. {
  4451. if (init === void 0)
  4452. {
  4453. init = false;
  4454. }
  4455. // furnace
  4456. hideLeveledItems(FURNACE_LEVELS.length, function (i)
  4457. {
  4458. return FURNACE_LEVELS[i] + 'Furnace';
  4459. }, init);
  4460. // oil storage
  4461. hideLeveledItems(OIL_STORAGE_SIZES.length, function (i)
  4462. {
  4463. return 'oilStorage' + (i + 1);
  4464. }, init);
  4465. // oven recipes
  4466. hideLeveledItems(OVEN_LEVELS.length, function (i)
  4467. {
  4468. return OVEN_LEVELS[i] + 'Oven';
  4469. }, init);
  4470. // other stuff
  4471. for (var key in RECIPE_MAX.crafting)
  4472. {
  4473. hideItem(key, RECIPE_MAX.crafting[key], init);
  4474. }
  4475. if (init)
  4476. {
  4477. settings.observe(settings.KEY.hideUselessItems, function ()
  4478. {
  4479. return processItems(false);
  4480. });
  4481. }
  4482. }
  4483. processItems(true);
  4484. }
  4485. crafting.init = init;
  4486. })(crafting || (crafting = {}));
  4487.  
  4488. /**
  4489. * improve item boxes
  4490. */
  4491. var itemBoxes;
  4492. (function (itemBoxes)
  4493. {
  4494. itemBoxes.name = 'itemBoxes';
  4495.  
  4496. function hideNumberInItemBox(key, setVisibility)
  4497. {
  4498. if (setVisibility === void 0)
  4499. {
  4500. setVisibility = false;
  4501. }
  4502. var itemBox = document.getElementById('item-box-' + key);
  4503. if (!itemBox)
  4504. {
  4505. return;
  4506. }
  4507. var numberElement = itemBox.querySelector('span[data-item-display]');
  4508. if (!numberElement)
  4509. {
  4510. return;
  4511. }
  4512. numberElement.classList.add('number-caption');
  4513. if (setVisibility)
  4514. {
  4515. numberElement.classList.remove('hide');
  4516. numberElement.classList.add('hidden');
  4517. }
  4518. else
  4519. {
  4520. numberElement.classList.remove('hidden');
  4521. numberElement.classList.add('hide');
  4522. }
  4523. }
  4524.  
  4525. function addSpan2ItemBox(key, replace, setVisibility)
  4526. {
  4527. if (replace === void 0)
  4528. {
  4529. replace = true;
  4530. }
  4531. if (setVisibility === void 0)
  4532. {
  4533. setVisibility = false;
  4534. }
  4535. if (replace)
  4536. {
  4537. hideNumberInItemBox(key, setVisibility);
  4538. }
  4539. var itemBox = document.getElementById('item-box-' + key);
  4540. if (!itemBox)
  4541. {
  4542. return;
  4543. }
  4544. var span = document.createElement('span');
  4545. span.className = 'caption';
  4546. itemBox.appendChild(span);
  4547. return span;
  4548. }
  4549.  
  4550. function addCaptionStyle()
  4551. {
  4552. var CLASS_NAME = 'show-captions';
  4553. 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");
  4554.  
  4555. function updateBodyClass()
  4556. {
  4557. var show = settings.get(settings.KEY.showCaptions);
  4558. document.body.classList[show ? 'add' : 'remove'](CLASS_NAME);
  4559. }
  4560. updateBodyClass();
  4561. settings.observe(settings.KEY.showCaptions, function ()
  4562. {
  4563. return updateBodyClass();
  4564. });
  4565. }
  4566.  
  4567. function setOilPerSecond(span, oil)
  4568. {
  4569. span.innerHTML = "+ " + format.number(oil) + " L/s <img src=\"images/oil.png\" class=\"image-icon-20\">";
  4570. }
  4571. // show capacity of furnace
  4572. function addFurnaceCaption()
  4573. {
  4574. for (var i = 0; i < FURNACE_LEVELS.length; i++)
  4575. {
  4576. var key = FURNACE_LEVELS[i] + 'Furnace';
  4577. var boundKey = getBoundKey(key);
  4578. var capacitySpan = addSpan2ItemBox(boundKey);
  4579. if (capacitySpan)
  4580. {
  4581. capacitySpan.classList.add('capacity');
  4582. capacitySpan.textContent = 'Capacity: ' + format.number(win.getFurnaceCapacity(boundKey), true);
  4583. }
  4584. }
  4585. // charcoal foundry
  4586. var foundryCapacitySpan = addSpan2ItemBox('charcoalFoundry');
  4587. if (foundryCapacitySpan)
  4588. {
  4589. foundryCapacitySpan.classList.add('capacity');
  4590. foundryCapacitySpan.textContent = 'Capacity: 100';
  4591. }
  4592. }
  4593. // show oil cap of oil storage
  4594. function addOilStorageCaption()
  4595. {
  4596. for (var i = 0; i < OIL_STORAGE_SIZES.length; i++)
  4597. {
  4598. var key = 'oilStorage' + (i + 1);
  4599. var capSpan = addSpan2ItemBox(getBoundKey(key));
  4600. if (capSpan)
  4601. {
  4602. capSpan.classList.add('oil-cap');
  4603. capSpan.textContent = 'Oil cap: ' + format.number(OIL_STORAGE_SIZES[i], true);
  4604. }
  4605. }
  4606. }
  4607. var oilPipeOrbKey = 'boundBlueOilPipeOrb';
  4608.  
  4609. function setOilPipeCaption(span)
  4610. {
  4611. setOilPerSecond(span, 50 + win.achMiningEasyCompleted * 50 + getGameValue(oilPipeOrbKey) * 100);
  4612. }
  4613. function setTombKeys(span, key)
  4614. {
  4615. span.style = 'color: #470058';
  4616. span.innerHTML = format.number(key);
  4617. }
  4618. function addTombKeyCaption()
  4619. {
  4620. 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");
  4621. var tpl = document.createElement('templateWrapper');
  4622. 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";
  4623. var shadowDrop = tpl.firstElementChild;
  4624. document.body.appendChild(shadowDrop);
  4625. var crystalChargedSpan = addSpan2ItemBox('faradoxsCrystalCharged');
  4626. if (crystalChargedSpan)
  4627. {
  4628. crystalChargedSpan.classList.add('tombKey');
  4629. var totalKeys = win.tombKeyTotal;
  4630. setTombKeys(crystalChargedSpan, totalKeys);
  4631. observer.add(crystalChargedSpan, function ()
  4632. {
  4633. return setTombKeys(crystalChargedSpan, totalKeys);
  4634. });
  4635. }
  4636. var darkCrystalChargedSpan = addSpan2ItemBox('darkFaradoxsCrystalCharged');
  4637. if (darkCrystalChargedSpan)
  4638. {
  4639. darkCrystalChargedSpan.classList.add('tombKey');
  4640. var totalKeys = win.darkTombKeyTotal;
  4641. setTombKeys(darkCrystalChargedSpan, totalKeys);
  4642. observer.add(darkCrystalChargedSpan, function ()
  4643. {
  4644. return setTombKeys(darkCrystalChargedSpan, totalKeys);
  4645. });
  4646. }
  4647. }
  4648. // show oil per second
  4649. function addOilCaption()
  4650. {
  4651. 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");
  4652. var tpl = document.createElement('templateWrapper');
  4653. 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";
  4654. var shadowDrop = tpl.firstElementChild;
  4655. document.body.appendChild(shadowDrop);
  4656. var handheldOilSpan = addSpan2ItemBox('handheldOilPump', true, true);
  4657. if (handheldOilSpan)
  4658. {
  4659. handheldOilSpan.classList.add('oil');
  4660. setOilPerSecond(handheldOilSpan, 1 * win.miner);
  4661. observer.add('miner', function ()
  4662. {
  4663. return setOilPerSecond(handheldOilSpan, 1 * win.miner);
  4664. });
  4665. }
  4666. var oilPipeSpan = addSpan2ItemBox('boundOilPipe', true, true);
  4667. if (oilPipeSpan)
  4668. {
  4669. oilPipeSpan.classList.add('oil');
  4670. setOilPipeCaption(oilPipeSpan);
  4671. observer.add(oilPipeOrbKey, function ()
  4672. {
  4673. return setOilPipeCaption(oilPipeSpan);
  4674. });
  4675. }
  4676. var charcoalFactorySpan = addSpan2ItemBox('boundCharcoalFactory');
  4677. var charcoalFactoryOilGain = (boundRedCharcoalFactoryOrb) ? 600 : 300;
  4678. if (charcoalFactorySpan)
  4679. {
  4680. charcoalFactorySpan.classList.add('oil');
  4681. setOilPerSecond(charcoalFactorySpan, charcoalFactoryOilGain);
  4682. observer.add(charcoalFactorySpan, function ()
  4683. {
  4684. return setOilPerSecond(charcoalFactorySpan, charcoalFactoryOilGain);
  4685. });
  4686. }
  4687. // add pump jack oil display
  4688. var pumpjackSpan = addSpan2ItemBox('boundPumpjacks', false);
  4689. var totalOilPumpjacks = win.boundPumpjacks * 10;
  4690. var pumpjackOilGain = (achMiningHardCompleted) ? (totalOilPumpjacks * 2) : totalOilPumpjacks;
  4691. if (pumpjackSpan)
  4692. {
  4693. pumpjackSpan.classList.add('oil');
  4694. var setCaption_1 = function ()
  4695. {
  4696. return setOilPerSecond(pumpjackSpan, pumpjackOilGain);
  4697. };
  4698. setCaption_1();
  4699. observer.add('boundPumpjacks', function ()
  4700. {
  4701. return setCaption_1();
  4702. });
  4703. }
  4704. // add number of workers as caption to oil factory
  4705. var workerSpan = addSpan2ItemBox('boundOilFactory');
  4706. if (workerSpan)
  4707. {
  4708. var setCaption_2 = function ()
  4709. {
  4710. return workerSpan.textContent = 'Workers: ' + format.number(win.oilFactoryCheapWorkers, true);
  4711. };
  4712. setCaption_2();
  4713. observer.add('oilFactoryCheapWorkers', function ()
  4714. {
  4715. return setCaption_2();
  4716. });
  4717. }
  4718. var factoryOilSpan = addSpan2ItemBox('boundOilFactory');
  4719. var factoryOilGain = (boundGreenOilFactoryOrb) ? win.oilFactoryCheapWorkers * 2 :win.oilFactoryCheapWorkers;
  4720. if (factoryOilSpan)
  4721. {
  4722. factoryOilSpan.classList.add('oil');
  4723. var setCaption_3 = function ()
  4724. {
  4725. return setOilPerSecond(factoryOilSpan, factoryOilGain);
  4726. };
  4727. setCaption_3();
  4728. observer.add('oilFactoryCheapWorkers', function ()
  4729. {
  4730. return setCaption_3();
  4731. });
  4732. }
  4733. }
  4734.  
  4735. function addWandCaption()
  4736. {
  4737. for (var i = 0; i < WAND_LEVELS.length; i++)
  4738. {
  4739. var level = WAND_LEVELS[i];
  4740. var key = level + 'Wand';
  4741. var wandSpan = addSpan2ItemBox(key);
  4742. if (wandSpan)
  4743. {
  4744. wandSpan.textContent = capitalize(level) + ' Wand';
  4745. }
  4746. }
  4747. }
  4748.  
  4749. function addVariousCaptions()
  4750. {
  4751. var key2Name = {
  4752. 'achievementBook': 'Achievements'
  4753. , 'emptyAnvil': 'Anvil'
  4754. , 'tap': 'Tree Tap'
  4755. , 'farmer': 'Farmer'
  4756. , 'spellScroll1': 'Spell Scroll 1'
  4757. , 'boundRuniteSpyglass': 'Spyglass'
  4758. , 'bobsUncle': "Bob's Uncle"
  4759. , 'boundBoatingDock': 'Boating Dock'
  4760. , 'lumberjack': 'Lumberjack'
  4761. , 'handheldOilPump': 'Oil Pump'
  4762. , 'boundCharcoalFactory': 'Ch.coal Factory'
  4763. , 'boundNeedle': 'Needle'
  4764. , 'vendor': 'Vendor'
  4765. , 'boundOilStorage1': 'Oil Storage 1'
  4766. , 'boundOilStorage2': 'Oil Storage 2'
  4767. , 'boundOilStorage3': 'Oil Storage 3'
  4768. , 'boundOilStorage4': 'Oil Storage 4'
  4769. , 'boundOilStorage5': 'Oil Storage 5'
  4770. , 'boundOilStorage6': 'Oil Storage 6'
  4771. , 'boundOilStorage7': 'Oil Storage 7'
  4772. , 'boundOilPipe': 'Oil Pipe'
  4773. , 'meditate1': 'Meditate level 1'
  4774. , 'meditate2': 'Meditate level 2'
  4775. , 'meditate3': 'Meditate level 3'
  4776. , 'meditate4': 'Meditate level 4'
  4777. , 'meditate5': 'Meditate level 5'
  4778. , 'meditate6': 'Meditate level 6'
  4779. , 'meditate7': 'Meditate level 7'
  4780. , 'meditate8': 'Meditate level 8'
  4781. , 'meditate9': 'Meditate level 9'
  4782. , 'gardener': 'Gardener'
  4783. , 'planter': 'Planter'
  4784. , 'boundBrewingKit': 'Brewing Kit'
  4785. , 'cooksBook': 'Cooks Book'
  4786. , 'cooksPage': 'Cooks Page'
  4787. , 'combatDropTable': 'Loot Table'
  4788. , 'magicBook': 'Spell Book'
  4789. , 'magicShop': 'Magic Shop'
  4790. , 'crackedSpinningWheel': 'Cracked Wheel'
  4791. , 'woodenSpinningWheel': 'Wooden Wheel'
  4792. , 'oakSpinningWheel': 'Oak Wheel'
  4793. , 'willowSpinningWheel': 'Willow Wheel'
  4794. , 'mapleSpinningWheel': 'Maple Wheel'
  4795. , 'stardustSpinningWheel': 'Stardust Wheel'
  4796. , 'strangeSpinningWheel': 'Strange Wheel'
  4797. , 'ancientSpinningWheel': 'Ancient Wheel'
  4798. };
  4799. for (var key in key2Name)
  4800. {
  4801. var span = addSpan2ItemBox(key);
  4802. if (span)
  4803. {
  4804. span.textContent = key2Name[key];
  4805. }
  4806. }
  4807. }
  4808. // show current tier
  4809. function addTierCaption()
  4810. {
  4811. 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");
  4812.  
  4813. function addOrbObserver(key, spanList)
  4814. {
  4815. var boundOrbKey = getBoundKey('Blue' + capitalize(key) + 'Orb');
  4816.  
  4817. function checkOrb()
  4818. {
  4819. var classAction = getGameValue(boundOrbKey) > 0 ? 'add' : 'remove';
  4820. for (var _i = 0, spanList_1 = spanList; _i < spanList_1.length; _i++)
  4821. {
  4822. var span = spanList_1[_i];
  4823. span.classList[classAction]('orb');
  4824. }
  4825. }
  4826. checkOrb();
  4827. observer.add(boundOrbKey, function ()
  4828. {
  4829. return checkOrb();
  4830. });
  4831. }
  4832. var remainingOrbItems = ORB_ITEMS;
  4833. for (var _i = 0, TIER_ITEMS_2 = TIER_ITEMS; _i < TIER_ITEMS_2.length; _i++)
  4834. {
  4835. var tierItem = TIER_ITEMS_2[_i];
  4836. var isBindable = TIER_ITEMS_NOT_BINDABLE.indexOf(tierItem) === -1;
  4837. var spanList = [];
  4838. for (var i = 0; i < TIER_LEVELS.length; i++)
  4839. {
  4840. var key = getTierKey(tierItem, i);
  4841. var toolKey = isBindable ? getBoundKey(key) : key;
  4842. var tierSpan = addSpan2ItemBox(toolKey);
  4843. if (tierSpan)
  4844. {
  4845. tierSpan.classList.add('tier');
  4846. tierSpan.textContent = TIER_NAMES[i];
  4847. spanList.push(tierSpan);
  4848. }
  4849. }
  4850. var orbIndex = remainingOrbItems.indexOf(tierItem);
  4851. if (orbIndex !== -1)
  4852. {
  4853. addOrbObserver(tierItem, spanList);
  4854. remainingOrbItems.splice(orbIndex, 1);
  4855. }
  4856. }
  4857. for (var _a = 0, remainingOrbItems_1 = remainingOrbItems; _a < remainingOrbItems_1.length; _a++)
  4858. {
  4859. var itemKey = remainingOrbItems_1[_a];
  4860. var captionSpan = document.querySelector('#item-box-' + getBoundKey(itemKey) + ' > span:last-of-type');
  4861. if (!captionSpan)
  4862. {
  4863. continue;
  4864. }
  4865. addOrbObserver(itemKey, [captionSpan]);
  4866. }
  4867. }
  4868. var boatTimerKeys = BOAT_LIST.map(function (boatKey)
  4869. {
  4870. return boatKey + 'Timer';
  4871. });
  4872.  
  4873. function checkBoat(span, timerKey, init)
  4874. {
  4875. if (init === void 0)
  4876. {
  4877. init = false;
  4878. }
  4879. var isInTransit = getGameValue(timerKey) > 0;
  4880. var otherInTransit = boatTimerKeys.some(function (k)
  4881. {
  4882. return k != timerKey && getGameValue(k) > 0 && !boundBoatingDock;
  4883. });
  4884. span.textContent = isInTransit ? 'In transit' : 'Ready';
  4885. span.style.visibility = otherInTransit ? 'hidden' : '';
  4886. var parent = span.parentElement;
  4887. parent.style.opacity = otherInTransit ? '.5' : '';
  4888. if (init)
  4889. {
  4890. observer.add(boatTimerKeys, function ()
  4891. {
  4892. return checkBoat(span, timerKey, false);
  4893. });
  4894. }
  4895. }
  4896. // show boat progress
  4897. function addBoatCaption()
  4898. {
  4899. addStyle("\n#item-box-boundSailBoat.item-box > span[data-item-display] + span + span\n{\n\tdisplay: none;\n}\n\t\t");
  4900. for (var i = 0; i < BOAT_LIST.length; i++)
  4901. {
  4902. var span = addSpan2ItemBox(getBoundKey(BOAT_LIST[i]));
  4903. if (span)
  4904. {
  4905. checkBoat(span, boatTimerKeys[i], true);
  4906. }
  4907. }
  4908. }
  4909. // show bonemeal
  4910. function addBonemealCaption()
  4911. {
  4912. var noBonemealSpan = addSpan2ItemBox('boundBonemealBin');
  4913. if (!noBonemealSpan)
  4914. {
  4915. return;
  4916. }
  4917. noBonemealSpan.textContent = 'Bonemeal: 0';
  4918. var bonemealSpan = addSpan2ItemBox('boundFilledBonemealBin');
  4919. if (!bonemealSpan)
  4920. {
  4921. return;
  4922. }
  4923. bonemealSpan.dataset.itemDisplay = 'bonemeal';
  4924. bonemealSpan.textContent = format.number(win.bonemeal);
  4925. var captionSpan = document.createElement('span');
  4926. captionSpan.className = 'caption';
  4927. captionSpan.textContent = 'Bonemeal: ';
  4928. bonemealSpan.parentElement.insertBefore(captionSpan, bonemealSpan);
  4929. }
  4930.  
  4931. function warningBeforeSellingGems()
  4932. {
  4933. var _sellNPCItemDialogue = win.sellNPCItemDialogue;
  4934. win.sellNPCItemDialogue = function (item, amount)
  4935. {
  4936. if (item == 'sapphire' || item == 'emerald' || item == 'ruby' || item == 'diamond' || item == 'bloodDiamond' || item == 'dragonstone' ||
  4937. item == 'darkDiamond')
  4938. {
  4939. var itemName = key2Name(amount == 1 ? item : item.replace(/y$/, 'ie') + 's', true);
  4940. if (amount == 0
  4941. || !win.confirm('Gems are precious and rare. Please consider carefully:\nDo you really want to sell ' + amount + ' ' + itemName + '?'))
  4942. {
  4943. return;
  4944. }
  4945. }
  4946. else if (item == 'logs' || item == 'oakLogs' || item == 'willowLogs' || item == 'mapleLogs' || item == 'stardustLogs' || item == 'strangeLogs' || item == 'ancientLogs')
  4947. {
  4948. let itemName = key2Name(amount == 1 ? item.replace(/s$/, '') : item, true);
  4949. if (amount == 0
  4950. || !win.confirm('Logs are time consuming to collect. Please consider carefully:\nDo you really want to sell ' + amount + ' ' + itemName + '?'))
  4951. {
  4952. return;
  4953. }
  4954. }
  4955. _sellNPCItemDialogue(item, amount);
  4956. };
  4957. }
  4958.  
  4959. function addWikiaLinks()
  4960. {
  4961. var WIKIA_CLASS = 'wikia-links';
  4962. 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");
  4963.  
  4964. function setWikiaLinksVisibility(init)
  4965. {
  4966. if (init === void 0)
  4967. {
  4968. init = false;
  4969. }
  4970. var show = settings.get(settings.KEY.wikiaLinks);
  4971. document.body.classList[show ? 'add' : 'remove'](WIKIA_CLASS);
  4972. if (init)
  4973. {
  4974. settings.observe(settings.KEY.wikiaLinks, function ()
  4975. {
  4976. return setWikiaLinksVisibility();
  4977. });
  4978. }
  4979. }
  4980. setWikiaLinksVisibility(true);
  4981. var boxes = document.getElementsByClassName('item-box');
  4982.  
  4983. function disableClickPropagation(el)
  4984. {
  4985. el.addEventListener('click', function (event)
  4986. {
  4987. event.stopPropagation();
  4988. });
  4989. }
  4990. for (var i = 0; i < boxes.length; i++)
  4991. {
  4992. var box = boxes.item(i);
  4993. var key = box.id.replace(/^item-box-/, '');
  4994. var linkArea = document.createElement('a');
  4995. linkArea.className = 'wikia-link';
  4996. linkArea.href = getWikiaLink(key);
  4997. linkArea.target = '_blank';
  4998. disableClickPropagation(linkArea);
  4999. box.appendChild(linkArea);
  5000. var tooltipEl = ensureTooltip('wikiLink', linkArea);
  5001. if (tooltipEl.innerHTML === '')
  5002. {
  5003. tooltipEl.innerHTML = "Click to open the wikia page about this item.";
  5004. }
  5005. }
  5006. }
  5007.  
  5008. function init()
  5009. {
  5010. addCaptionStyle();
  5011. addFurnaceCaption();
  5012. //addOilStorageCaption();
  5013. addOilCaption();
  5014. addTombKeyCaption();
  5015. addWandCaption();
  5016. addVariousCaptions();
  5017. addTierCaption();
  5018. addBoatCaption();
  5019. addBonemealCaption();
  5020. warningBeforeSellingGems();
  5021. addWikiaLinks();
  5022. }
  5023. itemBoxes.init = init;
  5024. })(itemBoxes || (itemBoxes = {}));
  5025.  
  5026. /**
  5027. * add new chat
  5028. */
  5029. var chat;
  5030. (function (chat)
  5031. {
  5032. chat.name = 'chat';
  5033. // min time difference between repeated messages to not be considered as spam
  5034. var MIN_DIFF_REPEATED_MSG = 5e3;
  5035. var KEYWORD_LIST_KEY = 'keywordList';
  5036. chat.keywordList = store.has(KEYWORD_LIST_KEY) ? store.get(KEYWORD_LIST_KEY) : [];
  5037. var CHAT_HISTORY_KEY = 'chatHistory';
  5038. var MAX_CHAT_HISTORY_LENGTH = 100;
  5039. var PM_HISTORY_KEY = 'pmHistory';
  5040. var MAX_PM_HISTORY_LENGTH = 50;
  5041. var Type;
  5042. (function (Type)
  5043. {
  5044. Type[Type["reload"] = -1] = "reload";
  5045. Type[Type["normal"] = 0] = "normal";
  5046. Type[Type["pmReceived"] = 1] = "pmReceived";
  5047. Type[Type["pmSent"] = 2] = "pmSent";
  5048. Type[Type["serverMsg"] = 3] = "serverMsg";
  5049. })(Type || (Type = {}));;
  5050. var Tag;
  5051. (function (Tag)
  5052. {
  5053. Tag[Tag["none"] = 0] = "none";
  5054. Tag[Tag["donor"] = 1] = "donor";
  5055. Tag[Tag["contributor"] = 2] = "contributor";
  5056. Tag[Tag["mod"] = 3] = "mod";
  5057. Tag[Tag["dev"] = 4] = "dev";
  5058. Tag[Tag["server"] = 5] = "server";
  5059. })(Tag || (Tag = {}));;
  5060. /**
  5061. * The chunk hiding starts with at least 10 chunks.
  5062. * So there are at least
  5063. * (chunkHidingMinChunks-1) * msgChunkSize + 1 = 9 * 100 + 1 = 901
  5064. * messages before the chunk hiding mechanism starts.
  5065. */
  5066. var CHUNK_HIDING_MIN_CHUNKS = 10;
  5067. var MSG_CHUNK_SIZE = 100;
  5068. var RELOADED_CHAT_DATA = {
  5069. timestamp: 0
  5070. , username: ''
  5071. , userlevel: 0
  5072. , icon: 0
  5073. , tag: 0
  5074. , type: Type.reload
  5075. , msg: '[...]'
  5076. };
  5077. var CHAT_BOX_ID = 'div-chat';
  5078. var DEFAULT_CHAT_DIV_ID = 'div-chat-area';
  5079. var GENERAL_CHAT_DIV_ID = 'div-chat-general';
  5080. var PM_CHAT_TAB_PREFIX = 'tab-chat-pm-';
  5081. var PM_CHAT_DIV_PREFIX = 'div-chat-pm-';
  5082. var CHAT_TABS_ID = 'chat-tabs';
  5083. var CHAT_INPUT_ID = 'chat-input-text';
  5084. var CHAT_CLASS = 'div-chat-area';
  5085. var COLORIZE_CLASS = 'colorize';
  5086. var SpecialTab;
  5087. (function (SpecialTab)
  5088. {
  5089. SpecialTab[SpecialTab["default"] = 0] = "default";
  5090. SpecialTab[SpecialTab["general"] = 1] = "general";
  5091. SpecialTab[SpecialTab["filler"] = 2] = "filler";
  5092. })(SpecialTab || (SpecialTab = {}));;
  5093. var CHAT_SPECIAL_TAB_ID = (_a = {}
  5094. , _a[SpecialTab.default] = 'tab-chat-default'
  5095. , _a[SpecialTab.general] = 'tab-chat-general'
  5096. , _a[SpecialTab.filler] = 'tab-chat-filler'
  5097. , _a);
  5098. var CONTEXTMENU_ID = 'player-contextmenu';
  5099. var CHAT_ICONS = [
  5100. {
  5101. key: ''
  5102. , title: ''
  5103. }
  5104. , {
  5105. key: 'halloween2015'
  5106. , title: 'Halloween Gamer (2015)'
  5107. }
  5108. , {
  5109. key: 'christmas2015'
  5110. , title: 'Chirstmas Gamer (2015)'
  5111. }
  5112. , {
  5113. key: 'easter2016'
  5114. , title: 'Easter Gamer (2016)'
  5115. }
  5116. , {
  5117. key: 'halloween2016'
  5118. , title: 'Halloween Gamer (2016)'
  5119. }
  5120. , {
  5121. key: 'christmas2016'
  5122. , title: 'Chirstmas Gamer (2016)'
  5123. }
  5124. , {
  5125. key: 'dh1Max'
  5126. , title: 'DH1 Pro'
  5127. }
  5128. , {
  5129. key: 'hardcore'
  5130. , title: 'Hardcore Player'
  5131. }
  5132. , {
  5133. key: 'quest'
  5134. , title: 'Questmaster'
  5135. }
  5136. , {
  5137. key: 'maxMining'
  5138. , title: 'Mastery in mining'
  5139. }
  5140. , {
  5141. key: 'maxCrafting'
  5142. , title: 'Mastery in crafting'
  5143. }
  5144. , {
  5145. key: 'maxWC'
  5146. , title: 'Mastery in woodcutting'
  5147. }
  5148. , {
  5149. key: 'maxFarming'
  5150. , title: 'Mastery in farming'
  5151. }
  5152. , {
  5153. key: 'maxBrewing'
  5154. , title: 'Mastery in brewing'
  5155. }
  5156. , {
  5157. key: 'maxCombat'
  5158. , title: 'Mastery in combat'
  5159. }
  5160. , {
  5161. key: 'maxMagic'
  5162. , title: 'Mastery in magic'
  5163. }
  5164. , {
  5165. key: 'maxFishing'
  5166. , title: 'Mastery in fishing'
  5167. }
  5168. , {
  5169. key: 'maxCooking'
  5170. , title: 'Mastery in cooking'
  5171. }
  5172. , {
  5173. key: 'maxLevel'
  5174. , title: 'Mastery of all skills'
  5175. }
  5176. , {
  5177. key: 'birdcage'
  5178. , title: 'Stole a birdcage'
  5179. }
  5180. , {
  5181. key: 'achievement'
  5182. , title: 'Achievement Hunter'
  5183. }
  5184. , {
  5185. key: 'pinkPartyHat'
  5186. , title: 'Pink Party Hat'
  5187. }
  5188. , {
  5189. key: 'redPartyHat'
  5190. , title: 'Red Party Hat'
  5191. }
  5192. , {
  5193. key: 'greenPartyHat'
  5194. , title: 'Green Party Hat'
  5195. }
  5196. , {
  5197. key: 'yellowPartyHat'
  5198. , title: 'Yellow Party Hat'
  5199. }
  5200. , {
  5201. key: 'whitePartyHat'
  5202. , title: 'White Party Hat'
  5203. }
  5204. , {
  5205. key: 'bluePartyHat'
  5206. , title: 'Blue Party Hat'
  5207. }
  5208. , {
  5209. key: 'easter2018'
  5210. , title: 'Easter Gamer (2018)'
  5211. }
  5212. , {
  5213. key: 'firstEvent20181st'
  5214. , title: '1st place Gamer (#1 event 2018)'
  5215. }
  5216. , {
  5217. key: 'firstEvent20182nd'
  5218. , title: '2nd place Gamer (#1 event 2018)'
  5219. }
  5220. , {
  5221. key: 'firstEvent20183rd'
  5222. , title: '3rd place Gamer (#1 event 2018)'
  5223. }
  5224. , {
  5225. key: 'firstEvent20184th'
  5226. , title: '4th place Gamer (#1 event 2018)'
  5227. }
  5228. ];
  5229. var getUnknownChatIcon = function (icon)
  5230. {
  5231. return {
  5232. key: 'unknown'
  5233. , title: ''
  5234. , img: '<img src="images/chat-icons/' + icon + '.png" class="image-icon-20" />'
  5235. };
  5236. };
  5237. var CHAT_TAGS = [
  5238. null
  5239. , {
  5240. key: 'donor'
  5241. , name: ''
  5242. }
  5243. , {
  5244. key: 'contributor'
  5245. , name: 'Contributor'
  5246. }
  5247. , {
  5248. key: 'mod'
  5249. , name: 'Moderator'
  5250. }
  5251. , {
  5252. key: 'dev'
  5253. , name: 'Dev'
  5254. }
  5255. , {
  5256. key: 'yell'
  5257. , name: 'Server Message'
  5258. }
  5259. ];
  5260. var LOCALE = 'en-US';
  5261. var LOCALE_OPTIONS = {
  5262. hour12: false
  5263. , year: 'numeric'
  5264. , month: 'long'
  5265. , day: 'numeric'
  5266. , hour: '2-digit'
  5267. , minute: '2-digit'
  5268. , second: '2-digit'
  5269. };
  5270. // game commands
  5271. var COMMANDS = [
  5272. 'pm'
  5273. , 'mute'
  5274. , 'clear'
  5275. , 'ipmute'
  5276. ];
  5277. var CLEAR_CMD = 'clear';
  5278. var TUTORIAL_CMD = 'tutorial';
  5279. // load chat history
  5280. var chatHistory = store.get(CHAT_HISTORY_KEY) || [];
  5281. var pmHistory = store.get(PM_HISTORY_KEY) || [];
  5282. // store chat colors for each user
  5283. var user2Color;
  5284. var usedColors;
  5285. // reserve color for special messages (e.g. server messages): white
  5286. var reservedColors = ['#ffffff'];
  5287. // message chunks
  5288. var msgChunkMap = new Map();
  5289. // for adding elements at startup
  5290. var chatboxFragments = new Map();
  5291. var chatInitialized = false;
  5292. // find index of last message which is not a pm
  5293. var isLastMsgNotReload = false;
  5294. for (var i = chatHistory.length - 1; i >= 0; i--)
  5295. {
  5296. if (!isDataPM(chatHistory[i]))
  5297. {
  5298. isLastMsgNotReload = chatHistory[i].type != Type.reload;
  5299. break;
  5300. }
  5301. }
  5302. // insert a placeholder for a reloaded chat
  5303. if (isLastMsgNotReload)
  5304. {
  5305. RELOADED_CHAT_DATA.timestamp = (new Date()).getTime();
  5306. chatHistory.push(RELOADED_CHAT_DATA);
  5307. }
  5308.  
  5309. function isMuted(user)
  5310. {
  5311. return user !== win.username
  5312. && win.mutedPeople.some(function (name)
  5313. {
  5314. return user.indexOf(name) > -1;
  5315. });
  5316. }
  5317.  
  5318. function isSpam(data)
  5319. {
  5320. // allow all own messages, messages from contributors, mods, devs and all server messages
  5321. if (data.username === win.username || data.tag != Tag.none)
  5322. {
  5323. return false;
  5324. }
  5325. /**
  5326. * get last message of current user
  5327. */
  5328. var historyIndex = chatHistory.indexOf(data);
  5329. if (historyIndex == -1)
  5330. {
  5331. historyIndex = chatHistory.length;
  5332. }
  5333. var lastData = null;
  5334. for (var i = historyIndex - 1; i >= 0 && (lastData === null); i--)
  5335. {
  5336. var dataBefore = chatHistory[i];
  5337. if (dataBefore.username === data.username)
  5338. {
  5339. lastData = dataBefore;
  5340. }
  5341. }
  5342. /**
  5343. * compare message and don't allow the same message twice
  5344. */
  5345. if (lastData
  5346. && lastData.msg === data.msg
  5347. && (data.timestamp - lastData.timestamp) < MIN_DIFF_REPEATED_MSG)
  5348. {
  5349. return true;
  5350. }
  5351. return false;
  5352. }
  5353.  
  5354. function saveKeywordList()
  5355. {
  5356. store.set(KEYWORD_LIST_KEY, chat.keywordList);
  5357. }
  5358.  
  5359. function addKeyword(keyword)
  5360. {
  5361. if (keyword !== '' && chat.keywordList.indexOf(keyword) === -1)
  5362. {
  5363. chat.keywordList.push(keyword);
  5364. saveKeywordList();
  5365. return true;
  5366. }
  5367. return false;
  5368. }
  5369. chat.addKeyword = addKeyword;
  5370.  
  5371. function removeKeyword(keyword)
  5372. {
  5373. var index = chat.keywordList.indexOf(keyword);
  5374. if (index !== -1)
  5375. {
  5376. chat.keywordList.splice(index, 1);
  5377. saveKeywordList();
  5378. return true;
  5379. }
  5380. return false;
  5381. }
  5382. chat.removeKeyword = removeKeyword;
  5383.  
  5384. function handleScrolling(chatbox)
  5385. {
  5386. if (win.isAutoScrolling)
  5387. {
  5388. setTimeout(function ()
  5389. {
  5390. return chatbox.scrollTop = chatbox.scrollHeight;
  5391. });
  5392. }
  5393. }
  5394. // for chat messages which arrive before DOMContentLoaded and can not be displayed since the DOM isn't ready
  5395. function processChatData(username, iconString, tagString, msg, isPM)
  5396. {
  5397. var tag = parseInt(tagString, 10);
  5398. var userlevel = 0;
  5399. var type = Type.normal;
  5400. if (isPM == 1)
  5401. {
  5402. var match = msg.match(/^\s*\[(PM from|Sent to) ([A-Za-z0-9_ ]+)\]: (.+?)\s*$/) || ['', '', username, msg];
  5403. type = match[1] == 'Sent to' ? Type.pmSent : Type.pmReceived;
  5404. username = match[2];
  5405. if (username !== 'sexy_squid')
  5406. {
  5407. username = username.replace(/_/g, ' ');
  5408. }
  5409. msg = match[3];
  5410. }
  5411. else if (tag == Tag.server)
  5412. {
  5413. type = Type.serverMsg;
  5414. }
  5415. else
  5416. {
  5417. var match = msg.match(/^\s*\((\d+)\): (.+?)\s*$/);
  5418. if (match)
  5419. {
  5420. userlevel = parseInt(match[1], 10);
  5421. msg = match[2];
  5422. }
  5423. else
  5424. {
  5425. userlevel = win.getGlobalLevel();
  5426. }
  5427. }
  5428. // unlinkify when using DH2QoL to store the plain message
  5429. if (win.addToChatBox.toString().includes('linkify(arguments[3])'))
  5430. {
  5431. msg = msg.replace(/<a href='([^']+)' target='_blank'>\1<\/a>/ig, '$1');
  5432. }
  5433. if (type == Type.pmSent)
  5434. {
  5435. // turn some critical characters into HTML entities
  5436. msg = msg.replace(/[<>]/g, function (char)
  5437. {
  5438. return '&#' + char.charCodeAt(0) + ';';
  5439. });
  5440. }
  5441. return {
  5442. timestamp: now()
  5443. , username: username
  5444. , userlevel: userlevel
  5445. , icon: parseInt(iconString, 10)
  5446. , tag: tag
  5447. , type: type
  5448. , msg: msg
  5449. };
  5450. }
  5451.  
  5452. function saveChatHistory()
  5453. {
  5454. store.set(CHAT_HISTORY_KEY, chatHistory);
  5455. }
  5456.  
  5457. function savePmHistory()
  5458. {
  5459. store.set(PM_HISTORY_KEY, pmHistory);
  5460. }
  5461.  
  5462. function add2ChatHistory(data)
  5463. {
  5464. if (data.type === Type.pmReceived
  5465. || data.type === Type.pmSent)
  5466. {
  5467. pmHistory.push(data);
  5468. pmHistory = pmHistory.slice(-MAX_PM_HISTORY_LENGTH);
  5469. savePmHistory();
  5470. }
  5471. else
  5472. {
  5473. chatHistory.push(data);
  5474. chatHistory = chatHistory.slice(-MAX_CHAT_HISTORY_LENGTH);
  5475. saveChatHistory();
  5476. }
  5477. }
  5478.  
  5479. function username2Id(username)
  5480. {
  5481. return username.replace(/ /g, '_');
  5482. }
  5483.  
  5484. function setNewCounter(tab, num, force)
  5485. {
  5486. if (force === void 0)
  5487. {
  5488. force = false;
  5489. }
  5490. var panel = getChatPanel(tab.dataset.username || '');
  5491. if (force
  5492. || !tab.classList.contains('selected')
  5493. || !win.isAutoScrolling && panel.scrollHeight > panel.scrollTop + panel.offsetHeight)
  5494. {
  5495. tab.dataset.new = num.toString();
  5496. }
  5497. }
  5498.  
  5499. function incrementNewCounter(tab)
  5500. {
  5501. setNewCounter(tab, parseInt(tab.dataset.new || '0', 10) + 1);
  5502. }
  5503.  
  5504. function getChatTab(username, specialTab)
  5505. {
  5506. var id = (specialTab != null)
  5507. ? CHAT_SPECIAL_TAB_ID[specialTab]
  5508. : PM_CHAT_TAB_PREFIX + username2Id(username);
  5509. var tab = document.getElementById(id);
  5510. if (!tab)
  5511. {
  5512. tab = document.createElement('div');
  5513. tab.className = 'chat-tab';
  5514. if (specialTab != null)
  5515. {
  5516. tab.classList.add(SpecialTab[specialTab]);
  5517. }
  5518. tab.id = id;
  5519. tab.dataset.username = username;
  5520. setNewCounter(tab, 0, true);
  5521. if (username.length > 0)
  5522. {
  5523. tab.textContent = username;
  5524. // thanks /u/Spino-Prime for pointing out this was missing
  5525. var closeSpan = document.createElement('span');
  5526. closeSpan.className = 'close';
  5527. tab.appendChild(closeSpan);
  5528. }
  5529. var chatTabs = document.getElementById(CHAT_TABS_ID);
  5530. var filler = chatTabs.querySelector('.filler');
  5531. if (filler)
  5532. {
  5533. chatTabs.insertBefore(tab, filler);
  5534. }
  5535. else
  5536. {
  5537. chatTabs.appendChild(tab);
  5538. }
  5539. }
  5540. return tab;
  5541. }
  5542.  
  5543. function getChatPanel(username)
  5544. {
  5545. var id = username == '' ? GENERAL_CHAT_DIV_ID : PM_CHAT_DIV_PREFIX + username2Id(username);
  5546. var panel = document.getElementById(id);
  5547. if (!panel)
  5548. {
  5549. panel = document.createElement('div');
  5550. panel.setAttribute('disabled', 'disabled');
  5551. panel.id = id;
  5552. panel.className = CHAT_CLASS;
  5553. var defaultChat = document.getElementById(DEFAULT_CHAT_DIV_ID);
  5554. var height = defaultChat.style.height;
  5555. panel.style.height = height;
  5556. var chatDiv = defaultChat.parentElement;
  5557. chatDiv.insertBefore(panel, defaultChat);
  5558. }
  5559. return panel;
  5560. }
  5561.  
  5562. function changeChatTab(oldTab, newTab)
  5563. {
  5564. if (oldTab)
  5565. {
  5566. oldTab.classList.remove('selected');
  5567. var oldChatPanel = void 0;
  5568. if (oldTab.classList.contains('default'))
  5569. {
  5570. oldChatPanel = document.getElementById(DEFAULT_CHAT_DIV_ID);
  5571. }
  5572. else
  5573. {
  5574. oldChatPanel = getChatPanel(oldTab.dataset.username || '');
  5575. }
  5576. oldChatPanel.classList.remove('selected');
  5577. }
  5578. newTab.classList.add('selected');
  5579. setNewCounter(newTab, 0, true);
  5580. var newChatPanel;
  5581. if (newTab.classList.contains('default'))
  5582. {
  5583. newChatPanel = document.getElementById(DEFAULT_CHAT_DIV_ID);
  5584. }
  5585. else
  5586. {
  5587. newChatPanel = getChatPanel(newTab.dataset.username || '');
  5588. }
  5589. newChatPanel.classList.add('selected');
  5590. var toUsername = newTab.dataset.username;
  5591. var newTextPlaceholder = toUsername == '' ? win.username + ':' : 'PM to ' + toUsername + ':';
  5592. document.getElementById(CHAT_INPUT_ID).placeholder = newTextPlaceholder;
  5593. handleScrolling(newChatPanel);
  5594. }
  5595.  
  5596. function clearChat(username)
  5597. {
  5598. if (username === '')
  5599. {
  5600. // clean server chat
  5601. chatHistory = [];
  5602. saveChatHistory();
  5603. }
  5604. else
  5605. {
  5606. // delete pms stored for that user
  5607. for (var i = 0; i < pmHistory.length; i++)
  5608. {
  5609. var data = pmHistory[i];
  5610. if (data.username == username)
  5611. {
  5612. pmHistory.splice(i, 1);
  5613. i--;
  5614. }
  5615. }
  5616. savePmHistory();
  5617. }
  5618. // clear pm-chat panel
  5619. var panel = getChatPanel(username);
  5620. while (panel.children.length > 0)
  5621. {
  5622. panel.removeChild(panel.children[0]);
  5623. }
  5624. msgChunkMap.delete(username);
  5625. return panel;
  5626. }
  5627.  
  5628. function closeChatTab(username)
  5629. {
  5630. // clear pm-chat panel and remove message-history
  5631. clearChat(username);
  5632. // remove pm-tab (and change tab if necessary)
  5633. var selectedTab = getSelectedTab();
  5634. var tab2Close = getChatTab(username, null);
  5635. if (selectedTab.dataset.username == username)
  5636. {
  5637. var generalTab = getChatTab('', SpecialTab.general);
  5638. changeChatTab(tab2Close, generalTab);
  5639. }
  5640. var tabContainer = tab2Close.parentElement;
  5641. tabContainer.removeChild(tab2Close);
  5642. }
  5643.  
  5644. function isDataPM(data)
  5645. {
  5646. return data.type === Type.pmSent || data.type === Type.pmReceived;
  5647. }
  5648.  
  5649. function colorizeMsg(username)
  5650. {
  5651. if (username == '')
  5652. {
  5653. return null;
  5654. }
  5655. if (!user2Color.has(username))
  5656. {
  5657. var color = void 0;
  5658. do {
  5659. var colorizer = settings.getSub(settings.KEY.colorizeChat, 'colorizer');
  5660. if (colorizer == 1)
  5661. {
  5662. color = colorGenerator.getRandom(
  5663. {
  5664. luminosity: 'light'
  5665. });
  5666. }
  5667. else if (colorizer == 2)
  5668. {
  5669. color = colorGenerator.getRandom(
  5670. {
  5671. luminosity: 'dark'
  5672. });
  5673. }
  5674. else
  5675. {
  5676. color = colorGenerator.getEquallyDistributed();
  5677. }
  5678. } while (usedColors.has(color));
  5679. user2Color.set(username, color);
  5680. usedColors.add(color);
  5681. addStyle("\n#" + CHAT_BOX_ID + "." + COLORIZE_CLASS + " .chat-msg[data-username=\"" + username + "\"]\n{\n\tbackground-color: " + color + ";\n}\n\t\t\t", 'name-color');
  5682. }
  5683. return user2Color.get(username);
  5684. }
  5685.  
  5686. function createMessageSegment(data)
  5687. {
  5688. var isThisPm = isDataPM(data);
  5689. var msgUsername = data.type === Type.pmSent ? win.username : data.username;
  5690. var history = isThisPm ? pmHistory : chatHistory;
  5691. var historyIndex = history.indexOf(data);
  5692. var isSameUser = null;
  5693. var isSameTime = null;
  5694. for (var i = historyIndex - 1; i >= 0 && (isSameUser === null || isSameTime === null); i--)
  5695. {
  5696. var dataBefore = history[i];
  5697. if (isThisPm === isDataPM(dataBefore))
  5698. {
  5699. if (isSameUser === null)
  5700. {
  5701. var beforeUsername = dataBefore.type == Type.pmSent ? win.username : dataBefore.username;
  5702. isSameUser = beforeUsername === msgUsername;
  5703. }
  5704. if (dataBefore.type != Type.reload)
  5705. {
  5706. isSameTime = Math.floor(data.timestamp / 1000 / 60) - Math.floor(dataBefore.timestamp / 1000 / 60) === 0;
  5707. }
  5708. }
  5709. }
  5710. var d = new Date(data.timestamp);
  5711. var hour = (d.getHours() < 10 ? '0' : '') + d.getHours();
  5712. var minute = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes();
  5713. var icon = CHAT_ICONS[data.icon] || getUnknownChatIcon(data.icon);
  5714. var tag = CHAT_TAGS[data.tag] ||
  5715. {
  5716. key: ''
  5717. , name: ''
  5718. };
  5719. var formattedMsg = data.msg
  5720. .replace(/<a href='(.+?)' target='_blank'>\1<\/a>/g, '$1')
  5721. .replace(/(https?:\/\/[^\s"<>]+)/g, '<a target="_blank" href="$1">$1</a>');
  5722. colorizeMsg(msgUsername);
  5723. var msgTitle = data.type == Type.reload ? 'Chat loaded on ' + d.toLocaleString(LOCALE, LOCALE_OPTIONS) : '';
  5724. var user = data.type === Type.serverMsg ? 'Server Message' : msgUsername;
  5725. var levelAppendix = data.type == Type.normal ? ' (' + data.userlevel + ')' : '';
  5726. var userTitle = data.tag != Tag.server ? tag.name : '';
  5727. return "<span class=\"chat-msg\" data-type=\"" + data.type + "\" data-tag=\"" + tag.key + "\" data-username=\"" + msgUsername + "\">"
  5728. + ("<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>")
  5729. + ("<span class=\"user\" data-name=\"" + msgUsername + "\" data-same-user=\"" + isSameUser + "\">")
  5730. + ("<span class=\"icon " + icon.key + "\" title=\"" + icon.title + "\"></span>")
  5731. + ("<span class=\"name chat-tag-" + tag.key + "\" title=\"" + userTitle + "\">" + user + levelAppendix + ":</span>")
  5732. + "</span>"
  5733. + ("<span class=\"msg\" title=\"" + msgTitle + "\">" + formattedMsg + "</span>")
  5734. + "</span>";
  5735. }
  5736.  
  5737. function add2Chat(data)
  5738. {
  5739. if (!chatInitialized)
  5740. {
  5741. return;
  5742. }
  5743. var isThisPm = isDataPM(data);
  5744. // don't mute pms (you can just ignore pm-tab if you like)
  5745. if (!isThisPm && isMuted(data.username))
  5746. {
  5747. return;
  5748. }
  5749. var userKey = isThisPm ? data.username : '';
  5750. if (isThisPm)
  5751. {
  5752. win.lastPMUser = data.username;
  5753. }
  5754. // username is 3-12 characters long
  5755. var chatbox = getChatPanel(userKey);
  5756. var msgChunk = msgChunkMap.get(userKey);
  5757. if (!msgChunk || msgChunk.children.length >= MSG_CHUNK_SIZE)
  5758. {
  5759. msgChunk = document.createElement('div');
  5760. msgChunk.className = 'msg-chunk';
  5761. msgChunkMap.set(userKey, msgChunk);
  5762. if (chatboxFragments != null)
  5763. {
  5764. if (!chatboxFragments.has(userKey))
  5765. {
  5766. chatboxFragments.set(userKey, document.createDocumentFragment());
  5767. }
  5768. chatboxFragments.get(userKey).appendChild(msgChunk);
  5769. }
  5770. else
  5771. {
  5772. chatbox.appendChild(msgChunk);
  5773. }
  5774. }
  5775. var tmp = document.createElement('templateWrapper');
  5776. tmp.innerHTML = createMessageSegment(data);
  5777. msgChunk.appendChild(tmp.children[0]);
  5778. handleScrolling(chatbox);
  5779. // add delay because handleScrolling is will set scrollTop delayed
  5780. setTimeout(function ()
  5781. {
  5782. var chatTab = getChatTab(userKey, isThisPm ? null : SpecialTab.general);
  5783. incrementNewCounter(chatTab);
  5784. });
  5785. }
  5786.  
  5787. function applyChatStyle()
  5788. {
  5789. addStyle("\ndiv.div-chat-area\n{\n\tpadding-left: 0;\n}\nspan.chat-msg\n{\n\tdisplay: flex;\n\tmin-height: 21px;\
  5790. \n\tpadding: 1px 0;\n\tpadding-left: 5px;\n}\n#" + CHAT_BOX_ID + ":not(." + COLORIZE_CLASS + ") span.chat-msg:nth-child(2n)\
  5791. \n{\n\tbackground-color: hsla(0, 0%, 90%, 1);\n}\n.chat-msg[data-type=\"" + Type.reload + "\"]\n{\n\tfont-size: 0.8rem;\
  5792. \n\tline-height: 1.2rem;\n}\n.chat-msg .timestamp\n{\n\tdisplay: none;\n}\n#" + CHAT_BOX_ID + ".showTimestamps \
  5793. .chat-msg:not([data-type=\"" + Type.reload + "\"]) .timestamp\n{\n\tcolor: hsla(0, 0%, 50%, 1);\n\tdisplay: inline-block;\
  5794. \n\tfont-size: .9rem;\n\tmargin: 0;\n\tmargin-right: 5px;\n\tposition: relative;\n\twidth: 2.5rem;\n}\n.chat-msg \
  5795. .timestamp[data-same-time=\"true\"]\n{\n\tcolor: hsla(0, 0%, 50%, .1);\n}\n.chat-msg:not([data-type=\"" + Type.reload + "\"]) \
  5796. .timestamp:hover::after\n{\n\tbackground-color: hsla(0, 0%, 12%, 1);\n\tborder-radius: .2rem;\n\tcontent: attr(data-fulltime);\
  5797. \n\tcolor: hsla(0, 0%, 100%, 1);\n\tline-height: 1.35rem;\n\tpadding: .4rem .8rem;\n\tpointer-events: none;\n\tposition: absolute;\
  5798. \n\tleft: 2.5rem;\n\ttop: -0.4rem;\n\ttext-align: center;\n\twhite-space: nowrap;\n}\n\n#" + CHAT_BOX_ID + ".showTags \
  5799. .chat-msg[data-type=\"" + Type.pmReceived + "\"] { color: purple; }\n#" + CHAT_BOX_ID + ".showTags \
  5800. .chat-msg[data-type=\"" + Type.pmSent + "\"] { color: purple; }\n#" + CHAT_BOX_ID + ".showTags \
  5801. .chat-msg[data-type=\"" + Type.serverMsg + "\"] { color: blue; }\n#" + CHAT_BOX_ID + ".showTags \
  5802. .chat-msg[data-tag=\"contributor\"] { color: green; }\n#" + CHAT_BOX_ID + ".showTags .chat-msg[data-tag=\"mod\"] \
  5803. { color: #669999; }\n#" + CHAT_BOX_ID + ".showTags .chat-msg[data-tag=\"dev\"] { color: #666600; }\n.chat-msg:not([data-type=\"" + Type.reload + "\"]) \
  5804. .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 + "\"]) \
  5805. .user\n{\n\tflex-basis: 182px;\n}\n#" + CHAT_BOX_ID + ".showIcons #" + GENERAL_CHAT_DIV_ID + " .chat-msg:not([data-type=\"" + Type.reload + "\"]) \
  5806. .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 \
  5807. .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 \
  5808. .user .icon.unknown > img,\n.chat-msg .user .icon:not(.unknown)::before\n{\n\tbackground-size: 20px 20px;\n\tcontent: '';\n\tdisplay: inline-block;\
  5809. \n\tmargin-right: 2px;\n\twidth: 20px;\n\theight: 20px;\n\tvertical-align: middle;\n}\n.chat-msg \
  5810. .user .icon.halloween2015::before\t{ background-image: url('images/chat-icons/1.png'); }\n.chat-msg \
  5811. .user .icon.christmas2015::before\t{ background-image: url('images/chat-icons/2.png'); }\n.chat-msg \
  5812. .user .icon.easter2016::before\t{ background-image: url('images/chat-icons/3.png'); }\n.chat-msg \
  5813. .user .icon.halloween2016::before\t{ background-image: url('images/chat-icons/4.png'); }\n.chat-msg \
  5814. .user .icon.christmas2016::before\t{ background-image: url('images/chat-icons/5.png'); }\n.chat-msg \
  5815. .user .icon.dh1Max::before\t\t{ background-image: url('images/chat-icons/6.png'); }\n.chat-msg \
  5816. .user .icon.hardcore::before\t\t{ background-image: url('images/chat-icons/7.png'); }\n.chat-msg \
  5817. .user .icon.quest::before\t\t\t{ background-image: url('images/chat-icons/8.png'); }\n.chat-msg \
  5818. .user .icon.maxMining::before\t\t{ background-image: url('images/chat-icons/9.png'); }\n.chat-msg \
  5819. .user .icon.maxCrafting::before\t{ background-image: url('images/chat-icons/10.png'); }\n.chat-msg \
  5820. .user .icon.maxWC::before\t\t\t{ background-image: url('images/chat-icons/11.png'); }\n.chat-msg \
  5821. .user .icon.maxFarming::before\t{ background-image: url('images/chat-icons/12.png'); }\n.chat-msg \
  5822. .user .icon.maxBrewing::before\t{ background-image: url('images/chat-icons/13.png'); }\n.chat-msg \
  5823. .user .icon.maxCombat::before\t\t{ background-image: url('images/chat-icons/14.png'); }\n.chat-msg \
  5824. .user .icon.maxMagic::before\t\t{ background-image: url('images/chat-icons/15.png'); }\n.chat-msg \
  5825. .user .icon.maxFishing::before\t{ background-image: url('images/chat-icons/16.png'); }\n.chat-msg \
  5826. .user .icon.maxCooking::before\t{ background-image: url('images/chat-icons/17.png'); }\n.chat-msg \
  5827. .user .icon.maxLevel::before\t\t{ background-image: url('images/chat-icons/18.png'); }\n.chat-msg \
  5828. .user .icon.birdcage::before\t\t{ background-image: url('images/chat-icons/19.png'); }\n.chat-msg \
  5829. .user .icon.achievement::before\t{ background-image: url('images/chat-icons/20.png'); }\n.chat-msg \
  5830. .user .icon.pinkPartyHat::before\t{ background-image: url('images/chat-icons/21.png'); }\n.chat-msg \
  5831. .user .icon.redPartyHat::before\t{ background-image: url('images/chat-icons/22.png'); }\n.chat-msg \
  5832. .user .icon.greenPartyHat::before\t{ background-image: url('images/chat-icons/23.png'); }\n.chat-msg \
  5833. .user .icon.yellowPartyHat::before\t{ background-image: url('images/chat-icons/24.png'); }\n.chat-msg \
  5834. .user .icon.whitePartyHat::before\t{ background-image: url('images/chat-icons/25.png'); }\n.chat-msg \
  5835. .user .icon.bluePartyHat::before\t{ background-image: url('images/chat-icons/26.png'); }\n\n.chat-msg \
  5836. .user .icon.easter2018::before\t{ background-image: url('images/chat-icons/27.png'); }\n\n.chat-msg \
  5837. .user .icon.firstEvent20181st::before\t{ background-image: url('images/chat-icons/28.png'); }\n\n.chat-msg \
  5838. .user .icon.firstEvent20182nd::before\t{ background-image: url('images/chat-icons/29.png'); }\n\n.chat-msg \
  5839. .user .icon.firstEvent20183rd::before\t{ background-image: url('images/chat-icons/30.png'); }\n\n.chat-msg \
  5840. .user .icon.firstEvent20184th::before\t{ background-image: url('images/chat-icons/31.png'); }\n\n.chat-msg \
  5841. .user:not([data-same-user=\"true\"]) .name\n{\n\tcolor: rgba(0, 0, 0, 0.7);\n\tcursor: pointer;\n}\n.chat-msg \
  5842. .user .name.chat-tag-donor::before\n{\n\tbackground-image: url('images/chat-icons/donor.png');\n\tbackground-size: 20px 20px;\
  5843. \n\tcontent: '';\n\tdisplay: inline-block;\n\theight: 20px;\n\twidth: 20px;\n\tvertical-align: middle;\n}\n.chat-msg \
  5844. .user .name.chat-tag-yell\n{\n\tcursor: default;\n}\n#" + CHAT_BOX_ID + ".showTags .chat-msg \
  5845. .user .name.chat-tag-contributor,\n#" + CHAT_BOX_ID + ".showTags .chat-msg \
  5846. .user .name.chat-tag-mod,\n#" + CHAT_BOX_ID + ".showTags .chat-msg \
  5847. .user .name.chat-tag-dev,\n#" + CHAT_BOX_ID + ".showTags .chat-msg \
  5848. .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;\
  5849. \n\tpadding-bottom: 2px;\n\ttext-align: center;\n\t/* 2px border, 10 padding */\n\twidth: calc(100% - 2*1px - 2*5px);\
  5850. \n}\n#" + CHAT_BOX_ID + ":not(.showTags) .chat-msg .user .name.chat-tag-contributor,\n#" + CHAT_BOX_ID + ":not(.showTags) .chat-msg \
  5851. .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 \
  5852. .user .name.chat-tag-yell\n{\n\tbackground: initial;\n\tborder: inherit;\n\tfont-family: inherit;\n\tfont-size: inherit;\n\tpadding: initial;\
  5853. \n}\n\n.chat-msg[data-type=\"" + Type.reload + "\"] .user > *,\n.chat-msg[data-type=\"" + Type.pmReceived + "\"] .user > .icon,\
  5854. \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");
  5855. }
  5856.  
  5857. function initColorizer(init)
  5858. {
  5859. if (init === void 0)
  5860. {
  5861. init = false;
  5862. }
  5863. var usernameList = user2Color && Array.from(user2Color.keys()) || [];
  5864. user2Color = new Map();
  5865. usedColors = new Set();
  5866. for (var _i = 0, reservedColors_1 = reservedColors; _i < reservedColors_1.length; _i++)
  5867. {
  5868. var color = reservedColors_1[_i];
  5869. usedColors.add(color);
  5870. }
  5871. var colorStyle = getStyle('name-color');
  5872. colorStyle.innerHTML = '';
  5873. for (var _a = 0, usernameList_1 = usernameList; _a < usernameList_1.length; _a++)
  5874. {
  5875. var username = usernameList_1[_a];
  5876. colorizeMsg(username);
  5877. }
  5878. if (init)
  5879. {
  5880. settings.observeSub(settings.KEY.colorizeChat, 'colorizer', function ()
  5881. {
  5882. return initColorizer();
  5883. });
  5884. }
  5885. }
  5886.  
  5887. function addIntelligentScrolling()
  5888. {
  5889. // add checkbox instead of button for toggling auto scrolling
  5890. var btn = document.querySelector('input[value="Toggle Autoscroll"]');
  5891. var btnParent = btn.parentElement;
  5892. var checkboxId = 'chat-toggle-autoscroll';
  5893. // create checkbox
  5894. var toggleCheckbox = document.createElement('input');
  5895. toggleCheckbox.type = 'checkbox';
  5896. toggleCheckbox.id = checkboxId;
  5897. toggleCheckbox.checked = true;
  5898. // create label
  5899. var toggleLabel = document.createElement('label');
  5900. toggleLabel.htmlFor = checkboxId;
  5901. toggleLabel.textContent = 'Autoscroll';
  5902. btnParent.insertBefore(toggleCheckbox, btn);
  5903. btnParent.insertBefore(toggleLabel, btn);
  5904. btn.style.display = 'none';
  5905. var chatArea = document.getElementById(GENERAL_CHAT_DIV_ID);
  5906. var showScrollTextTimeout = null;
  5907.  
  5908. function setAutoScrolling(value, full)
  5909. {
  5910. if (full === void 0)
  5911. {
  5912. full = false;
  5913. }
  5914. if (win.isAutoScrolling != value)
  5915. {
  5916. toggleCheckbox.checked = value;
  5917. win.isAutoScrolling = value;
  5918. var icon_2 = 'none';
  5919. var color_1 = value ? 'lime' : 'red';
  5920. var text_1 = (value ? 'En' : 'Dis') + 'abled' + (full ? ' Autoscroll' : '');
  5921. if (full)
  5922. {
  5923. if (showScrollTextTimeout)
  5924. {
  5925. win.clearTimeout(showScrollTextTimeout);
  5926. }
  5927. showScrollTextTimeout = win.setTimeout(function ()
  5928. {
  5929. return win.scrollText(icon_2, color_1, text_1);
  5930. }, 300);
  5931. }
  5932. else
  5933. {
  5934. win.scrollText(icon_2, color_1, text_1);
  5935. }
  5936. setNewCounter(getSelectedTab(), 0, true);
  5937. return true;
  5938. }
  5939. return false;
  5940. }
  5941. toggleCheckbox.addEventListener('change', function ()
  5942. {
  5943. setAutoScrolling(this.checked);
  5944. if (this.checked && settings.get(settings.KEY.intelligentScrolling))
  5945. {
  5946. chatArea.scrollTop = chatArea.scrollHeight - chatArea.clientHeight;
  5947. }
  5948. });
  5949. var placeholderTemplate = document.createElement('div');
  5950. placeholderTemplate.className = 'placeholder';
  5951. var childStore = new WeakMap();
  5952.  
  5953. function scrollHugeChat()
  5954. {
  5955. // # of children
  5956. var chunkNum = chatArea.children.length;
  5957. // start chunk hiding at a specific amount of chunks
  5958. if (chunkNum < CHUNK_HIDING_MIN_CHUNKS)
  5959. {
  5960. return;
  5961. }
  5962. var visibleTop = chatArea.scrollTop;
  5963. var visibleBottom = visibleTop + chatArea.clientHeight;
  5964. var referenceTop = visibleTop - win.innerHeight;
  5965. var referenceBottom = visibleBottom + win.innerHeight;
  5966. var top = 0;
  5967. // never hide the last element since its size may change at any time when a new message gets appended
  5968. for (var i = 0; i < chunkNum - 1; i++)
  5969. {
  5970. var child = chatArea.children[i];
  5971. var height = child.clientHeight;
  5972. var bottom = top + height;
  5973. var isVisible = top >= referenceTop && top <= referenceBottom
  5974. || bottom >= referenceTop && bottom <= referenceBottom
  5975. || top < referenceTop && bottom > referenceBottom;
  5976. var isPlaceholder = child.classList.contains('placeholder');
  5977. if (!isVisible && !isPlaceholder)
  5978. {
  5979. var newPlaceholder = placeholderTemplate.cloneNode(false);
  5980. newPlaceholder.style.height = height + 'px';
  5981. chatArea.replaceChild(newPlaceholder, child);
  5982. childStore.set(newPlaceholder, child);
  5983. }
  5984. else if (isVisible && isPlaceholder)
  5985. {
  5986. var oldChild = childStore.get(child);
  5987. chatArea.replaceChild(oldChild, child);
  5988. childStore.delete(child);
  5989. }
  5990. top = bottom;
  5991. }
  5992. }
  5993. var delayedScrollStart = null;
  5994. var delayedScrollTimeout = null;
  5995. // does not consider pm tabs; may be changed in a future version?
  5996. chatArea.addEventListener('scroll', function ()
  5997. {
  5998. if (settings.get(settings.KEY.intelligentScrolling))
  5999. {
  6000. var scrolled2Bottom = (chatArea.scrollTop + chatArea.clientHeight) >= chatArea.scrollHeight - 1;
  6001. setAutoScrolling(scrolled2Bottom, true);
  6002. }
  6003. var n = now();
  6004. if (delayedScrollStart == null)
  6005. {
  6006. delayedScrollStart = n;
  6007. }
  6008. if (delayedScrollStart + 300 > n)
  6009. {
  6010. if (delayedScrollTimeout)
  6011. {
  6012. win.clearTimeout(delayedScrollTimeout);
  6013. }
  6014. delayedScrollTimeout = win.setTimeout(function ()
  6015. {
  6016. delayedScrollStart = null;
  6017. delayedScrollTimeout = null;
  6018. scrollHugeChat();
  6019. }, 50);
  6020. }
  6021. });
  6022. }
  6023.  
  6024. function getSelectedTab()
  6025. {
  6026. return document.querySelector('#' + CHAT_TABS_ID + ' .chat-tab.selected');
  6027. }
  6028.  
  6029. function getSelectedTabUsername()
  6030. {
  6031. var selectedTab = getSelectedTab();
  6032. return selectedTab.dataset.username || '';
  6033. }
  6034.  
  6035. function clickChatTab(newTab)
  6036. {
  6037. var oldTab = getSelectedTab();
  6038. if (newTab == oldTab)
  6039. {
  6040. return;
  6041. }
  6042. changeChatTab(oldTab, newTab);
  6043. }
  6044.  
  6045. function clickCloseChatTab(tab)
  6046. {
  6047. var username = tab.dataset.username || '';
  6048. var chatPanel = getChatPanel(username);
  6049. if (chatPanel.children.length === 0
  6050. || confirm("Do you want to close the pm tab of \"" + username + "\"?"))
  6051. {
  6052. closeChatTab(username);
  6053. }
  6054. }
  6055.  
  6056. function checkSetting(init)
  6057. {
  6058. if (init === void 0)
  6059. {
  6060. init = false;
  6061. }
  6062. var enabled = settings.get(settings.KEY.useNewChat);
  6063. // dis-/enable chat tabs
  6064. var chatTabs = document.getElementById(CHAT_TABS_ID);
  6065. chatTabs.style.display = enabled ? '' : 'none';
  6066. // dis-/enable checkbox for intelligent scrolling
  6067. var intelScrollId = 'chat-toggle-intelligent-scroll';
  6068. var input = document.getElementById(intelScrollId);
  6069. if (input)
  6070. {
  6071. input.style.display = enabled ? '' : 'none';
  6072. }
  6073. var label = document.querySelector('label[for="' + intelScrollId + '"]');
  6074. if (label)
  6075. {
  6076. label.style.display = enabled ? '' : 'none';
  6077. }
  6078. // virtually click on a tab
  6079. var defaultTab = getChatTab('', SpecialTab.default);
  6080. var generalTab = getChatTab('', SpecialTab.general);
  6081. clickChatTab(enabled ? generalTab : defaultTab);
  6082. if (init)
  6083. {
  6084. settings.observe(settings.KEY.useNewChat, function ()
  6085. {
  6086. return checkSetting(false);
  6087. });
  6088. }
  6089. }
  6090.  
  6091. function addChatTabs()
  6092. {
  6093. var chatBoxArea = document.getElementById(CHAT_BOX_ID);
  6094. var chatTabs = document.createElement('div');
  6095. chatTabs.id = CHAT_TABS_ID;
  6096. chatTabs.addEventListener('click', function (event)
  6097. {
  6098. var newTab = event.target;
  6099. if (newTab.classList.contains('close'))
  6100. {
  6101. return clickCloseChatTab(newTab.parentElement);
  6102. }
  6103. if (!newTab.classList.contains('chat-tab') || newTab.classList.contains('filler'))
  6104. {
  6105. return;
  6106. }
  6107. clickChatTab(newTab);
  6108. });
  6109. chatBoxArea.appendChild(chatTabs);
  6110. // default tab (for disabled new chat)
  6111. getChatTab('', SpecialTab.default);
  6112. // general server chat
  6113. var generalTab = getChatTab('', SpecialTab.general);
  6114. generalTab.textContent = 'Server';
  6115. getChatPanel('');
  6116. getChatTab('', SpecialTab.filler);
  6117. var _sendChat = win.sendChat;
  6118. win.sendChat = function (inputEl)
  6119. {
  6120. var msg = inputEl.value;
  6121. var selectedTab = document.querySelector('.chat-tab.selected');
  6122. if (selectedTab.dataset.username != '' && msg[0] != '/')
  6123. {
  6124. inputEl.value = '/pm ' + (selectedTab.dataset.username || '').replace(/ /g, '_') + ' ' + msg;
  6125. }
  6126. _sendChat(inputEl);
  6127. };
  6128. }
  6129.  
  6130. function switch2PmTab(username)
  6131. {
  6132. if (settings.get(settings.KEY.useNewChat)){
  6133. var newTab = getChatTab(username, null);
  6134. clickChatTab(newTab);
  6135. }
  6136. }
  6137.  
  6138. function notifyPm(data)
  6139. {
  6140. notifications.event('Message from "' + data.username + '"'
  6141. , {
  6142. body: data.msg
  6143. , onclick: function ()
  6144. {
  6145. return switch2PmTab(data.username);
  6146. }
  6147. , whenActive: getSelectedTab().dataset.username != data.username
  6148. });
  6149. }
  6150.  
  6151. function checkMentionAndKeywords(data)
  6152. {
  6153. var lowerMsg = data.msg.toLowerCase();
  6154. var usernameRegex = new RegExp('\\b' + win.username + '\\b', 'i');
  6155. if (settings.getSub(settings.KEY.showNotifications, 'mention') && usernameRegex.test(lowerMsg))
  6156. // if (lowerMsg.indexOf(win.username) > -1)
  6157. {
  6158. notifications.event('You\'ve been mentioned'
  6159. , {
  6160. body: data.msg
  6161. });
  6162. }
  6163. var match = [];
  6164. for (var _i = 0, keywordList_1 = chat.keywordList; _i < keywordList_1.length; _i++)
  6165. {
  6166. var keyword = keywordList_1[_i];
  6167. var regex = new RegExp('\\b' + keyword + '\\b', 'i');
  6168. if (regex.test(lowerMsg))
  6169. // if (lowerMsg.indexOf(keyword) > -1)
  6170. {
  6171. match.push(keyword);
  6172. }
  6173. }
  6174. if (settings.getSub(settings.KEY.showNotifications, 'keyword') && match.length > 0)
  6175. {
  6176. notifications.event('Keyword: "' + match.join('", "') + '"'
  6177. , {
  6178. body: data.msg
  6179. });
  6180. }
  6181. }
  6182. var addToChatBox_ = null;
  6183.  
  6184. function newAddToChatBox(username, icon, tag, msg, isPM)
  6185. {
  6186. var data = processChatData(username, icon, tag, msg, isPM);
  6187. var isThisSpam = false;
  6188. if (isDataPM(data))
  6189. {
  6190. if (data.type == Type.pmSent)
  6191. {
  6192. switch2PmTab(data.username);
  6193. }
  6194. else
  6195. {
  6196. notifyPm(data);
  6197. }
  6198. }
  6199. else
  6200. {
  6201. isThisSpam = settings.get(settings.KEY.enableSpamDetection) && isSpam(data);
  6202. if (!isThisSpam && data.username != win.username)
  6203. {
  6204. // check mentioning and keywords only for non-pms and only for messages from other players
  6205. checkMentionAndKeywords(data);
  6206. }
  6207. }
  6208. if (isThisSpam)
  6209. {
  6210. console.info('detected spam:', data);
  6211. }
  6212. else
  6213. {
  6214. add2ChatHistory(data);
  6215. add2Chat(data);
  6216. }
  6217. var fn = addToChatBox_ == null ? win.addToChatBox : addToChatBox_;
  6218. fn(username, icon, tag, msg, isPM);
  6219. }
  6220. chat.newAddToChatBox = newAddToChatBox;
  6221.  
  6222. function openPmTab(username)
  6223. {
  6224. if (username == win.username || username == '')
  6225. {
  6226. return;
  6227. }
  6228. var userTab = getChatTab(username, null);
  6229. clickChatTab(userTab);
  6230. var input = document.getElementById(CHAT_INPUT_ID);
  6231. input.focus();
  6232. }
  6233.  
  6234. function newChat()
  6235. {
  6236. addChatTabs();
  6237. applyChatStyle();
  6238. initColorizer(true);
  6239. addToChatBox_ = win.addToChatBox;
  6240. win.addToChatBox = newAddToChatBox;
  6241. chatInitialized = true;
  6242. var chatbox = document.getElementById(CHAT_BOX_ID);
  6243. chatbox.addEventListener('click', function (event)
  6244. {
  6245. var target = event.target;
  6246. var userEl = target && target.parentElement;
  6247. if (!target || !userEl || !target.classList.contains('name') || !userEl.classList.contains('user'))
  6248. {
  6249. return;
  6250. }
  6251. if (userEl.dataset.sameUser != 'true')
  6252. {
  6253. openPmTab(userEl.dataset.name || '');
  6254. }
  6255. });
  6256. chatbox.addEventListener('mouseover', function (event)
  6257. {
  6258. var target = event.target;
  6259. if (!target.classList.contains('timestamp') || !target.dataset.timestamp)
  6260. {
  6261. return;
  6262. }
  6263. var timestamp = parseInt(target.dataset.timestamp || '0', 10);
  6264. target.dataset.fulltime = (new Date(timestamp)).toLocaleDateString(LOCALE, LOCALE_OPTIONS);
  6265. target.dataset.timestamp = '';
  6266. });
  6267. // add context menu
  6268. var contextmenu = document.createElement('ul');
  6269. contextmenu.id = CONTEXTMENU_ID;
  6270. contextmenu.style.display = 'none';
  6271. 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>";
  6272. document.body.appendChild(contextmenu);
  6273. win.$(contextmenu).menu(
  6274. {
  6275. items: '> :not(.ui-widget-header)'
  6276. });
  6277. var nameListEl = contextmenu.querySelector('.name');
  6278. var nameDivEl = nameListEl.firstElementChild;
  6279. var muteEl = contextmenu.querySelector('.mute');
  6280. var unmuteEl = contextmenu.querySelector('.unmute');
  6281. chatbox.addEventListener('contextmenu', function (event)
  6282. {
  6283. var target = event.target;
  6284. var userEl = target && target.parentElement;
  6285. if (!userEl || !userEl.classList.contains('user'))
  6286. {
  6287. return;
  6288. }
  6289. var username = userEl.dataset.name;
  6290. // ignore clicks on server messages or other special messages
  6291. if (!username || userEl.dataset.sameUser == 'true')
  6292. {
  6293. return;
  6294. }
  6295. contextmenu.style.left = event.clientX + 'px';
  6296. contextmenu.style.top = event.clientY + 'px';
  6297. contextmenu.style.display = '';
  6298. contextmenu.dataset.username = username;
  6299. nameDivEl.textContent = username;
  6300. var isMuted = win.mutedPeople.indexOf(username) !== -1;
  6301. muteEl.style.display = isMuted ? 'none' : '';
  6302. unmuteEl.style.display = isMuted ? '' : 'none';
  6303. event.stopPropagation();
  6304. event.preventDefault();
  6305. });
  6306. // add click listener for context menu and stop propagation
  6307. contextmenu.addEventListener('click', function (event)
  6308. {
  6309. var target = event.target;
  6310. event.stopPropagation();
  6311. while (target && target.id != CONTEXTMENU_ID && target.tagName != 'LI')
  6312. {
  6313. target = target.parentElement;
  6314. }
  6315. if (!target || target.id == CONTEXTMENU_ID)
  6316. {
  6317. return;
  6318. }
  6319. var username = contextmenu.dataset.username || '';
  6320. if (target.classList.contains('open-pm'))
  6321. {
  6322. openPmTab(username);
  6323. }
  6324. else if (target.classList.contains('stats'))
  6325. {
  6326. win.lookup(username);
  6327. }
  6328. else if (target.classList.contains('mute'))
  6329. {
  6330. if (username == '')
  6331. {
  6332. return;
  6333. }
  6334. win.mutedPeople.push(username);
  6335. win.scrollText('none', 'lime', '<em>' + username + '</em> muted');
  6336. }
  6337. else if (target.classList.contains('unmute'))
  6338. {
  6339. if (username == '')
  6340. {
  6341. return;
  6342. }
  6343. var index = win.mutedPeople.indexOf(username);
  6344. if (index !== -1)
  6345. {
  6346. win.mutedPeople.splice(index, 1);
  6347. }
  6348. win.scrollText('none', 'red', '<em>' + username + '</em> unmuted');
  6349. }
  6350. else
  6351. {
  6352. return;
  6353. }
  6354. contextmenu.style.display = 'none';
  6355. });
  6356. // add click listener to hide context menu
  6357. document.addEventListener('click', function (event)
  6358. {
  6359. if (contextmenu.style.display != 'none')
  6360. {
  6361. contextmenu.style.display = 'none';
  6362. }
  6363. });
  6364. win.addEventListener('contextmenu', function (event)
  6365. {
  6366. if (contextmenu.style.display != 'none')
  6367. {
  6368. contextmenu.style.display = 'none';
  6369. }
  6370. });
  6371. // handle settings
  6372. var showSettings = [settings.KEY.showTimestamps, settings.KEY.showIcons, settings.KEY.showTags];
  6373.  
  6374. function setShowSetting(key)
  6375. {
  6376. var enabled = settings.get(key);
  6377. chatbox.classList[enabled ? 'add' : 'remove'](settings.KEY[key]);
  6378. }
  6379. for (var _i = 0, showSettings_1 = showSettings; _i < showSettings_1.length; _i++)
  6380. {
  6381. var key = showSettings_1[_i];
  6382. setShowSetting(key);
  6383. settings.observe(key, function (k)
  6384. {
  6385. return setShowSetting(k);
  6386. });
  6387. }
  6388. }
  6389.  
  6390. function addCommandSuggester()
  6391. {
  6392. var input = document.getElementById(CHAT_INPUT_ID);
  6393. input.addEventListener('keyup', function (event)
  6394. {
  6395. if (event.key == 'Backspace' || event.key == 'Delete' || event.key == 'Enter' || event.key == 'Tab'
  6396. || input.selectionStart != input.selectionEnd
  6397. || input.selectionStart != input.value.length
  6398. || !input.value.startsWith('/'))
  6399. {
  6400. return;
  6401. }
  6402. var value = input.value.substr(1);
  6403. for (var _i = 0, COMMANDS_1 = COMMANDS; _i < COMMANDS_1.length; _i++)
  6404. {
  6405. var cmd = COMMANDS_1[_i];
  6406. if (cmd.startsWith(value))
  6407. {
  6408. input.value = '/' + cmd;
  6409. input.selectionStart = 1 + value.length;
  6410. input.selectionEnd = input.value.length;
  6411. break;
  6412. }
  6413. }
  6414. });
  6415. }
  6416.  
  6417. function addOwnCommands()
  6418. {
  6419. COMMANDS.push(TUTORIAL_CMD);
  6420.  
  6421. function processOwnCommands(value)
  6422. {
  6423. if (!value.startsWith('/'))
  6424. {
  6425. return value;
  6426. }
  6427. var msgPrefix = '/';
  6428. var msg = value.substr(1);
  6429. if (msg.startsWith('pm'))
  6430. {
  6431. var split = msg.split(' ');
  6432. msgPrefix = '/' + split.slice(0, 2).join(' ') + ' ';
  6433. msg = split.slice(2).join(' ');
  6434. }
  6435. if (msg.startsWith(CLEAR_CMD))
  6436. {
  6437. // clear current chat (pm chat, or general chat)
  6438. var username = getSelectedTabUsername();
  6439. clearChat(username);
  6440. }
  6441. else if (msg.startsWith(TUTORIAL_CMD))
  6442. {
  6443. // thanks aguyd (https://greasyfork.org/forum/profile/aguyd) for the idea
  6444. var name_2 = msg.substr(TUTORIAL_CMD.length).trim();
  6445. msgPrefix = '';
  6446. msg = 'https://www.reddit.com/r/DiamondHunt/comments/5vrufh/diamond_hunt_2_starter_faq/';
  6447. if (name_2.length != 0)
  6448. {
  6449. // maybe add '@' before the name?
  6450. msg = name_2 + ', ' + msg;
  6451. }
  6452. }
  6453. return msgPrefix + msg;
  6454. }
  6455. var _sendChat = win.sendChat;
  6456. win.sendChat = function (inputEl)
  6457. {
  6458. inputEl.value = processOwnCommands(inputEl.value);
  6459. _sendChat(inputEl);
  6460. };
  6461. }
  6462.  
  6463. function checkColorize(init)
  6464. {
  6465. if (init === void 0)
  6466. {
  6467. init = false;
  6468. }
  6469. var chatDiv = document.getElementById(CHAT_BOX_ID);
  6470. chatDiv.classList[settings.get(settings.KEY.colorizeChat) ? 'add' : 'remove'](COLORIZE_CLASS);
  6471. if (init)
  6472. {
  6473. settings.observe(settings.KEY.colorizeChat, function ()
  6474. {
  6475. return checkColorize(false);
  6476. });
  6477. }
  6478. }
  6479.  
  6480. function init()
  6481. {
  6482. newChat();
  6483. addIntelligentScrolling();
  6484. addCommandSuggester();
  6485. addOwnCommands();
  6486. checkColorize(true);
  6487. checkSetting(true);
  6488. var _enlargeChat = win.enlargeChat;
  6489. var chatBoxArea = document.getElementById(CHAT_BOX_ID);
  6490.  
  6491. function setChatBoxHeight(height)
  6492. {
  6493. var defaultChat = document.getElementById(DEFAULT_CHAT_DIV_ID);
  6494. defaultChat.style.height = height;
  6495. var generalChat = document.getElementById(GENERAL_CHAT_DIV_ID);
  6496. generalChat.style.height = height;
  6497. var chatDivs = chatBoxArea.querySelectorAll('div[id^="' + PM_CHAT_DIV_PREFIX + '"]');
  6498. for (var i = 0; i < chatDivs.length; i++)
  6499. {
  6500. chatDivs[i].style.height = height;
  6501. }
  6502. }
  6503. win.enlargeChat = function (enlargeB)
  6504. {
  6505. _enlargeChat(enlargeB);
  6506. var defaultChatDiv = document.getElementById(DEFAULT_CHAT_DIV_ID);
  6507. var height = defaultChatDiv.style.height;
  6508. store.set('chat.height', height);
  6509. setChatBoxHeight(height);
  6510. handleScrolling(defaultChatDiv);
  6511. };
  6512. setChatBoxHeight(store.get('chat.height'));
  6513. // add history to chat
  6514. // TEMP >>>
  6515. // move pm entries to pm history
  6516. var changed = false;
  6517. for (var i = 0; i < chatHistory.length; i++)
  6518. {
  6519. var data = chatHistory[i];
  6520. if (isDataPM(data))
  6521. {
  6522. chatHistory.splice(i, 1);
  6523. i--;
  6524. pmHistory.push(data);
  6525. changed = true;
  6526. }
  6527. }
  6528. if (changed)
  6529. {
  6530. saveChatHistory();
  6531. savePmHistory();
  6532. }
  6533. // TEMP <<<
  6534. chatHistory.forEach(function (d)
  6535. {
  6536. return add2Chat(d);
  6537. });
  6538. pmHistory.forEach(function (d)
  6539. {
  6540. return add2Chat(d);
  6541. });
  6542. if (chatboxFragments)
  6543. {
  6544. chatboxFragments.forEach(function (fragment, key)
  6545. {
  6546. var chatbox = getChatPanel(key);
  6547. chatbox.appendChild(fragment);
  6548. });
  6549. chatboxFragments = null;
  6550. }
  6551. // reset the new counter for all tabs
  6552. var tabs = document.querySelectorAll('.chat-tab');
  6553. for (let i = 0; i < tabs.length; i++)
  6554. {
  6555. setNewCounter(tabs[i], 0, true);
  6556. }
  6557. }
  6558. chat.init = init;
  6559. var _a;
  6560. })(chat || (chat = {}));
  6561.  
  6562. /**
  6563. * hopefully only temporary fixes
  6564. */
  6565. var temporaryFixes;
  6566. (function (temporaryFixes)
  6567. {
  6568. temporaryFixes.name = 'temporaryFixes';
  6569. function fixMagicShopButton(){
  6570. var getBackButton = $("#tab-container-magicShop span:first");
  6571. getBackButton.prop("class", "medium-button");
  6572. getBackButton.html(`<img class="image-icon-30" src="images/icons/back.png"> back`);
  6573. getBackButton.after("<br/><br/>");
  6574. }
  6575. function fixWrongURLs()
  6576. {
  6577. var image = document.querySelectorAll('.dialogue-loot .image-icon-50');
  6578. for (var i=0; i < image.length; i++){
  6579. var key = image[i];
  6580. var change = key.src = key.src.replace('/images/icons/darkTombKey.png','/images/darkTombKey.png');
  6581. }
  6582. }
  6583. // update spells being clickable in combat
  6584. function setSpellsClickable()
  6585. {
  6586. var spellbox = document.getElementById('fight-spellboox');
  6587. if (spellbox)
  6588. {
  6589. for (var i = 0; i < spellbox.children.length; i++)
  6590. {
  6591. var child = spellbox.children.item(i);
  6592. if (!win.isInCombat() && child.hasAttribute('onclick'))
  6593. {
  6594. child.dataset.onclick = child.getAttribute('onclick') || '';
  6595. child.removeAttribute('onclick');
  6596. }
  6597. else if (win.isInCombat() && !!child.dataset.onclick)
  6598. {
  6599. child.setAttribute('onclick', child.dataset.onclick || '');
  6600. child.dataset.onclick = '';
  6601. }
  6602. }
  6603. }
  6604. }
  6605. // warn before unloading/reloading the tab if combat is in progress
  6606. function combatWarnOnUnload()
  6607. {
  6608. if (!win.isInCombat())
  6609. {
  6610. win.onbeforeunload = null;
  6611. }
  6612. else
  6613. {
  6614. if (win.onbeforeunload == null)
  6615. {
  6616. win.onbeforeunload = function ()
  6617. {
  6618. return 'You are in a fight!';
  6619. };
  6620. }
  6621. }
  6622. }
  6623.  
  6624. function fixCombatCountdown()
  6625. {
  6626. var el = document.getElementById('combat-countdown');
  6627. if (!el)
  6628. {
  6629. return;
  6630. }
  6631. if (win.isInCombat())
  6632. {
  6633. el.style.display = '';
  6634. var visible = win.combatCommenceTimer != 0;
  6635. el.style.visibility = visible ? '' : 'hidden';
  6636. }
  6637. }
  6638. // fix exhaustion timer and updating brewing and cooking recipes
  6639. function fixExhaustionTimer()
  6640. {
  6641. if (document.getElementById('tab-container-combat').style.display != 'none')
  6642. {
  6643. win.combatNotFightingTick();
  6644. }
  6645. }
  6646.  
  6647. function fixClientGameLoop()
  6648. {
  6649. var _clientGameLoop = win.clientGameLoop;
  6650. win.clientGameLoop = function ()
  6651. {
  6652. _clientGameLoop();
  6653. //setSpellsClickable();
  6654. combatWarnOnUnload();
  6655. fixCombatCountdown();
  6656. fixExhaustionTimer();
  6657. };
  6658. }
  6659. // fix elements of scrollText (e.g. when joining the game and receiving xp at that moment)
  6660. function fixScroller()
  6661. {
  6662. var textEls = document.querySelectorAll('div.scroller');
  6663. for (var i = 0; i < textEls.length; i++)
  6664. {
  6665. var scroller = textEls[i];
  6666. if (scroller.style.position != 'absolute')
  6667. {
  6668. scroller.style.display = 'none';
  6669. }
  6670. }
  6671. }
  6672. // fix style of tooltips
  6673. function fixTooltipStyle()
  6674. {
  6675. addStyle("\nbody > div.tooltip > h2:first-child\n{\n\tmargin-top: 0;\n\tfont-size: 20pt;\n\tfont-weight: normal;\n}\n\t\t");
  6676. }
  6677. // fix buiulding magic table dynamically
  6678. function fixRefreshingMagicRecipes()
  6679. {
  6680. // define missing properties for checking the needed materials
  6681. win.enchantStargemPotionMagic = 0;
  6682. win.changeWeatherMagic = 0;
  6683. win.refreshLoadMagicTable = false;
  6684. var _processMagicTab = win.processMagicTab;
  6685. win.processMagicTab = function ()
  6686. {
  6687. var _refreshLoadCraftingTable = win.refreshLoadCraftingTable;
  6688. win.refreshLoadCraftingTable = win.refreshLoadMagicTable;
  6689. _processMagicTab();
  6690. win.refreshLoadCraftingTable = _refreshLoadCraftingTable;
  6691. if (win.magicPage3 == 1)
  6692. {
  6693. win.showMateriesNeededAndLevelLabelsMagic('enchantStargemPotion');
  6694. win.showMateriesNeededAndLevelLabelsMagic('beam');
  6695. win.showMateriesNeededAndLevelLabelsMagic('changeWeather');
  6696. }
  6697. };
  6698. }
  6699.  
  6700. function moveItemBox(itemKey, targetElId, color1, color2)
  6701. {
  6702. var itemBox = document.getElementById('item-box-' + itemKey);
  6703. var targetContainer = document.getElementById(targetElId);
  6704. targetContainer.appendChild(itemBox);
  6705. // remove event listeners before binding the tooltip to it
  6706. var $itemBox = win.$(itemBox);
  6707. $itemBox.off('mouseover').off('mouseleave');
  6708. itemBox.title = '';
  6709. // bind tooltip to item box
  6710. ensureTooltip('ingredient-secondary', itemBox);
  6711. // change color
  6712. itemBox.style.background = 'linear-gradient(' + color1 + ', ' + color2 + ')';
  6713. $itemBox
  6714. .mouseover(function ()
  6715. {
  6716. itemBox.style.background = 'none';
  6717. itemBox.style.backgroundColor = color2;
  6718. })
  6719. .mouseleave(function ()
  6720. {
  6721. itemBox.style.background = 'linear-gradient(' + color1 + ', ' + color2 + ')';
  6722. });
  6723. }
  6724. // move the strange leaf to brewing tab (thanks lasse_brus for this idea)
  6725. function moveStrangeLeafs()
  6726. {
  6727. //moveItemBox('strangeBlueLeaf', 'tab-sub-container-brewing', '#800080', '#990099');
  6728. //moveItemBox('strangePinkLeaf', 'tab-sub-container-brewing', '#800080', '#990099');
  6729. }
  6730. // fix height of map item
  6731. function fixTreasureMap()
  6732. {
  6733. var mapBox = document.getElementById('item-box-treasureMap');
  6734. var numSpan = mapBox.lastElementChild;
  6735. numSpan.style.display = '';
  6736. numSpan.style.visibility = 'hidden';
  6737. }
  6738. // fix wobbling tree places on hover (in wood cutting)
  6739. function fixWoodcutting()
  6740. {
  6741. addStyle("\nimg.woodcutting-tree-img\n{\n\tborder: 1px solid transparent;\n}\n\t\t");
  6742. }
  6743. // fix wobbling quest rows on hover (in quest book)
  6744. function fixQuestBook()
  6745. {
  6746. addStyle("\n#table-quest-list tr\n{\n\tborder: 1px solid transparent;\n}\n\t\t");
  6747. }
  6748.  
  6749. function fixScrollImages()
  6750. {
  6751. function fixIcon(icon)
  6752. {
  6753. return icon + (icon != 'none' && !/\..{3,4}$/.test(icon) ? '.png' : '');
  6754. }
  6755. var _scrollTextHitSplat = win.scrollTextHitSplat;
  6756. win.scrollTextHitSplat = function (icon, color, text, elId, cbType)
  6757. {
  6758. _scrollTextHitSplat(fixIcon(icon), color, text, elId, cbType);
  6759. };
  6760. var _scrollText = win.scrollText;
  6761. win.scrollText = function (icon, color, text)
  6762. {
  6763. _scrollText(fixIcon(icon), color, text);
  6764. };
  6765. }
  6766.  
  6767. function fixQuest8BraveryRecipe()
  6768. {
  6769. observer.add([
  6770. 'quest8'
  6771. , 'braveryPotion'
  6772. ], function ()
  6773. {
  6774. var show = win.quest8 > 0 && win.braveryPotion == 0;
  6775. var recipe = document.getElementById('brewing-braveryPotion');
  6776. if (recipe)
  6777. {
  6778. recipe.style.display = show ? '' : 'none';
  6779. }
  6780. });
  6781. }
  6782.  
  6783. function fixHitText()
  6784. {
  6785. win.scrollTextHitSplat = function (icon, color, text, elId, cbType)
  6786. {
  6787. var imgTag = icon != 'none' ? "<img src=\"images/" + icon + "\" class=\"image-icon-50\" />" : '';
  6788. var elementChosen = document.getElementById(elId);
  6789. if (!elementChosen)
  6790. {
  6791. return;
  6792. }
  6793. var rect = elementChosen.getBoundingClientRect();
  6794. var xCoord = (rect.left + rect.right) / 2;
  6795. var yCoord = (rect.bottom + rect.top) / 2;
  6796. var extraStyle = '';
  6797. if (cbType == 'melee')
  6798. {
  6799. extraStyle = 'border: 1px solid red; background-color: #4d0000;';
  6800. }
  6801. else if (cbType == 'heal')
  6802. {
  6803. extraStyle = 'border: 1px solid green; background-color: lime;';
  6804. }
  6805. var $elementToAppend = win.$("<div class=\"scroller\" style=\"" + extraStyle + " color: " + color + "; position: fixed;\">" + imgTag + text + "</div>").appendTo('body');
  6806. if (xCoord == 0 && yCoord == 0)
  6807. {
  6808. var tab = document.getElementById('tab-container-bar-combat');
  6809. var tabRect = tab.getBoundingClientRect();
  6810. var boxRect = $elementToAppend.get(0).getBoundingClientRect();
  6811. xCoord = elId == 'img-hero' ? (tabRect.left - boxRect.width) : tabRect.right;
  6812. yCoord = tabRect.top;
  6813. }
  6814. $elementToAppend
  6815. .css(
  6816. {
  6817. left: xCoord
  6818. , top: yCoord
  6819. })
  6820. .animate(
  6821. {
  6822. top: '-=50px'
  6823. }, function ()
  6824. {
  6825. return $elementToAppend.fadeOut(1000, function ()
  6826. {
  6827. return $elementToAppend.remove();
  6828. });
  6829. });
  6830. };
  6831. }
  6832.  
  6833. function fixBoatTooltips()
  6834. {
  6835. var boatBox = document.getElementById('item-box-boundRowBoat');
  6836. var boatTooltip = boatBox && document.getElementById(boatBox.dataset.tooltipId || '');
  6837. var tooltipParent = boatTooltip && boatTooltip.parentElement;
  6838. if (!boatBox || !boatTooltip || !tooltipParent)
  6839. {
  6840. return;
  6841. }
  6842.  
  6843. function setTripDuration(durationEl, boatKey)
  6844. {
  6845. var durationStr = TRIP_DURATION.hasOwnProperty(boatKey) ? TRIP_DURATION[boatKey].toString(10) : '?';
  6846. durationEl.innerHTML = "<strong>Trip duration:</strong> " + durationStr + " hours";
  6847. }
  6848. boatTooltip.id = boatBox.dataset.tooltipId = 'tooltip-boundRowBoat';
  6849. boatTooltip.appendChild(document.createElement('br'));
  6850. var boatDuration = document.createElement('span');
  6851. boatDuration.className = 'trip-duration';
  6852. setTripDuration(boatDuration, 'rowBoat');
  6853. boatTooltip.appendChild(boatDuration);
  6854. for (var _i = 0, BOAT_LIST_1 = BOAT_LIST; _i < BOAT_LIST_1.length; _i++)
  6855. {
  6856. var boatKey = BOAT_LIST_1[_i];
  6857. var boundKey = getBoundKey(boatKey);
  6858. var itemBox = document.getElementById('item-box-' + boundKey);
  6859. if (!itemBox)
  6860. {
  6861. continue;
  6862. }
  6863. var tooltip = document.getElementById('tooltip-' + boundKey);
  6864. if (!tooltip)
  6865. {
  6866. tooltip = boatTooltip.cloneNode(true);
  6867. tooltip.id = 'tooltip-' + boundKey;
  6868. var header = tooltip.firstElementChild;
  6869. header.textContent = capitalize(split2Words(boatKey));
  6870. tooltipParent.appendChild(tooltip);
  6871. itemBox.dataset.tooltipId = 'tooltip-' + boundKey;
  6872. }
  6873. var durationEl = tooltip.getElementsByClassName('trip-duration').item(0);
  6874. if (durationEl)
  6875. {
  6876. setTripDuration(durationEl, boatKey);
  6877. }
  6878. }
  6879. }
  6880.  
  6881. function fixAlignments()
  6882. {
  6883. 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");
  6884. }
  6885. function fixFontSize11Tabs()
  6886. {
  6887. var tabKey = ['items', 'skills', 'mining', 'crafting', 'woodcutting', 'farming', 'brewing', 'combat', 'magic', 'cooking', 'shop'];
  6888. for (var i = 0; i < tabKey.length; i++)
  6889. {
  6890. var tab = document.getElementById('tab-container-bar-'+ tabKey[i] +'-label');
  6891. tab.style.fontSize = "15px";
  6892. }
  6893. }
  6894. function addSpellTooltips()
  6895. {
  6896. var heal = document.querySelector('[data-spell-name="heal"]');
  6897. heal.title = 'Mana: 2';
  6898. win.$(heal).tooltip();
  6899. var pound = document.querySelector('[data-spell-name="pound"]');
  6900. pound.title = 'Mana: 2';
  6901. win.$(pound).tooltip();
  6902. var teleport = document.querySelector('[data-spell-name="teleport"]');
  6903. teleport.title = 'Mana: 10';
  6904. win.$(teleport).tooltip();
  6905. var gust = document.querySelector('[data-spell-name="gust"]');
  6906. gust.title = 'Mana: 3';
  6907. win.$(gust).tooltip();
  6908. var bubble = document.querySelector('[data-spell-name="bubble"]');
  6909. bubble.title = 'Mana: 10';
  6910. win.$(bubble).tooltip();
  6911. var sandstorm = document.querySelector('[data-spell-name="sandstorm"]');
  6912. sandstorm.title = 'Mana: 20';
  6913. win.$(sandstorm).tooltip();
  6914. var ghostScan = document.querySelector('[data-spell-name="ghostScan"]');
  6915. ghostScan.title = 'Mana: 20';
  6916. win.$(ghostScan).tooltip();
  6917. var beam = document.querySelector('[data-spell-name="beam"]');
  6918. beam.title = 'Mana: 15';
  6919. win.$(beam).tooltip();
  6920. var reflect = document.querySelector('[data-spell-name="reflect"]');
  6921. reflect.title = 'Mana: 20';
  6922. win.$(reflect).tooltip();
  6923. var superHeal = document.querySelector('[data-spell-name="superHeal"]');
  6924. superHeal.title = 'Mana: 8';
  6925. win.$(superHeal).tooltip();
  6926. var barrier = document.querySelector('[data-spell-name="barrier"]');
  6927. barrier.title = 'Mana: 25';
  6928. win.$(barrier).tooltip();
  6929. var healSteal = document.querySelector('[data-spell-name="healSteal"]');
  6930. healSteal.title = 'Mana: 25';
  6931. win.$(healSteal).tooltip();
  6932. var poison = document.querySelector('[data-spell-name="poison"]');
  6933. poison.title = 'Mana: 30';
  6934. win.$(poison).tooltip();
  6935. }
  6936. function addPotionsToSpellBox(){
  6937. $("#fight-spellboox").prepend(`<div></div>`);
  6938. var potList = ['antiDragonFirePotion', 'lootBagPotion', 'criticalStrikePotion', 'combatSelectorPotion', 'superCombatCooldownPotion', 'combatCooldownPotion', 'megaManaPotion',
  6939. 'superManaPotion', 'manaPotion'];
  6940. for (var i = 0; i < potList.length; i++){
  6941.  
  6942. $("#fight-spellboox div:first").prepend(`<span onclick="clicksPotion('`+potList[i]+`')" class="fight-spell"><img src="images/`+potList[i]+`.png" ></span>`);
  6943. }
  6944. $("#combat-potions-spell-book").attr("hidden", true);
  6945. $("#fight-spellboox div:first").append(`<hr>`);
  6946. }
  6947. function modifySpellImages()
  6948. {
  6949. var spell = document.querySelectorAll('.fight-spell');
  6950. for (var i = 0; i < spell.length; i++){
  6951. spell[i].style.width = '43px';
  6952. spell[i].style.height = '43px';
  6953. }
  6954. var img= [];
  6955. for (let i = 0; i < spell.length; i++){
  6956. img[i] = spell[i].getElementsByTagName('img')[0];
  6957. img[i].style.width = '43px';
  6958. }
  6959. }
  6960. function addHeroStatTooltips()
  6961. {
  6962. var table = document.querySelector('#hero-area table.table-hero-stats');
  6963. if (!table)
  6964. {
  6965. return;
  6966. }
  6967. var statRow = table.rows.item(0);
  6968. var attackCell = statRow.cells.item(0);
  6969. attackCell.title = 'Attack Damage';
  6970. win.$(attackCell).tooltip();
  6971. var accuracyCell = statRow.cells.item(1);
  6972. accuracyCell.title = 'Attack Accuracy';
  6973. win.$(accuracyCell).tooltip();
  6974. var speedCell = statRow.cells.item(2);
  6975. speedCell.title = 'Attack Speed';
  6976. win.$(speedCell).tooltip();
  6977. var defenseCell = statRow.cells.item(3);
  6978. defenseCell.title = 'Defense';
  6979. win.$(defenseCell).tooltip();
  6980. var magicCell = statRow.cells.item(4);
  6981. magicCell.title = 'Magic Bonus';
  6982. win.$(magicCell).tooltip();
  6983. // energy, cooldown, HP and mana
  6984. var energyRow = table.rows.item(1);
  6985. var energy = energyRow.cells.item(0);
  6986. energy.title = 'Energy';
  6987. var cdRow = table.rows.item(2);
  6988. var cd = cdRow.cells.item(0);
  6989. cd.title = 'Combat Cooldown';
  6990. var getHPbar = document.querySelectorAll('.inner-hp-bar-label');
  6991. getHPbar[0].title = 'Health Points';
  6992. var getManabar = document.querySelectorAll('.inner-mana-bar-label');
  6993. getManabar[0].title = 'Mana Points';
  6994. }
  6995.  
  6996. function unifyTooltips()
  6997. {
  6998. function getLastNonEmptyChild(parent)
  6999. {
  7000. for (var i = parent.childNodes.length - 1; i >= 0; i--)
  7001. {
  7002. var child = parent.childNodes.item(i);
  7003. if (child.nodeType === Node.TEXT_NODE
  7004. && (child.textContent || '').trim() !== '')
  7005. {
  7006. return null;
  7007. }
  7008. else if (child.nodeType === Node.ELEMENT_NODE)
  7009. {
  7010. return child;
  7011. }
  7012. }
  7013. return null;
  7014. }
  7015. // clean unnecessary br-tags in tooltips
  7016. var tooltips = document.querySelectorAll('#tooltip-list > div[id^="tooltip-"]');
  7017. for (var i = 0; i < tooltips.length; i++)
  7018. {
  7019. var tooltip = tooltips[i];
  7020. var lneChild = void 0;
  7021. while ((lneChild = getLastNonEmptyChild(tooltip)) && lneChild.tagName == 'BR')
  7022. {
  7023. tooltip.removeChild(lneChild);
  7024. }
  7025. }
  7026.  
  7027. function getTooltip(item)
  7028. {
  7029. return document.getElementById('tooltip-' + item);
  7030. }
  7031. var boldify = [
  7032. 'oilBarrel'
  7033. , 'boundEmptyPickaxe'
  7034. , 'boundEmptyShovel'
  7035. , 'boundRocket'
  7036. , 'ashes'
  7037. , 'iceBones'
  7038. ];
  7039. var lastDotRegex = /\.\s*$/;
  7040. for (var _i = 0, boldify_1 = boldify; _i < boldify_1.length; _i++)
  7041. {
  7042. var item = boldify_1[_i];
  7043. var tooltip = getTooltip(item);
  7044. if (!tooltip)
  7045. {
  7046. continue;
  7047. }
  7048. var textNode = tooltip.lastChild;
  7049. while (textNode && (textNode.nodeType != Node.TEXT_NODE || (textNode.textContent || '').trim() === ''))
  7050. {
  7051. if (textNode.nodeName === 'SPAN')
  7052. {
  7053. textNode = textNode.lastChild;
  7054. }
  7055. else
  7056. {
  7057. textNode = textNode.previousSibling;
  7058. }
  7059. }
  7060. if (!textNode)
  7061. {
  7062. continue;
  7063. }
  7064. var text = textNode.textContent || '';
  7065. var split = text.split(/\.(?=\s*\S+)/);
  7066. var clickText = split[split.length - 1];
  7067. textNode.textContent = text.replace(clickText, '');
  7068. if (split.length > 1)
  7069. {
  7070. tooltip.appendChild(document.createElement('br'));
  7071. tooltip.appendChild(document.createElement('br'));
  7072. }
  7073. var boldText = document.createElement('b');
  7074. boldText.textContent = clickText;
  7075. tooltip.appendChild(boldText);
  7076. }
  7077.  
  7078. function prepareTooltip(item, editText, createOnMissing)
  7079. {
  7080. if (createOnMissing === void 0)
  7081. {
  7082. createOnMissing = false;
  7083. }
  7084. var tooltip = getTooltip(item);
  7085. if (!tooltip)
  7086. {
  7087. return;
  7088. }
  7089. // try to find the b-node:
  7090. var bNode = getLastNonEmptyChild(tooltip);
  7091. if (bNode && bNode.tagName === 'SPAN')
  7092. {
  7093. bNode = getLastNonEmptyChild(bNode);
  7094. }
  7095. if (!bNode || bNode.tagName !== 'B')
  7096. {
  7097. if (!createOnMissing)
  7098. {
  7099. bNode = null;
  7100. }
  7101. else
  7102. {
  7103. tooltip.appendChild(document.createElement('br'));
  7104. tooltip.appendChild(document.createElement('br'));
  7105. bNode = document.createElement('b');
  7106. tooltip.appendChild(bNode);
  7107. }
  7108. }
  7109. if (bNode)
  7110. {
  7111. bNode.textContent = editText(bNode);
  7112. }
  7113. }
  7114. // remove dots
  7115. for (let i = 0; i < tooltips.length; i++)
  7116. {
  7117. let item = tooltips.item(i).id.replace(/^tooltip-/, '');
  7118. prepareTooltip(item, function (bNode)
  7119. {
  7120. var text = bNode.textContent || '';
  7121. if (/Click to /.test(text))
  7122. {
  7123. return text.replace(lastDotRegex, '');
  7124. }
  7125. return text;
  7126. });
  7127. }
  7128. // add click texts
  7129. function setText(item, text)
  7130. {
  7131. prepareTooltip(item, function ()
  7132. {
  7133. return text;
  7134. }, true);
  7135. }
  7136. for (var _a = 0, FURNACE_LEVELS_1 = FURNACE_LEVELS; _a < FURNACE_LEVELS_1.length; _a++)
  7137. {
  7138. var furnaceLevel = FURNACE_LEVELS_1[_a];
  7139. var furnaceItem = getBoundKey(furnaceLevel + 'Furnace');
  7140. setText(furnaceItem, 'Click to operate');
  7141. var ovenItem = getBoundKey(furnaceLevel + 'Oven');
  7142. setText(ovenItem, 'Click to operate');
  7143. }
  7144. // fix tooltip of quests-book
  7145. var questBookTooltip = getTooltip('quests-book');
  7146. if (questBookTooltip)
  7147. {
  7148. var childNodes = questBookTooltip.childNodes;
  7149. for (let i = 0; i < childNodes.length; i++)
  7150. {
  7151. var node = childNodes[i];
  7152. if (node.nodeType === Node.TEXT_NODE
  7153. && (node.textContent || '').indexOf('Click to see a list of quests.') > -1)
  7154. {
  7155. var next = node.nextSibling;
  7156. if (next)
  7157. {
  7158. questBookTooltip.removeChild(next);
  7159. }
  7160. questBookTooltip.removeChild(node);
  7161. }
  7162. }
  7163. }
  7164. // fix tooltip of axe
  7165. var axeTooltip = getTooltip('boundEmptyAxe');
  7166. if (axeTooltip)
  7167. {
  7168. axeTooltip.insertBefore(document.createElement('br'), axeTooltip.lastElementChild);
  7169. }
  7170. var texts = {
  7171. 'quests-book': 'Click to see the list of quests'
  7172. , 'achievementBook': 'Click to see the list of achievements'
  7173. , 'boundEmptyChisel': 'Click to use'
  7174. , 'rake': 'Click to upgrade your rake'
  7175. , 'boundBoat': 'Click to send boat'
  7176. };
  7177. for (let item in texts)
  7178. {
  7179. setText(item, texts[item]);
  7180. }
  7181. for (var _b = 0, BOAT_LIST_2 = BOAT_LIST; _b < BOAT_LIST_2.length; _b++)
  7182. {
  7183. var boatKey = BOAT_LIST_2[_b];
  7184. setText(getBoundKey(boatKey), 'Click to send boat');
  7185. }
  7186. }
  7187. var cached = {
  7188. scrollWidth: 0
  7189. , scrollHeight: 0
  7190. };
  7191.  
  7192. function changeTooltipPosition(event)
  7193. {
  7194. var tooltipX = event.pageX - 8;
  7195. var tooltipY = event.pageY + 8;
  7196. var el = document.querySelector('body > div.tooltip');
  7197. if (!el)
  7198. {
  7199. return;
  7200. }
  7201. if (!this)
  7202. {
  7203. // init
  7204. cached.scrollWidth = document.body.scrollWidth;
  7205. cached.scrollHeight = document.body.scrollHeight;
  7206. }
  7207. var rect = el.getBoundingClientRect();
  7208. var css = {
  7209. left: tooltipX
  7210. , top: tooltipY
  7211. , width: ''
  7212. , height: ''
  7213. , maxWidth: cached.scrollWidth
  7214. , maxHeight: cached.scrollHeight
  7215. };
  7216. var diffX = cached.scrollWidth - 20 - tooltipX - rect.width;
  7217. if (diffX < 0)
  7218. {
  7219. css.left += diffX;
  7220. css.width = rect.width - 42;
  7221. }
  7222. var diffY = cached.scrollHeight - 20 - tooltipY - rect.height;
  7223. if (diffY < 0)
  7224. {
  7225. css.top += diffY;
  7226. css.height = rect.height - 22;
  7227. }
  7228. win.$(el).css(css);
  7229. }
  7230.  
  7231. function fixTooltipPositioning()
  7232. {
  7233. win.changeTooltipPosition = changeTooltipPosition;
  7234. win.loadTooltips();
  7235. }
  7236.  
  7237. function fixCombatNavigation()
  7238. {
  7239. var backBtns = document.querySelectorAll('span.medium-button[onclick*="openTab(\'combat\')"]');
  7240. for (var i = 0; i < backBtns.length; i++)
  7241. {
  7242. var btn = backBtns.item(i);
  7243. var img = btn.firstElementChild;
  7244. var textNode = btn.lastChild;
  7245. if (!img || img.tagName != 'IMG' || !textNode)
  7246. {
  7247. continue;
  7248. }
  7249. img.className = img.className.replace(/(-\d+)-b/, '$1');
  7250. textNode.textContent = ' back';
  7251. }
  7252. }
  7253.  
  7254. function fixPromethiumSmeltingTime()
  7255. {
  7256. var _getTimerPerBar = win.getTimerPerBar;
  7257. win.getTimerPerBar = function (bar)
  7258. {
  7259. if (bar == 'promethiumBar')
  7260. {
  7261. return 80;
  7262. }
  7263. return _getTimerPerBar(bar);
  7264. };
  7265. }
  7266.  
  7267. function fixImage()
  7268. {
  7269. var oxygenEl = document.querySelector('img[src="images/oxygenPotion"]');
  7270. if (oxygenEl)
  7271. {
  7272. oxygenEl.src += '.png';
  7273. }
  7274. }
  7275.  
  7276. function init()
  7277. {
  7278. fixMagicShopButton();
  7279. fixWrongURLs();
  7280. fixClientGameLoop();
  7281. fixScroller();
  7282. fixTooltipStyle();
  7283. //fixRefreshingMagicRecipes();
  7284. moveStrangeLeafs();
  7285. fixTreasureMap();
  7286. fixWoodcutting();
  7287. fixQuestBook();
  7288. // apply fix for scroll images later to fix images in this code too
  7289. fixHitText();
  7290. fixScrollImages();
  7291. fixQuest8BraveryRecipe();
  7292. fixBoatTooltips();
  7293. fixAlignments();
  7294. addHeroStatTooltips();
  7295. fixFontSize11Tabs();
  7296. //addSpellTooltips();
  7297. addPotionsToSpellBox();
  7298. modifySpellImages();
  7299. unifyTooltips();
  7300. fixTooltipPositioning();
  7301. fixCombatNavigation();
  7302. fixPromethiumSmeltingTime();
  7303. fixImage();
  7304. }
  7305. temporaryFixes.init = init;
  7306. })(temporaryFixes || (temporaryFixes = {}));
  7307.  
  7308. /**
  7309. * improve timer
  7310. */
  7311. var timer;
  7312. (function (timer)
  7313. {
  7314. timer.name = 'timer';
  7315. var IMPROVED_CLASS = 'improved';
  7316. var NOTIFICATION_AREA_ID = 'notifaction-area';
  7317. var PERCENT_CLASS = 'percent';
  7318. var REMAINING_CLASS = 'remaining';
  7319. var TIMER_CLASS = 'timer';
  7320.  
  7321. function bindNewFormatter()
  7322. {
  7323. function doBind()
  7324. {
  7325. win.formatTime = win.formatTimeShort = win.formatTimeShort2 = function (seconds)
  7326. {
  7327. return format.timer(seconds);
  7328. };
  7329. }
  7330. win.addEventListener('load', function ()
  7331. {
  7332. return setTimeout(function ()
  7333. {
  7334. return doBind();
  7335. }, 100);
  7336. });
  7337. doBind();
  7338. setTimeout(function ()
  7339. {
  7340. return doBind();
  7341. }, 100);
  7342. }
  7343.  
  7344. function applyStyle()
  7345. {
  7346. 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");
  7347. }
  7348.  
  7349. function improveSmeltingTimer()
  7350. {
  7351. var el = document.getElementById('notif-smelting');
  7352. if (!el)
  7353. {
  7354. return;
  7355. }
  7356. var smeltingNotifBox = el;
  7357. smeltingNotifBox.classList.add(IMPROVED_CLASS);
  7358. var smeltingTimerEl = document.createElement('span');
  7359. smeltingTimerEl.className = TIMER_CLASS;
  7360. smeltingNotifBox.appendChild(smeltingTimerEl);
  7361. var remainingBarsEl = document.createElement('span');
  7362. remainingBarsEl.className = REMAINING_CLASS;
  7363. smeltingNotifBox.appendChild(remainingBarsEl);
  7364. var delta = 0;
  7365.  
  7366. function updatePercValues(init)
  7367. {
  7368. if (init === void 0)
  7369. {
  7370. init = false;
  7371. }
  7372. updateSmeltingTimer(delta = 0);
  7373. if (init)
  7374. {
  7375. observer.add('smeltingPercD', function ()
  7376. {
  7377. return updatePercValues();
  7378. });
  7379. observer.add('smeltingPerc', function ()
  7380. {
  7381. return updatePercValues();
  7382. });
  7383. }
  7384. }
  7385.  
  7386. function updateSmeltingTimer(delta)
  7387. {
  7388. if (delta === void 0)
  7389. {
  7390. delta = 0;
  7391. }
  7392. var totalTime = win.smeltingPercD;
  7393. // thanks at /u/marcus898 for your bug report
  7394. var elapsedTime = Math.round(win.smeltingPerc * totalTime / 100) + delta;
  7395. smeltingTimerEl.textContent = format.timer(Math.max(totalTime - elapsedTime, 0));
  7396. remainingBarsEl.textContent = (win.smeltingTotalAmount - win.smeltingAmount).toString();
  7397. }
  7398. observer.addTick(function ()
  7399. {
  7400. return updateSmeltingTimer(delta++);
  7401. });
  7402. updatePercValues(true);
  7403. }
  7404.  
  7405. function improveTimer(cssRulePrefix, textColor, timerColor, infoIdPrefx, containerPrefix, updateFn)
  7406. {
  7407. 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");
  7408. let iteration = cssRulePrefix == '.woodcutting-tree' ? 6 : 7;
  7409. for (var i = 0; i < iteration; i++)
  7410. {
  7411. var num = i + 1;
  7412. var infoId = infoIdPrefx + num;
  7413. var container = document.getElementById(containerPrefix + num);
  7414. container.style.position = 'relative';
  7415. var infoEl = document.createElement('div');
  7416. infoEl.className = 'info';
  7417. infoEl.id = infoId;
  7418. infoEl.innerHTML = "<div class=\"name\"></div><div class=\"timer\"></div>";
  7419. container.appendChild(infoEl);
  7420. updateFn(num, infoId, true);
  7421. }
  7422. }
  7423.  
  7424. function updateTreeInfo(placeId, infoElId, init)
  7425. {
  7426. if (init === void 0)
  7427. {
  7428. init = false;
  7429. }
  7430. var infoEl = document.getElementById(infoElId);
  7431. var nameEl = infoEl.firstElementChild;
  7432. var timerEl = infoEl.lastElementChild;
  7433. var idKey = 'treeId' + placeId;
  7434. var growTimerKey = 'treeGrowTimer' + placeId;
  7435. var lockedKey = 'treeUnlocked' + placeId;
  7436. var treeId = getGameValue(idKey);
  7437. if (treeId == 0)
  7438. {
  7439. var isLocked = (placeId == 5 || placeId == 6) && win.donorWoodcuttingPatch < win.currentTimeMillis;
  7440. nameEl.textContent = isLocked ? 'Locked' : 'Empty';
  7441. timerEl.textContent = '';
  7442. }
  7443. else
  7444. {
  7445. nameEl.textContent = key2Name(win.getTreeName(treeId)) || 'Unknown Tree';
  7446. var remainingTime = win.TREE_GROW_TIME[treeId - 1] - getGameValue(growTimerKey);
  7447. timerEl.textContent = remainingTime > 0 ? '(' + format.timer(remainingTime) + ')' : 'Fully grown';
  7448. }
  7449. if (init)
  7450. {
  7451. observer.add([idKey, growTimerKey, lockedKey], function ()
  7452. {
  7453. return updateTreeInfo(placeId, infoElId, false);
  7454. });
  7455. }
  7456. }
  7457. // add tree grow timer
  7458. function improveTreeGrowTimer()
  7459. {
  7460. improveTimer('.woodcutting-tree', 'white', 'yellow', 'wc-tree-info-', 'wc-div-tree-', updateTreeInfo);
  7461. }
  7462.  
  7463. function updatePatchInfo(patchId, infoElId, init)
  7464. {
  7465. if (init === void 0)
  7466. {
  7467. init = false;
  7468. }
  7469. var infoEl = document.getElementById(infoElId);
  7470. var nameEl = infoEl.querySelector('.name');
  7471. var timerEl = infoEl.querySelector('.timer');
  7472. var idKey = 'farmingPatchSeed' + patchId;
  7473. var growTimeKey = 'farmingPatchGrowTime' + patchId;
  7474. var timerKey = 'farmingPatchTimer' + patchId;
  7475. var stageKey = 'farmingPatchStage' + patchId;
  7476. var stage = getGameValue(stageKey);
  7477. var seedName = PLANT_NAME[getGameValue(idKey)] || 'Unkown Plant';
  7478. if (stage == 0)
  7479. {
  7480. var isLocked = (patchId == 5 || patchId == 6) && win.donorFarmingPatch < win.currentTimeMillis;
  7481. nameEl.textContent = isLocked ? 'Locked' : 'Click to grow';
  7482. timerEl.textContent = '';
  7483. }
  7484. else if (stage >= 4)
  7485. {
  7486. nameEl.textContent = stage > 4 ? 'Dead Plant' : seedName;
  7487. timerEl.textContent = stage > 4 ? 'Click to remove' : 'Click to harvest';
  7488. }
  7489. else
  7490. {
  7491. nameEl.textContent = seedName;
  7492. var remainingTime = getGameValue(growTimeKey) - getGameValue(timerKey);
  7493. timerEl.textContent = '(' + format.timer(remainingTime) + ')';
  7494. }
  7495. if (init)
  7496. {
  7497. observer.add([idKey, timerKey, stageKey, 'donorFarmingPatch'], function ()
  7498. {
  7499. return updatePatchInfo(patchId, infoElId, false);
  7500. });
  7501. }
  7502. }
  7503. // add seed name and change color of timer
  7504. function getSoonestTreeTimer()
  7505. {
  7506. if (win.treeStage1 == 4
  7507. || win.treeStage2 == 4
  7508. || win.treeStage3 == 4
  7509. || win.treeStage4 == 4
  7510. || win.treeStage5 == 4
  7511. || win.treeStage6 == 4)
  7512. {
  7513. return -1;
  7514. }
  7515. var minTimer = null;
  7516. for (var i = 1; i <= 6; i++)
  7517. {
  7518. var treeId = getGameValue('treeId' + i);
  7519. var unlocked = getGameValue('treeUnlocked' + i) == 1;
  7520. var timerValue = getGameValue('treeGrowTimer' + i);
  7521. if (unlocked && treeId !== 0 && timerValue > 0)
  7522. {
  7523. var remainingTime = win.TREE_GROW_TIME[treeId - 1] - timerValue;
  7524. minTimer = minTimer === null ? remainingTime : Math.min(minTimer, remainingTime);
  7525. }
  7526. }
  7527. return minTimer || 0;
  7528. }
  7529.  
  7530. function getSoonestFarmingTimer()
  7531. {
  7532. if (win.farmingPatchStage1 == 0 || win.farmingPatchStage1 == 4
  7533. || win.farmingPatchStage2 == 0 || win.farmingPatchStage2 == 4
  7534. || win.farmingPatchStage3 == 0 || win.farmingPatchStage3 == 4
  7535. || win.farmingPatchStage4 == 0 || win.farmingPatchStage4 == 4
  7536. || win.donorFarmingPatch > win.currentTimeMillis && (win.farmingPatchStage5 == 0 || win.farmingPatchStage5 == 4
  7537. || win.farmingPatchStage6 == 0 || win.farmingPatchStage6 == 4))
  7538. {
  7539. return -1;
  7540. }
  7541. var minTimer = null;
  7542. for (var i = 1; i <= ((win.donorFarmingPatch > win.currentTimeMillis) ? 6 : 4); i++)
  7543. {
  7544. var remainingTimer = getGameValue('farmingPatchGrowTime' + i) - getGameValue('farmingPatchTimer' + i);
  7545. minTimer = minTimer === null ? remainingTimer : Math.min(minTimer, remainingTimer);
  7546. }
  7547. return minTimer || 0;
  7548. }
  7549.  
  7550. function improveSeedGrowTimer()
  7551. {
  7552. improveTimer('div[id^="farming-patch-area"]', 'black', 'blue', 'farming-patch-info-', 'farming-patch-area-', updatePatchInfo);
  7553. }
  7554.  
  7555. function addTabTimer()
  7556. {
  7557. var TAB_TIMER_KEY = 'tabTimer';
  7558. 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");
  7559.  
  7560. function getTabEl(key)
  7561. {
  7562. return document.getElementById('tab-container-bar-' + key);
  7563. }
  7564.  
  7565. function addInfoDiv(key)
  7566. {
  7567. var infoDiv = document.createElement('div');
  7568. infoDiv.className = 'info';
  7569. var tab = getTabEl(key);
  7570. if (tab)
  7571. {
  7572. tab.appendChild(infoDiv);
  7573. }
  7574. return infoDiv;
  7575. }
  7576.  
  7577. function createTabTimer(key, timerFn)
  7578. {
  7579. var tab = getTabEl(key);
  7580. var timerDiv = addInfoDiv(key);
  7581. if (!tab || !timerDiv)
  7582. {
  7583. return;
  7584. }
  7585. timerDiv.classList.add('timer');
  7586.  
  7587. function updateTimer()
  7588. {
  7589. var minTimer = timerFn();
  7590. if (tab)
  7591. {
  7592. tab.classList[minTimer == -1 ? 'add' : 'remove']('ready');
  7593. }
  7594. timerDiv.textContent = minTimer <= 0 ? '' : format.timer(minTimer);
  7595. }
  7596. updateTimer();
  7597. observer.addTick(function ()
  7598. {
  7599. return updateTimer();
  7600. });
  7601. }
  7602. createTabTimer('woodcutting', getSoonestTreeTimer);
  7603. createTabTimer('farming', getSoonestFarmingTimer);
  7604. createTabTimer('combat', function ()
  7605. {
  7606. return win.combatGlobalCooldown;
  7607. });
  7608. var energyDiv = addInfoDiv('combat');
  7609. energyDiv.classList.add('extra');
  7610.  
  7611. function updateEnergy()
  7612. {
  7613. energyDiv.innerHTML = '<img src="images/steak.png" class="image-icon-15"> ' + format.number(win.energy);
  7614. }
  7615. updateEnergy();
  7616. observer.add('energy', function ()
  7617. {
  7618. return updateEnergy();
  7619. });
  7620. // add highlight for stardust potions
  7621. var potionDiv = addInfoDiv('brewing');
  7622. potionDiv.classList.add('extra');
  7623. var potionList = ['stardustPotion', 'superStardustPotion'];
  7624. var potionImageList = [];
  7625.  
  7626. function updatePotion(key, img, init)
  7627. {
  7628. if (init === void 0)
  7629. {
  7630. init = false;
  7631. }
  7632. var timerKey = key + 'Timer';
  7633. var show = getGameValue(key) > 0 && getGameValue(timerKey) === 0;
  7634. img.style.display = show ? '' : 'none';
  7635. if (init)
  7636. {
  7637. observer.add(key, function ()
  7638. {
  7639. return updatePotion(key, img);
  7640. });
  7641. observer.add(timerKey, function ()
  7642. {
  7643. return updatePotion(key, img);
  7644. });
  7645. }
  7646. }
  7647. for (var i = 0; i < potionList.length; i++)
  7648. {
  7649. var key = potionList[i];
  7650. var img = document.createElement('img');
  7651. img.src = 'images/' + key + '.png';
  7652. img.className = 'image-icon-15';
  7653. potionImageList[i] = img;
  7654. potionDiv.appendChild(img);
  7655. updatePotion(key, img, true);
  7656. }
  7657.  
  7658. function updateVisibility()
  7659. {
  7660. document.body.classList[settings.get(settings.KEY.showTabTimer) ? 'add' : 'remove'](TAB_TIMER_KEY);
  7661. }
  7662. updateVisibility();
  7663. settings.observe(settings.KEY.showTabTimer, function ()
  7664. {
  7665. return updateVisibility();
  7666. });
  7667. observer.add('profileShortTabs', function ()
  7668. {
  7669. var short = !!win.profileShortTabs;
  7670. document.body.classList[short ? 'add' : 'remove']('short-tabs');
  7671. });
  7672. }
  7673.  
  7674. function addOilInfo()
  7675. {
  7676. var NULL_TYPE = 'null';
  7677. var PLUS_TYPE = 'plus';
  7678. var MINUS_TYPE = 'minus';
  7679. 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");
  7680. var oilFlow = document.getElementById('oil-flow-values');
  7681. var parent = oilFlow && oilFlow.parentElement;
  7682. if (!oilFlow || !parent)
  7683. {
  7684. return;
  7685. }
  7686. var container = document.createElement('div');
  7687. container.id = 'oil-filling-level';
  7688. var fillingLevel = document.createElement('div');
  7689. container.appendChild(fillingLevel);
  7690. var first = parent.firstElementChild;
  7691. if (first)
  7692. {
  7693. parent.insertBefore(container, first);
  7694. }
  7695. else
  7696. {
  7697. parent.appendChild(container);
  7698. }
  7699. parent.style.position = 'relative';
  7700. var netFlow = document.createElement('span');
  7701. netFlow.id = 'oil-flow-net';
  7702. parent.insertBefore(netFlow, oilFlow);
  7703. var next = oilFlow.nextElementSibling;
  7704. var netTimer = document.createElement('span');
  7705. netTimer.id = 'oil-flow-net-timer';
  7706. if (next)
  7707. {
  7708. parent.insertBefore(netTimer, next);
  7709. }
  7710. else
  7711. {
  7712. parent.appendChild(netTimer);
  7713. }
  7714. var oilNet;
  7715. var oilNetType;
  7716.  
  7717. function updateNetFlow(init)
  7718. {
  7719. if (init === void 0)
  7720. {
  7721. init = false;
  7722. }
  7723. oilNet = win.oilIn - win.oilOut;
  7724. oilNetType = oilNet === 0 ? NULL_TYPE : (oilNet > 0 ? PLUS_TYPE : MINUS_TYPE);
  7725. netFlow.dataset.type = oilNetType;
  7726. var sign = oilNet === 0 ? PLUS_MINUS_SIGN : (oilNet > 0 ? '+' : '');
  7727. netFlow.textContent = sign + oilNet;
  7728. if (init)
  7729. {
  7730. observer.add('oilIn', function ()
  7731. {
  7732. return updateNetFlow();
  7733. });
  7734. observer.add('oilOut', function ()
  7735. {
  7736. return updateNetFlow();
  7737. });
  7738. }
  7739. updateFullTimer(init);
  7740. }
  7741. var hour2Color = (_a = {}
  7742. , // 30min
  7743. _a[.5 * 60 * 60] = 'rgb(255, 0, 0)'
  7744. , _a[5 * 60 * 60] = 'rgb(255, 255, 0)'
  7745. , _a[8 * 60 * 60] = 'rgb(255, 255, 255)'
  7746. , _a);
  7747.  
  7748. function updateFullTimer(init)
  7749. {
  7750. if (init === void 0)
  7751. {
  7752. init = false;
  7753. }
  7754. netTimer.dataset.type = oilNetType;
  7755. var time = 0;
  7756. if (oilNet > 0)
  7757. {
  7758. netTimer.title = 'full in...';
  7759. var diff = win.maxOil - win.oil;
  7760. time = diff / oilNet;
  7761. }
  7762. else if (oilNet < 0)
  7763. {
  7764. netTimer.title = 'empty in...';
  7765. time = win.oil / Math.abs(oilNet);
  7766. }
  7767. netTimer.textContent = '(' + format.timer(Math.ceil(time)) + ')';
  7768. var filledPercent = win.oil / win.maxOil * 100;
  7769. fillingLevel.style.height = (100 - filledPercent) + '%';
  7770. /**
  7771. * colorize filling level according to the time it needs to be full/empty:
  7772. * - red iff oil storage full/empty in 30min
  7773. * - yellow iff oil storage full/empty in 5h
  7774. * - white iff oil storage full/empty in 8h or more
  7775. */
  7776. var color = oilNet === 0 ? '#ffffff' : colorGenerator.getColorTransition(time, hour2Color);
  7777. container.style.borderColor = color;
  7778. if (init)
  7779. {
  7780. observer.add('maxOil', function ()
  7781. {
  7782. return updateFullTimer();
  7783. });
  7784. observer.add('oil', function ()
  7785. {
  7786. return updateFullTimer();
  7787. });
  7788. observer.addTick(function ()
  7789. {
  7790. return updateFullTimer();
  7791. });
  7792. }
  7793. }
  7794. updateNetFlow(true);
  7795. var _a;
  7796. }
  7797.  
  7798. function addRocketTimer()
  7799. {
  7800. var notifArea = document.getElementById(NOTIFICATION_AREA_ID);
  7801. if (!notifArea)
  7802. {
  7803. return;
  7804. }
  7805. var notifBox = document.createElement('span');
  7806. notifBox.className = 'notif-box ' + IMPROVED_CLASS;
  7807. notifBox.id = 'notif-rocket';
  7808. notifBox.style.display = 'none';
  7809. 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>";
  7810. var AVG_KM_PER_SEC;
  7811. if (rocketDestination == 1){
  7812. AVG_KM_PER_SEC = 15;
  7813. }else if (rocketDestination == 3){
  7814. AVG_KM_PER_SEC = 37000;
  7815. }else{
  7816. AVG_KM_PER_SEC = 400;
  7817. }
  7818. notifBox.title = 'This value is only an estimation based on an average speed of '+AVG_KM_PER_SEC+'km per second.';
  7819. notifArea.appendChild(notifBox);
  7820. var img = notifBox.getElementsByTagName('img').item(0);
  7821. var timerEl = notifBox.getElementsByClassName(TIMER_CLASS).item(0);
  7822. var percentEl = notifBox.getElementsByClassName(PERCENT_CLASS).item(0);
  7823. var smoothedTime = 0;
  7824.  
  7825. function updateRocketKm()
  7826. {
  7827. /* if(AVG_KM_PER_SEC != (rocketDestination == 1 ? 15 : 392))
  7828. {
  7829. AVG_KM_PER_SEC = rocketDestination == 1 ? 15 : 392;
  7830. notifBox.title = 'This value is only an estimation based on an average speed of '+AVG_KM_PER_SEC+'km per second.';
  7831. } */
  7832. var distance;
  7833. if (rocketDestination == 1){
  7834. AVG_KM_PER_SEC = 15;
  7835. distance = MAX_ROCKET_MOON_KM;
  7836. }else if (rocketDestination == 3){
  7837. AVG_KM_PER_SEC = 37000;
  7838. distance = MAX_ROCKET_INTERSTELLAR_KM;
  7839. }else{
  7840. AVG_KM_PER_SEC = 400;
  7841. distance = MAX_ROCKET_MARS_KM;
  7842. }
  7843. notifBox.title = 'This value is only an estimation based on an average speed of '+AVG_KM_PER_SEC+'km per second.';
  7844.  
  7845. var hideStatic = win.rocketKm < distance;
  7846. var hideTimer = win.rocketKm <= 0 || !hideStatic;
  7847. notifBox.style.display = hideTimer ? 'none' : '';
  7848. var percent = win.rocketKm / distance;
  7849. var diff = distance - win.rocketKm;
  7850. if (win.rocketMoonId < 0)
  7851. {
  7852. percent = 1 - percent;
  7853. diff = win.rocketKm;
  7854. }
  7855. var avgRemainingTime = Math.round(diff / AVG_KM_PER_SEC);
  7856. // be more accurate in the last few seconds (may be the last 2 up to 16 seconds)
  7857. var threshold = smoothedTime < 10 ? 1 : 8;
  7858. if (Math.abs(smoothedTime - avgRemainingTime) >= threshold)
  7859. {
  7860. smoothedTime = avgRemainingTime + 1;
  7861. }
  7862. percentEl.textContent = Math.floor(percent * 100).toString();
  7863. }
  7864.  
  7865. function tickRocketTimer()
  7866. {
  7867. if (smoothedTime > 0)
  7868. {
  7869. smoothedTime = Math.max(smoothedTime - 1, 0);
  7870. timerEl.textContent = format.timer(smoothedTime);
  7871. }
  7872. }
  7873. updateRocketKm();
  7874. observer.add('rocketKm', function (key, oldValue, newValue)
  7875. {
  7876. return updateRocketKm();
  7877. });
  7878. observer.addTick(function ()
  7879. {
  7880. return tickRocketTimer();
  7881. });
  7882.  
  7883. function updateRocketDirection()
  7884. {
  7885. // alternatively: `transform: rotateZ(180deg) rotateY(180deg)`
  7886. var transform = win.rocketMoonId >= 0 ? '' : 'rotate(90deg)';
  7887. img.style.transform = transform;
  7888. var itemBox = document.getElementById('default-item-img-tag-boundRocket');
  7889. if (itemBox)
  7890. {
  7891. itemBox.style.transform = transform;
  7892. }
  7893. }
  7894. updateRocketDirection();
  7895. observer.add('rocketMoonId', function ()
  7896. {
  7897. return updateRocketDirection();
  7898. });
  7899. }
  7900. function addVendorRefreshTimer()
  7901. {
  7902. var notifArea = document.getElementById(NOTIFICATION_AREA_ID);
  7903. if (!notifArea)
  7904. {
  7905. return;
  7906. }
  7907. var notifBox = document.createElement('span');
  7908. notifBox.className = 'notif-box ' + IMPROVED_CLASS;
  7909. notifBox.id = 'notif-vendorRefresh';
  7910. notifBox.style.display = 'none';
  7911. 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>";
  7912. notifArea.appendChild(notifBox);
  7913. var img = notifBox.getElementsByTagName('img').item(0);
  7914. var timerEl = notifBox.getElementsByClassName(TIMER_CLASS).item(0);
  7915.  
  7916. function updateVendorRefreshTimer()
  7917. {
  7918. var hideTimer = win.vendorNotification == 1;
  7919. notifBox.style.display = hideTimer ? 'none' : '';
  7920. var timeLeft = Math.floor( (12*60*60) - (Date.now()-vendorLastChanged)/1000 );
  7921. timerEl.textContent = format.timer(timeLeft);
  7922. }
  7923. updateVendorRefreshTimer();
  7924. observer.addTick(function ()
  7925. {
  7926. return updateVendorRefreshTimer();
  7927. });
  7928. }
  7929. function addBobsUncleTimer()
  7930. {
  7931. var notifArea = document.getElementById(NOTIFICATION_AREA_ID);
  7932. if (!notifArea)
  7933. {
  7934. return;
  7935. }
  7936. var notifBox = document.createElement('span');
  7937. notifBox.className = 'notif-box ' + IMPROVED_CLASS;
  7938. notifBox.id = 'notif-bobsUncle';
  7939. notifBox.style.display = 'none';
  7940. 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>";
  7941. notifArea.appendChild(notifBox);
  7942. var img = notifBox.getElementsByTagName('img').item(0);
  7943. var timerEl = notifBox.getElementsByClassName(TIMER_CLASS).item(0);
  7944.  
  7945. function updateBobsUncleTimer()
  7946. {
  7947. var hideTimer = win.farmingPatchStage7 == 0 || win.farmingPatchStage7 == 4;
  7948. notifBox.style.display = hideTimer ? 'none' : '';
  7949. var timeLeft = getGameValue('farmingPatchGrowTime7') - getGameValue('farmingPatchTimer7');
  7950. timerEl.textContent = format.timer(timeLeft);
  7951. }
  7952. updateBobsUncleTimer();
  7953. observer.addTick(function ()
  7954. {
  7955. return updateBobsUncleTimer();
  7956. });
  7957. }
  7958. function addCharcoalFactoryTimer()
  7959. {
  7960. var notifArea = document.getElementById(NOTIFICATION_AREA_ID);
  7961. if (!notifArea)
  7962. {
  7963. return;
  7964. }
  7965. var notifBox = document.createElement('span');
  7966. notifBox.className = 'notif-box ' + IMPROVED_CLASS;
  7967. notifBox.id = 'notif-charcoalFactory';
  7968. notifBox.style.display = 'none';
  7969. var consumeTime = (boundRedCharcoalFactoryOrb) ? 492: 112;
  7970. notifBox.title = 'This value is only an estimation based on an average consumption rate of one charcoal every '+consumeTime+' seconds.';
  7971. 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>";
  7972. notifArea.appendChild(notifBox);
  7973. var img = notifBox.getElementsByTagName('img').item(0);
  7974. var timerEl = notifBox.getElementsByClassName(TIMER_CLASS).item(0);
  7975. var now = Math.floor(Date.now()/1000);
  7976. function updateCharcoalFactoryTimer()
  7977. {
  7978. var hideTimer = win.boundCharcoalFactory == 0 || win.charcoalFactoryCharcoal == 0;
  7979. notifBox.style.display = hideTimer ? 'none' : '';
  7980. var averageTimeLeft = getGameValue('charcoalFactoryCharcoal') * consumeTime;
  7981. var smoothedTime = averageTimeLeft + now - Math.floor(Date.now()/1000);
  7982. timerEl.textContent = format.timer(smoothedTime);
  7983. }
  7984. updateCharcoalFactoryTimer();
  7985. observer.addTick(function (){
  7986. return updateCharcoalFactoryTimer();
  7987. });
  7988. }
  7989. function getLogTypeList()
  7990. {
  7991. var list = [];
  7992. var els = document.querySelectorAll('input[id^="input-charcoalFoundry-"]');
  7993. for (var i = 0; i < els.length; i++)
  7994. {
  7995. list.push(els[i].id.replace(/^input-charcoalFoundry-/i, ''));
  7996. }
  7997. return list;
  7998. }
  7999.  
  8000. function improveFoundryTimer()
  8001. {
  8002. var el = document.getElementById('notif-charcoalFoundry');
  8003. if (!el)
  8004. {
  8005. return;
  8006. }
  8007. var notifBox = el;
  8008. notifBox.classList.add(IMPROVED_CLASS);
  8009. var timerEl = document.createElement('span');
  8010. timerEl.className = TIMER_CLASS;
  8011. notifBox.appendChild(timerEl);
  8012. var remainingEl = document.createElement('span');
  8013. remainingEl.className = REMAINING_CLASS;
  8014. notifBox.appendChild(remainingEl);
  8015. var logTypeList = null;
  8016. observer.add('charcoalFoundryN', function (key, oldValue, newValue)
  8017. {
  8018. timerEl.textContent = format.timer(win.charcoalFoundryD - win.charcoalFoundryN);
  8019. // init log type list when needed
  8020. if (!logTypeList)
  8021. {
  8022. logTypeList = getLogTypeList();
  8023. }
  8024. var woodAmount = win.charcoalFoundryTotal - win.charcoalFoundryCurrent;
  8025. var coalPerLog = win.getCharcoalPerLog(logTypeList[win.charcoalFoundryLogId - 1]);
  8026. var remainingCoal = woodAmount * (isNaN(coalPerLog) ? 1 : coalPerLog);
  8027. remainingEl.textContent = remainingCoal.toString();
  8028. });
  8029. }
  8030. function improveCharcoalFactoryTimer()
  8031. {
  8032. var el = document.getElementById('notif-charcoalFactory');
  8033. if (!el)
  8034. {
  8035. return;
  8036. }
  8037. var notifBox = el;
  8038. notifBox.classList.add(IMPROVED_CLASS);
  8039. var remainingEl = document.createElement('span');
  8040. remainingEl.className = REMAINING_CLASS;
  8041. notifBox.appendChild(remainingEl);
  8042. observer.add('charcoalFactoryCharcoal', function (key, oldValue, newValue)
  8043. {
  8044. var remainingCoal = win.charcoalFactoryCharcoal;
  8045. remainingEl.textContent = remainingCoal.toString();
  8046. });
  8047. }
  8048.  
  8049. function init()
  8050. {
  8051. bindNewFormatter();
  8052. applyStyle();
  8053. improveSmeltingTimer();
  8054. improveTreeGrowTimer();
  8055. improveSeedGrowTimer();
  8056. addTabTimer();
  8057. addOilInfo();
  8058. addRocketTimer();
  8059. improveFoundryTimer();
  8060. addVendorRefreshTimer();
  8061. addBobsUncleTimer();
  8062. addCharcoalFactoryTimer();
  8063. //improveCharcoalFactoryTimer();
  8064. }
  8065. timer.init = init;
  8066. })(timer || (timer = {}));
  8067.  
  8068. /**
  8069. * improve smelting dialog
  8070. */
  8071. var smelting;
  8072. (function (smelting)
  8073. {
  8074. smelting.name = 'smelting';
  8075. var TIME_NEEDED_ID = 'smelting-time-needed';
  8076. var LAST_SMELTING_AMOUNT_KEY = 'lastSmeltingAmount';
  8077. var LAST_SMELTING_BAR_KEY = 'lastSmeltingBar';
  8078. var smeltingValue = null;
  8079. var amountInput;
  8080.  
  8081. function prepareAmountInput()
  8082. {
  8083. amountInput = document.getElementById('input-smelt-bars-amount');
  8084. amountInput.type = 'number';
  8085. amountInput.min = '0';
  8086. amountInput.step = '5';
  8087.  
  8088. function onValueChange()
  8089. {
  8090. smeltingValue = null;
  8091. win.selectBar('', null, amountInput, document.getElementById('smelting-furnace-capacity').value);
  8092. }
  8093. amountInput.addEventListener('mouseup', onValueChange);
  8094. amountInput.addEventListener('keyup', onValueChange);
  8095. amountInput.setAttribute('onkeyup', '');
  8096. }
  8097.  
  8098. function setBarCap(bar, capacity)
  8099. {
  8100. if (bar == '')
  8101. {
  8102. bar = win.selectedBar;
  8103. }
  8104. var requirements = SMELTING_REQUIREMENTS[bar];
  8105. var maxAmount = parseInt(capacity, 10);
  8106. for (var key in requirements)
  8107. {
  8108. var req = requirements[key];
  8109. maxAmount = Math.min(Math.floor(getGameValue(key) / req), maxAmount);
  8110. }
  8111. var value = parseInt(amountInput.value, 10);
  8112. if (value > maxAmount)
  8113. {
  8114. smeltingValue = value;
  8115. amountInput.value = maxAmount.toString();
  8116. }
  8117. else if (smeltingValue != null)
  8118. {
  8119. amountInput.value = Math.min(smeltingValue, maxAmount).toString();
  8120. if (smeltingValue <= maxAmount)
  8121. {
  8122. smeltingValue = null;
  8123. }
  8124. }
  8125. }
  8126.  
  8127. function prepareTimeNeeded()
  8128. {
  8129. var neededMatsEl = document.getElementById('dialogue-furnace-mats-needed');
  8130. var parent = neededMatsEl && neededMatsEl.parentElement;
  8131. if (!neededMatsEl || !parent)
  8132. {
  8133. return;
  8134. }
  8135. var br = document.createElement('br');
  8136. var timeBox = document.createElement('div');
  8137. timeBox.className = 'basic-smallbox';
  8138. timeBox.innerHTML = "<img src=\"images/icons/hourglass.png\" class=\"image-icon-30\">\n\t\tDuration: <span id=\"" + TIME_NEEDED_ID + "\"></span>";
  8139. var next = neededMatsEl.nextElementSibling;
  8140. parent.insertBefore(br, next);
  8141. parent.insertBefore(timeBox, next);
  8142. }
  8143.  
  8144. function updateTimeNeeded(value)
  8145. {
  8146. var timeEl = document.getElementById(TIME_NEEDED_ID);
  8147. if (!timeEl)
  8148. {
  8149. return;
  8150. }
  8151. var num = parseInt(value, 10);
  8152. var timePerBar = win.getTimerPerBar(win.selectedBar);
  8153. timeEl.textContent = format.timer(timePerBar * num);
  8154. }
  8155.  
  8156. function init()
  8157. {
  8158. prepareAmountInput();
  8159. prepareTimeNeeded();
  8160. var _selectBar = win.selectBar;
  8161. var updateSmeltingRequirements = function (bar, inputElement, inputBarsAmountEl, capacity)
  8162. {
  8163. _selectBar(bar, inputElement, inputBarsAmountEl, capacity);
  8164. var matsArea = document.getElementById('dialogue-furnace-mats-needed');
  8165. if (matsArea)
  8166. {
  8167. matsArea.innerHTML = format.numbersInText(matsArea.innerHTML);
  8168. }
  8169. updateTimeNeeded(inputBarsAmountEl.value);
  8170. };
  8171. win.selectBar = function (bar, inputElement, inputBarsAmountEl, capacity)
  8172. {
  8173. setBarCap(bar, capacity);
  8174. // save selected bar
  8175. if (bar != '')
  8176. {
  8177. store.set(LAST_SMELTING_BAR_KEY, bar);
  8178. }
  8179. // save amount
  8180. store.set(LAST_SMELTING_AMOUNT_KEY, inputBarsAmountEl.value);
  8181. updateSmeltingRequirements(bar, inputElement, inputBarsAmountEl, capacity);
  8182. };
  8183. var lastBar = store.get(LAST_SMELTING_BAR_KEY);
  8184. var lastAmount = store.get(LAST_SMELTING_AMOUNT_KEY);
  8185. var _openFurnaceDialogue = win.openFurnaceDialogue;
  8186. win.openFurnaceDialogue = function (furnace)
  8187. {
  8188. var capacity = win.getFurnaceCapacity(furnace);
  8189. if (win.smeltingBarType == 0)
  8190. {
  8191. amountInput.max = capacity.toString();
  8192. }
  8193. // restore amount
  8194. var inputBarsAmountEl = document.getElementById('input-smelt-bars-amount');
  8195. if (inputBarsAmountEl && inputBarsAmountEl.value == '-1' && lastAmount != null)
  8196. {
  8197. inputBarsAmountEl.value = lastAmount;
  8198. }
  8199. _openFurnaceDialogue(furnace);
  8200. // restore selected bar
  8201. if ((!win.selectedBar || win.selectedBar == 'none') && lastBar != null)
  8202. {
  8203. win.selectedBar = lastBar;
  8204. }
  8205. // update whether requirements are fulfilled
  8206. var barInputId = 'input-furnace-' + split2Words(win.selectedBar, '-').toLowerCase();
  8207. var inputElement = document.getElementById(barInputId);
  8208. if (inputElement && inputBarsAmountEl)
  8209. {
  8210. updateSmeltingRequirements(win.selectedBar, inputElement, inputBarsAmountEl, capacity.toString());
  8211. }
  8212. };
  8213. }
  8214. smelting.init = init;
  8215. })(smelting || (smelting = {}));
  8216.  
  8217. /**
  8218. * add chance to time calculator
  8219. */
  8220. var fishingInfo;
  8221. (function (fishingInfo)
  8222. {
  8223. fishingInfo.name = 'fishingInfo';
  8224. /**
  8225. * calculates the number of seconds until the event with the given chance happened at least once with the given
  8226. * probability p (in percent)
  8227. */
  8228. function calcSecondsTillP(chancePerSecond, p)
  8229. {
  8230. return Math.round(Math.log(1 - p / 100) / Math.log(1 - chancePerSecond));
  8231. }
  8232.  
  8233. function addChanceTooltip(headline, chancePerSecond, elId, targetEl)
  8234. {
  8235. // ensure tooltip exists and is correctly binded
  8236. var tooltipEl = ensureTooltip('chance-' + elId, targetEl);
  8237. // set elements content
  8238. var percValues = [1, 10, 20, 50, 80, 90, 99];
  8239. var percRows = '';
  8240. for (var _i = 0, percValues_1 = percValues; _i < percValues_1.length; _i++)
  8241. {
  8242. var p = percValues_1[_i];
  8243. 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>";
  8244. }
  8245. 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";
  8246. }
  8247.  
  8248. function addChanceStyle()
  8249. {
  8250. 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");
  8251. }
  8252.  
  8253. function addXp()
  8254. {
  8255. var table = document.querySelector('#dialogue-id-fishingRod table');
  8256. if (!table)
  8257. {
  8258. return;
  8259. }
  8260. var rows = table.rows;
  8261. for (var i = 0; i < rows.length; i++)
  8262. {
  8263. var row = rows.item(i);
  8264. if (row.classList.contains('xp-added'))
  8265. {
  8266. continue;
  8267. }
  8268. if (i == 0)
  8269. {
  8270. var xpCell = document.createElement('th');
  8271. xpCell.textContent = 'XP';
  8272. row.appendChild(xpCell);
  8273. }
  8274. else
  8275. {
  8276. var cell = row.insertCell(-1);
  8277. var rawFish = row.id.replace('dialogue-fishing-rod-tr-', '');
  8278. var xp = FISH_XP[rawFish];
  8279. cell.textContent = xp == null ? '?' : format.number(xp);
  8280. }
  8281. row.classList.add('xp-added');
  8282. }
  8283. }
  8284.  
  8285. function chance2TimeCalculator()
  8286. {
  8287. var table = document.querySelector('#dialogue-id-fishingRod table');
  8288. if (!table)
  8289. {
  8290. return;
  8291. }
  8292. var rows = table.rows;
  8293. for (var i = 1; i < rows.length; i++)
  8294. {
  8295. var row = rows.item(i);
  8296. var rawFish = row.id.replace('dialogue-fishing-rod-tr-', '');
  8297. var fish = rawFish.replace('raw', '').toLowerCase();
  8298. if (!rawFish || !fish)
  8299. {
  8300. continue;
  8301. }
  8302. var chanceCell = row.cells.item(row.cells.length - 2);
  8303. var chance = (chanceCell.textContent || '')
  8304. .replace(/[^\d\/]/g, '')
  8305. .split('/')
  8306. .reduce(function (p, c)
  8307. {
  8308. return p / parseInt(c, 10);
  8309. }, 1);
  8310. addChanceTooltip("One raw " + fish + " at least every:", chance, rawFish, row);
  8311. }
  8312. }
  8313.  
  8314. function init()
  8315. {
  8316. addChanceStyle();
  8317. var _clicksShovel = win.clicksShovel;
  8318. win.clicksShovel = function ()
  8319. {
  8320. _clicksShovel();
  8321. var shovelChance = document.getElementById('dialogue-shovel-chance');
  8322. var titleEl = shovelChance.parentElement;
  8323. var chance = 1 / win.getChanceOfDiggingSand();
  8324. addChanceTooltip('One sand at least every:', chance, 'shovel', titleEl);
  8325. };
  8326. // depends on fishingXp
  8327. var _clicksFishingRod = win.clicksFishingRod;
  8328. win.clicksFishingRod = function ()
  8329. {
  8330. _clicksFishingRod();
  8331. addXp();
  8332. chance2TimeCalculator();
  8333. };
  8334. }
  8335. fishingInfo.init = init;
  8336. })(fishingInfo || (fishingInfo = {}));
  8337.  
  8338. /**
  8339. * add tooltips for recipes
  8340. */
  8341. var recipeTooltips;
  8342. (function (recipeTooltips)
  8343. {
  8344. recipeTooltips.name = 'recipeTooltips';
  8345.  
  8346. function updateRecipeTooltips(recipeKey, recipes)
  8347. {
  8348. var table = document.getElementById('table-' + recipeKey + '-recipe');
  8349. var rows = table.rows;
  8350.  
  8351. function recipe2Title(recipe)
  8352. {
  8353. return recipe.recipe
  8354. .map(function (name, i)
  8355. {
  8356. return format.number(recipe.recipeCost[i]) + String.fromCharCode(160)
  8357. + split2Words(name).toLowerCase();
  8358. })
  8359. .join(' + ');
  8360. };
  8361. for (var i = 1; i < rows.length; i++)
  8362. {
  8363. var row = rows.item(i);
  8364. var key = row.id.replace(recipeKey + '-', '');
  8365. var recipe = recipes[key];
  8366. var requirementCell = row.cells.item(3);
  8367. requirementCell.title = recipe2Title(recipe);
  8368. win.$(requirementCell).tooltip();
  8369. }
  8370. }
  8371.  
  8372. function updateTooltipsOnReinitRecipes(key)
  8373. {
  8374. var capitalKey = capitalize(key);
  8375. var processKey = 'process' + capitalKey + 'Tab';
  8376. var _processTab = win[processKey];
  8377. win[processKey] = function ()
  8378. {
  8379. var reinit = !!getGameValue('refreshLoad' + capitalKey + 'Table');
  8380. _processTab();
  8381. if (reinit)
  8382. {
  8383. updateRecipeTooltips(key, getGameValue(key + 'Recipes'));
  8384. }
  8385. };
  8386. }
  8387.  
  8388. function init()
  8389. {
  8390. updateTooltipsOnReinitRecipes('crafting');
  8391. updateTooltipsOnReinitRecipes('brewing');
  8392. updateTooltipsOnReinitRecipes('magic');
  8393. updateTooltipsOnReinitRecipes('cooksBook');
  8394. }
  8395. recipeTooltips.init = init;
  8396. })(recipeTooltips || (recipeTooltips = {}));
  8397.  
  8398. /**
  8399. * fix formatting of numbers
  8400. */
  8401. var fixNumbers;
  8402. (function (fixNumbers)
  8403. {
  8404. fixNumbers.name = 'fixNumbers';
  8405.  
  8406. function prepareRecipeForTable(recipe)
  8407. {
  8408. // create a copy of the recipe to prevent requirement check from failing
  8409. var newRecipe = JSON.parse(JSON.stringify(recipe));
  8410. newRecipe.recipeCost = recipe.recipeCost.map(function (cost)
  8411. {
  8412. return format.number(cost);
  8413. });
  8414. newRecipe.description = format.numbersInText(newRecipe.description);
  8415. newRecipe.xp = format.number(recipe.xp);
  8416. return newRecipe;
  8417. }
  8418.  
  8419. function init()
  8420. {
  8421. var _addRecipeToBrewingTable = win.addRecipeToBrewingTable;
  8422. win.addRecipeToBrewingTable = function (brewingRecipe)
  8423. {
  8424. _addRecipeToBrewingTable(prepareRecipeForTable(brewingRecipe));
  8425. };
  8426. var _addRecipeToMagicTable = win.addRecipeToMagicTable;
  8427. win.addRecipeToMagicTable = function (magicRecipe)
  8428. {
  8429. _addRecipeToMagicTable(prepareRecipeForTable(magicRecipe));
  8430. };
  8431. var _addRecipeToCooksBookTable = win.addRecipeToCooksBookTable;
  8432. win.addRecipeToCooksBookTable = function (cooksBookRecipe)
  8433. {
  8434. _addRecipeToCooksBookTable(prepareRecipeForTable(cooksBookRecipe));
  8435. };
  8436. var tooltipList = document.querySelectorAll('#tooltip-list div[id^="tooltip-"][id$="Seeds"]');
  8437. for (var i = 0; i < tooltipList.length; i++)
  8438. {
  8439. var tooltip = tooltipList[i];
  8440. tooltip.innerHTML = format.numbersInText(tooltip.innerHTML);
  8441. }
  8442. var fightEnergyCells = document.querySelectorAll('#dialogue-fight tr > td:nth-child(4)');
  8443. for (let i = 0; i < fightEnergyCells.length; i++)
  8444. {
  8445. var cell = fightEnergyCells[i];
  8446. cell.innerHTML = format.numbersInText(cell.innerHTML);
  8447. }
  8448. var _rocketTick = win.rocketTick;
  8449. win.rocketTick = function ()
  8450. {
  8451. _rocketTick();
  8452. var rocketBox = document.getElementById('itembox-rocket');
  8453. if (rocketBox && /^\d+\s*Km$/i.test(rocketBox.textContent || ''))
  8454. {
  8455. rocketBox.innerHTML = format.numbersInText(rocketBox.innerHTML).replace('Km', 'km');
  8456. }
  8457. };
  8458. }
  8459. fixNumbers.init = init;
  8460. })(fixNumbers || (fixNumbers = {}));
  8461.  
  8462. /**
  8463. * add slider for machines
  8464. */
  8465. var machineDialog;
  8466. (function (machineDialog)
  8467. {
  8468. machineDialog.name = 'machineDialog';
  8469. var $slider;
  8470.  
  8471. function createSlider()
  8472. {
  8473. var br = document.querySelector('#dialogue-machinery-current-total ~ br');
  8474. var parent = br && br.parentElement;
  8475. if (!br || !parent)
  8476. {
  8477. return;
  8478. }
  8479. 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");
  8480. var slider = document.createElement('div');
  8481. parent.insertBefore(slider, br);
  8482. $slider = win.$(slider)
  8483. .slider(
  8484. {
  8485. range: 'max'
  8486. , min: 0
  8487. , max: 10
  8488. , value: 0
  8489. , slide: function (event, ui)
  8490. {
  8491. return updateValue(ui.value);
  8492. }
  8493. });
  8494. // hide br and up/down arrows
  8495. br.style.display = 'none';
  8496. var arrows = document.querySelectorAll('input[onclick^="turnOn("]');
  8497. for (var i = 0; i < arrows.length; i++)
  8498. {
  8499. arrows[i].style.display = 'none';
  8500. }
  8501. var els = document.querySelectorAll('[onclick*="openMachineryDialogue("]');
  8502. var boundMachineKeyList = [];
  8503. for (let i = 0; i < els.length; i++)
  8504. {
  8505. var match = els[i].id.match(/openMachineryDialogue\('(.+?)'\)/);
  8506. if (match)
  8507. {
  8508. boundMachineKeyList.push(getBoundKey(match[1]));
  8509. }
  8510. }
  8511. observer.add(boundMachineKeyList, function ()
  8512. {
  8513. return updateMax();
  8514. });
  8515. }
  8516.  
  8517. function updateMax()
  8518. {
  8519. var machineEl = document.getElementById('dialogue-machinery-chosen');
  8520. if (machineEl && machineEl.value != '')
  8521. {
  8522. var boundMachineKey = getBoundKey(machineEl.value);
  8523. var ownedNum = getGameValue(boundMachineKey);
  8524. $slider.slider('option', 'max', ownedNum);
  8525. $slider.get(0).dataset.owned = ownedNum.toString();
  8526. }
  8527. }
  8528.  
  8529. function updateValue(value)
  8530. {
  8531. var typeEl = document.getElementById('dialogue-machinery-chosen');
  8532. var numEl = document.getElementById('dialogue-machinery-current-on');
  8533. if (numEl && typeEl)
  8534. {
  8535. var valueBefore = parseInt(numEl.textContent || '0', 10);
  8536. var machine = typeEl.value;
  8537. var increment = valueBefore < value;
  8538. var diff = Math.abs(valueBefore - value);
  8539. for (var i = 0; i < diff; i++)
  8540. {
  8541. win.turnOn(machine, increment);
  8542. }
  8543. }
  8544. }
  8545.  
  8546. function init()
  8547. {
  8548. if (!settings.get(settings.KEY.changeMachineDialog))
  8549. {
  8550. return;
  8551. }
  8552. createSlider();
  8553. var _openMachineryDialogue = win.openMachineryDialogue;
  8554. win.openMachineryDialogue = function (machineType)
  8555. {
  8556. _openMachineryDialogue(machineType);
  8557. updateMax();
  8558. $slider.slider('value', getGameValue(machineType + 'On'));
  8559. };
  8560. }
  8561. machineDialog.init = init;
  8562. })(machineDialog || (machineDialog = {}));
  8563.  
  8564. /**
  8565. * improve behaviour of amount inputs
  8566. */
  8567. var amountInputs;
  8568. (function (amountInputs)
  8569. {
  8570. amountInputs.name = 'amountInputs';
  8571.  
  8572. function getVialType(recipe)
  8573. {
  8574. return recipe.levelReq < 35 ? 'vialOfWater' : (recipe.levelReq < 65 ? 'largeVialOfWater' : 'hugeVialOfWater');
  8575. }
  8576.  
  8577. function getSimpleMax(recipe)
  8578. {
  8579. var max = Number.MAX_SAFE_INTEGER;
  8580. for (var i = 0; i < recipe.recipe.length; i++)
  8581. {
  8582. max = Math.min(max, Math.floor(getGameValue(recipe.recipe[i]) / recipe.recipeCost[i]));
  8583. }
  8584. return max;
  8585. }
  8586.  
  8587. function getMax(recipe)
  8588. {
  8589. var max = getSimpleMax(recipe);
  8590. if (/Potion$/.test(recipe.itemName))
  8591. {
  8592. var vialType = getVialType(recipe);
  8593. max = Math.min(max, getGameValue(vialType));
  8594. }
  8595. return max;
  8596. }
  8597.  
  8598. function ensureNumberInput(idOrEl)
  8599. {
  8600. var numInput = typeof idOrEl === 'string' ? document.getElementById(idOrEl) : idOrEl;
  8601. if (numInput)
  8602. {
  8603. if (numInput.type != 'number' && settings.get(settings.KEY.makeNumberInputs))
  8604. {
  8605. var width = numInput.clientWidth;
  8606. if (width !== 0)
  8607. {
  8608. numInput.style.width = width + 'px';
  8609. }
  8610. numInput.type = 'number';
  8611. numInput.min = '0';
  8612. var onkeyup_1 = numInput.getAttribute('onkeyup');
  8613. if (onkeyup_1)
  8614. {
  8615. numInput.setAttribute('onmouseup', onkeyup_1);
  8616. }
  8617. }
  8618. else if (numInput.type == 'number' && !settings.get(settings.KEY.makeNumberInputs))
  8619. {
  8620. numInput.style.width = '';
  8621. numInput.type = '';
  8622. numInput.removeAttribute('onmouseup');
  8623. }
  8624. }
  8625. return numInput;
  8626. }
  8627.  
  8628. function getCurrentMax(keyId, recipeCollection)
  8629. {
  8630. var keyEl = document.getElementById(keyId);
  8631. if (!keyEl)
  8632. {
  8633. return 0;
  8634. }
  8635. var key = keyEl.value;
  8636. return getMax(recipeCollection[key]);
  8637. };
  8638.  
  8639. function ensureMaxBtn(keyId, inputId, recipeCollection, key)
  8640. {
  8641. var recipe = recipeCollection[key];
  8642. var numInput = ensureNumberInput(inputId);
  8643. var next = numInput && numInput.nextElementSibling;
  8644. var parent = numInput && numInput.parentElement;
  8645. if (numInput && parent)
  8646. {
  8647. if ((!next || next.nodeName !== 'BUTTON') && settings.get(settings.KEY.addMaxBtn))
  8648. {
  8649. var btn = document.createElement('button');
  8650. btn.textContent = 'Max';
  8651. btn.addEventListener('click', function ()
  8652. {
  8653. numInput.value = getCurrentMax(keyId, recipeCollection).toString();
  8654. });
  8655. parent.appendChild(btn);
  8656. }
  8657. else if (next && next.nodeName === 'BUTTON' && !settings.get(settings.KEY.addMaxBtn))
  8658. {
  8659. parent.removeChild(next);
  8660. }
  8661. numInput.value = Math.min(1, getMax(recipe)).toString();
  8662. numInput.select();
  8663. }
  8664. }
  8665.  
  8666. function watchKeepInput(event)
  8667. {
  8668. var itemInput = document.getElementById('npc-sell-item-chosen');
  8669. var numInput = ensureNumberInput('dialogue-input-cmd');
  8670. if (!itemInput || !numInput)
  8671. {
  8672. return;
  8673. }
  8674. var item = itemInput.value;
  8675. var newValue = Math.max(getGameValue(item) - Number(this.value), 0);
  8676. numInput.value = newValue.toString();
  8677. }
  8678.  
  8679. function updateKeepMaxValue(keepInput, init)
  8680. {
  8681. if (init === void 0)
  8682. {
  8683. init = false;
  8684. }
  8685. var itemInput = document.getElementById('npc-sell-item-chosen');
  8686. if (!itemInput)
  8687. {
  8688. return;
  8689. }
  8690. var item = itemInput.value;
  8691. var max = getGameValue(item);
  8692. keepInput.max = max.toString();
  8693. if (init)
  8694. {
  8695. observer.addTick(function ()
  8696. {
  8697. return updateKeepMaxValue(keepInput);
  8698. });
  8699. }
  8700. }
  8701.  
  8702. function ensureKeepInput(item)
  8703. {
  8704. var numInput = ensureNumberInput('dialogue-input-cmd');
  8705. var parent = numInput && numInput.parentElement;
  8706. var next = numInput && numInput.nextElementSibling;
  8707. var nextNext = next && next.nextElementSibling;
  8708. if (next && nextNext && parent)
  8709. {
  8710. if (nextNext.nodeName === 'BR' && settings.get(settings.KEY.addKeepInput))
  8711. {
  8712. var div = document.createElement('div');
  8713. var text = document.createTextNode('Keep: ');
  8714. div.appendChild(text);
  8715. var keepInput = document.createElement('input');
  8716. keepInput.type = 'number';
  8717. keepInput.value = keepInput.min = '0';
  8718. keepInput.max = getGameValue(item).toString();
  8719. keepInput.addEventListener('keyup', watchKeepInput);
  8720. keepInput.addEventListener('mouseup', watchKeepInput);
  8721. updateKeepMaxValue(keepInput, true);
  8722. div.appendChild(keepInput);
  8723. parent.insertBefore(div, nextNext);
  8724. }
  8725. else if (nextNext.nodeName !== 'BR' && !settings.get(settings.KEY.addKeepInput))
  8726. {
  8727. var br = document.createElement('br');
  8728. parent.insertBefore(br, nextNext);
  8729. parent.removeChild(nextNext);
  8730. }
  8731. }
  8732. }
  8733.  
  8734. function init()
  8735. {
  8736. var _multiCraft = win.multiCraft;
  8737. win.multiCraft = function (item)
  8738. {
  8739. _multiCraft(item);
  8740. ensureMaxBtn('dialogue-multicraft-chosen', 'dialogue-multicraft-input', win.craftingRecipes, item);
  8741. };
  8742. var _brew = win.brew;
  8743. win.brew = function (potion)
  8744. {
  8745. _brew(potion);
  8746. ensureMaxBtn('dialogue-potion-chosen', 'dialogue-brewing-input', win.brewingRecipes, potion);
  8747. };
  8748. var _cooksBookInputDialogue = win.cooksBookInputDialogue;
  8749. win.cooksBookInputDialogue = function (food)
  8750. {
  8751. _cooksBookInputDialogue(food);
  8752. ensureMaxBtn('dialogue-cooksBook-chosen', 'dialogue-cooksBook-input', win.cooksBookRecipes, food);
  8753. };
  8754. var _openSellNPCDialogue = win.openSellNPCDialogue;
  8755. win.openSellNPCDialogue = function (item)
  8756. {
  8757. _openSellNPCDialogue(item);
  8758. ensureKeepInput(item);
  8759. };
  8760. var allowedInputs = [
  8761. 'dialogue-ashes'
  8762. , 'dialogue-bindDonorCoins'
  8763. , 'dialogue-bonemeal'
  8764. , 'dialogue-bones'
  8765. , 'dialogue-brewing'
  8766. , 'dialogue-buy-item-2'
  8767. , 'dialogue-buyFromMarket'
  8768. , 'dialogue-charcoalFoundry'
  8769. , 'dialogue-consume'
  8770. , 'dialogue-cooksBook'
  8771. , 'dialogue-createArrows'
  8772. , 'dialogue-createFireArrows'
  8773. , 'dialogue-createIceArrows'
  8774. , 'dialogue-furnace'
  8775. , 'dialogue-iceBones'
  8776. , 'dialogue-id-boundHammer'
  8777. , 'dialogue-id-boundPickaxe'
  8778. , 'dialogue-id-cook-food'
  8779. , 'dialogue-id-oven-addheat'
  8780. , 'dialogue-market-chosenpostitem'
  8781. , 'dialogue-multicraft'
  8782. , 'dialogue-oilBarrels'
  8783. , 'dialogue-oilFactory'
  8784. , 'dialogue-sell-item'
  8785. , 'dialogue-stardustCrystals'
  8786. , 'dialogue-wand'
  8787. ];
  8788. var _openDialogue = win.openDialogue;
  8789. win.openDialogue = function (id, width, position)
  8790. {
  8791. _openDialogue(id, width, position);
  8792. if (allowedInputs.indexOf(id) === -1
  8793. || id === 'dialogue-buyFromMarket' && market.detectTedsUI()
  8794. || id === 'dialogue-market-chosenpostitem' && market.detectTedsUI())
  8795. {
  8796. return;
  8797. }
  8798. var dialog = document.getElementById(id);
  8799. var input = dialog && dialog.querySelector('input[type="text"],input[type="number"]');
  8800. if (!input)
  8801. {
  8802. return;
  8803. }
  8804. ensureNumberInput(input);
  8805. };
  8806. }
  8807. amountInputs.init = init;
  8808. })(amountInputs || (amountInputs = {}));
  8809.  
  8810. /**
  8811. * improves the top bar
  8812. */
  8813. var newTopbar;
  8814. (function (newTopbar)
  8815. {
  8816. newTopbar.name = 'newTopbar';
  8817. var linkCell, tabCell, infoCell;
  8818. var addQueues = {
  8819. link: []
  8820. , tab: []
  8821. , info: []
  8822. };
  8823.  
  8824. function createPipeNode()
  8825. {
  8826. return document.createTextNode('|');
  8827. }
  8828.  
  8829. function addLinkEntry(el)
  8830. {
  8831. if (!linkCell)
  8832. {
  8833. addQueues.link.push(el);
  8834. }
  8835. else
  8836. {
  8837. linkCell.appendChild(createPipeNode());
  8838. linkCell.appendChild(el);
  8839. }
  8840. }
  8841. newTopbar.addLinkEntry = addLinkEntry;
  8842.  
  8843. function addTabEntry(el)
  8844. {
  8845. if (!tabCell)
  8846. {
  8847. addQueues.tab.push(el);
  8848. }
  8849. else
  8850. {
  8851. tabCell.appendChild(createPipeNode());
  8852. tabCell.appendChild(el);
  8853. }
  8854. }
  8855. newTopbar.addTabEntry = addTabEntry;
  8856.  
  8857. function addInfoEntry(el)
  8858. {
  8859. if (!infoCell)
  8860. {
  8861. addQueues.info.push(el);
  8862. }
  8863. else
  8864. {
  8865. if (infoCell.firstChild)
  8866. {
  8867. infoCell.insertBefore(createPipeNode(), infoCell.firstChild);
  8868. infoCell.insertBefore(el, infoCell.firstChild);
  8869. }
  8870. else
  8871. {
  8872. infoCell.appendChild(createPipeNode());
  8873. infoCell.appendChild(el);
  8874. }
  8875. }
  8876. }
  8877. newTopbar.addInfoEntry = addInfoEntry;
  8878.  
  8879. function init()
  8880. {
  8881. if (!settings.get(settings.KEY.useNewToolbar))
  8882. {
  8883. return;
  8884. }
  8885. 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");
  8886. var table = document.querySelector('table.top-links');
  8887. if (!table)
  8888. {
  8889. return;
  8890. }
  8891. var row = table.rows.item(0);
  8892. var cells = row.cells;
  8893. var tabIdx = [2, 5];
  8894. var infoIdx = [6, 7];
  8895. var newRow = table.insertRow(-1);
  8896. linkCell = newRow.insertCell(-1);
  8897. tabCell = newRow.insertCell(-1);
  8898. tabCell.style.textAlign = 'center';
  8899. infoCell = newRow.insertCell(-1);
  8900. infoCell.style.textAlign = 'right';
  8901. for (var i = 0; i < cells.length; i++)
  8902. {
  8903. var container = linkCell;
  8904. if (tabIdx.indexOf(i) != -1)
  8905. {
  8906. container = tabCell;
  8907. }
  8908. else if (infoIdx.indexOf(i) != -1)
  8909. {
  8910. container = infoCell;
  8911. }
  8912. var cell = cells.item(i);
  8913. var el = cell.firstElementChild;
  8914. if (cell.childNodes.length > 1)
  8915. {
  8916. el = document.createElement('span');
  8917. el.style.color = 'yellow';
  8918. while (cell.childNodes.length > 0)
  8919. {
  8920. el.appendChild(cell.childNodes[0]);
  8921. }
  8922. }
  8923. if (container.children.length > 0)
  8924. {
  8925. container.appendChild(createPipeNode());
  8926. }
  8927. if (el)
  8928. {
  8929. container.appendChild(el);
  8930. }
  8931. }
  8932. var parent = row.parentElement;
  8933. if (parent)
  8934. {
  8935. parent.removeChild(row);
  8936. }
  8937. for (var _i = 0, _a = addQueues.link; _i < _a.length; _i++)
  8938. {
  8939. var el = _a[_i];
  8940. addLinkEntry(el);
  8941. }
  8942. for (var _b = 0, _c = addQueues.tab; _b < _c.length; _b++)
  8943. {
  8944. var el = _c[_b];
  8945. addTabEntry(el);
  8946. }
  8947. for (var _d = 0, _e = addQueues.info; _d < _e.length; _d++)
  8948. {
  8949. var el = _e[_d];
  8950. addInfoEntry(el);
  8951. }
  8952. var _openTab = win.openTab;
  8953. win.openTab = function (newTab)
  8954. {
  8955. var oldTab = win.currentOpenTab;
  8956. _openTab(newTab);
  8957. var children = tabCell.children;
  8958. for (var i = 0; i < children.length; i++)
  8959. {
  8960. var el = children[i];
  8961. var match = (el.getAttribute('onclick') || '').match(/openTab\('([^']+)'\)/);
  8962. if (!match)
  8963. {
  8964. continue;
  8965. }
  8966. var tab = match[1];
  8967. if (oldTab == tab)
  8968. {
  8969. el.style.color = '';
  8970. }
  8971. if (newTab == tab)
  8972. {
  8973. el.style.color = 'white';
  8974. }
  8975. }
  8976. };
  8977. }
  8978. newTopbar.init = init;
  8979. })(newTopbar || (newTopbar = {}));
  8980.  
  8981. /**
  8982. * style tweaks
  8983. */
  8984. var styleTweaks;
  8985. (function (styleTweaks)
  8986. {
  8987. styleTweaks.name = 'styleTweaks';
  8988. var bodyRegex = /(\bbody)(\s|$)/i;
  8989.  
  8990. function addTweakStyle(setting, style)
  8991. {
  8992. if (setting != '')
  8993. {
  8994. var prefix_1 = setting === '' ? '' : 'body.' + setting + ' ';
  8995. style = style
  8996. .replace(/(^\s*|\}\s*)([^\{\}]+)(?=\s*\{)/g, function (wholeMatch, before, rules)
  8997. {
  8998. return before + rules.split(',').map(function (rule)
  8999. {
  9000. if (bodyRegex.test(rule) && setting !== '')
  9001. {
  9002. return rule.replace(bodyRegex, '$1.' + setting + '$2');
  9003. }
  9004. return rule.replace(/^(\s*\n\s*)?/, '$1' + prefix_1);
  9005. }).join(',');
  9006. });
  9007. document.body.classList.add(setting);
  9008. }
  9009. addStyle(style, setting != '' ? setting : null);
  9010. }
  9011. // tweak oil production/consumption
  9012. function tweakOil()
  9013. {
  9014. 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");
  9015. // make room for oil cell on small devices
  9016. var oilFlowValues = document.getElementById('oil-flow-values');
  9017. var oilFlowCell = oilFlowValues.parentElement;
  9018. oilFlowCell.style.width = '30%';
  9019. }
  9020.  
  9021. function tweakSelection()
  9022. {
  9023. 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");
  9024. }
  9025. // tweak stardust monitor of DH2QoL to keep it in place
  9026. function tweakStardust()
  9027. {
  9028. 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");
  9029. }
  9030.  
  9031. function tweakSkillLevelText()
  9032. {
  9033. addTweakStyle('', "\ndiv.skill-xp-label\n{\n\ttext-shadow: white 0px 0px 0.5rem;\n}\n\t\t");
  9034. }
  9035.  
  9036. function tweakFightDialog()
  9037. {
  9038. 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");
  9039. }
  9040.  
  9041. function addAdditionalSkillBars()
  9042. {
  9043. if (!settings.get(settings.KEY.skillBars)){
  9044. return;
  9045. }
  9046. var _loadSkillTabs = win.loadSkillTabs;
  9047. win.loadSkillTabs = function ()
  9048. {
  9049. _loadSkillTabs();
  9050. for (var _i = 0, SKILL_LIST_1 = SKILL_LIST; _i < SKILL_LIST_1.length; _i++)
  9051. {
  9052. var skill = SKILL_LIST_1[_i];
  9053. var unlocked = getGameValue(skill + 'Unlocked') == 1;
  9054. if (!unlocked)
  9055. {
  9056. continue;
  9057. }
  9058. var xp = getGameValue(skill + 'Xp');
  9059. var currentLevelXp = win.getXpNeeded(win.getLevel(xp));
  9060. var nextLevelXp = win.getXpNeeded(win.getLevel(xp) + 1);
  9061. var perc = (xp - currentLevelXp) / (nextLevelXp - currentLevelXp) * 100;
  9062. var progress = document.getElementById('skill-progress-' + skill);
  9063. if (progress)
  9064. {
  9065. if (currentLevelXp >= 10000000)
  9066. {
  9067. perc = 100;
  9068. progress.style.backgroundColor = "yellow";
  9069. }
  9070. progress.style.width = perc + '%';
  9071. }
  9072. }
  9073. };
  9074. // init additional skill bars
  9075. 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");
  9076. for (var _i = 0, SKILL_LIST_2 = SKILL_LIST; _i < SKILL_LIST_2.length; _i++)
  9077. {
  9078. var skill = SKILL_LIST_2[_i];
  9079. var cell = document.getElementById('top-bar-level-td-' + skill);
  9080. if (!cell)
  9081. {
  9082. continue;
  9083. }
  9084. var levelBar = document.createElement('div');
  9085. levelBar.className = 'skill-bar';
  9086. var progress = document.createElement('div');
  9087. progress.id = 'skill-progress-' + skill;
  9088. progress.className = 'skill-progress';
  9089. levelBar.appendChild(progress);
  9090. cell.appendChild(levelBar);
  9091. // update skill level progress bars on click
  9092. levelBar.addEventListener('click', function ()
  9093. {
  9094. return win.loadSkillTabs();
  9095. });
  9096. }
  9097. win.loadSkillTabs();
  9098. }
  9099. // highlight cooking level requirement when not matched
  9100. function highlightCookinglevel()
  9101. {
  9102. var _cookFoodDialogue = win.cookFoodDialogue;
  9103. win.cookFoodDialogue = function (rawFood)
  9104. {
  9105. _cookFoodDialogue(rawFood);
  9106. var dialog = document.getElementById('dialogue-id-cook-food');
  9107. if (!dialog)
  9108. {
  9109. return;
  9110. }
  9111. var levelReq = document.getElementById('dialogue-cook-levelReq');
  9112. var levelReqLabel = levelReq && levelReq.previousElementSibling;
  9113. if (!levelReq || !levelReqLabel)
  9114. {
  9115. return;
  9116. }
  9117. var fulfilled = win.getCookingLevelReq(rawFood) > win.getLevel(win.cookingXp);
  9118. levelReq.style.color = fulfilled ? 'rgb(204, 0, 0)' : '';
  9119. levelReq.style.fontWeight = fulfilled ? 'bold' : '';
  9120. levelReqLabel.style.color = fulfilled ? 'rgb(204, 0, 0)' : '';
  9121. var ratioEl = document.getElementById('dialogue-cook-ratio');
  9122. if (!ratioEl)
  9123. {
  9124. var cookReqBox = levelReq.parentElement;
  9125. var br = document.createElement('br');
  9126. cookReqBox.appendChild(br);
  9127. var b = document.createElement('b');
  9128. 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\">: ";
  9129. cookReqBox.appendChild(b);
  9130. ratioEl = document.createElement('span');
  9131. ratioEl.id = 'dialogue-cook-ratio';
  9132. cookReqBox.appendChild(ratioEl);
  9133. }
  9134. var heat = win.getHeatNeeded(rawFood);
  9135. var energy = win.getEnergyGained(rawFood);
  9136. ratioEl.textContent = format.number(Math.round(energy / heat * 100) / 100);
  9137. };
  9138. }
  9139.  
  9140. function amountStyle()
  9141. {
  9142. var tweakName = 'amount-symbol';
  9143. 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");
  9144.  
  9145. function setAmountSymbolVisibility(init)
  9146. {
  9147. if (init === void 0)
  9148. {
  9149. init = false;
  9150. }
  9151. var show = settings.get(settings.KEY.amountSymbol);
  9152. document.body.classList[show ? 'add' : 'remove'](tweakName);
  9153. if (init)
  9154. {
  9155. settings.observe(settings.KEY.amountSymbol, function ()
  9156. {
  9157. return setAmountSymbolVisibility();
  9158. });
  9159. }
  9160. }
  9161. setAmountSymbolVisibility(true);
  9162. }
  9163.  
  9164. function efficiency()
  9165. {
  9166. var EFFICIENCY_CLASS = 'efficiency';
  9167. 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");
  9168. var farmingTab = document.getElementById('tab-container-farming');
  9169. if (farmingTab)
  9170. {
  9171. removeWhitespaceChildNodes(farmingTab);
  9172. }
  9173. var combatSubTab = document.getElementById('tab-sub-container-combat');
  9174. if (combatSubTab)
  9175. {
  9176. removeWhitespaceChildNodes(combatSubTab);
  9177. }
  9178.  
  9179. function checkSetting(init)
  9180. {
  9181. if (init === void 0)
  9182. {
  9183. init = false;
  9184. }
  9185. var show = settings.get(settings.KEY.useEfficiencyStyle);
  9186. document.body.classList[show ? 'add' : 'remove'](EFFICIENCY_CLASS);
  9187. if (init)
  9188. {
  9189. settings.observe(settings.KEY.useEfficiencyStyle, function ()
  9190. {
  9191. return checkSetting();
  9192. });
  9193. }
  9194. }
  9195. checkSetting(true);
  9196. }
  9197.  
  9198. function hardcore()
  9199. {
  9200. if (win.isHardcore != 1)
  9201. {
  9202. return;
  9203. }
  9204. addStyle("\nspan#shop-giant-button-playermarket\n{\n\tbackground-color: gray;\n\tbackground-image: none;\n\tcursor: not-allowed;\n}\n\t\t");
  9205. var marketBtn = document.getElementById('shop-giant-button-playermarket');
  9206. if (marketBtn)
  9207. {
  9208. marketBtn.removeAttribute('onclick');
  9209. marketBtn.setAttribute('title', 'The player market is disabled for hardcore accounts');
  9210. }
  9211. }
  9212.  
  9213. function smallScreen()
  9214. {
  9215. addStyle("\ntable.top-links\n{\n\tz-index: 10;\n}\n\t\t");
  9216. }
  9217.  
  9218. function init()
  9219. {
  9220. tweakOil();
  9221. tweakSelection();
  9222. tweakStardust();
  9223. tweakSkillLevelText();
  9224. tweakFightDialog();
  9225. addAdditionalSkillBars();
  9226. highlightCookinglevel();
  9227. amountStyle();
  9228. efficiency();
  9229. //hardcore();
  9230. smallScreen();
  9231. }
  9232. styleTweaks.init = init;
  9233. })(styleTweaks || (styleTweaks = {}));
  9234.  
  9235. /**
  9236. * add ingame notification boxes
  9237. */
  9238. var notifBoxes;
  9239. (function (notifBoxes)
  9240. {
  9241. notifBoxes.name = 'notifBoxes';
  9242.  
  9243. function addNotifBox(imageKey, itemKey, showFront)
  9244. {
  9245. if (itemKey === void 0)
  9246. {
  9247. itemKey = null;
  9248. }
  9249. if (showFront === void 0)
  9250. {
  9251. showFront = false;
  9252. }
  9253. var notifBox = document.createElement('span');
  9254. notifBox.className = 'notif-box';
  9255. notifBox.id = 'notification-static-' + imageKey;
  9256. notifBox.style.display = 'none';
  9257. if (showFront)
  9258. {
  9259. notifBox.style.cssFloat = 'left';
  9260. }
  9261. notifBox.innerHTML = "<img src=\"images/" + imageKey + ".png\" class=\"image-icon-50\" id=\"notif-" + imageKey + "-img\">";
  9262. if (itemKey != null)
  9263. {
  9264. notifBox.innerHTML += "<span data-item-display=\"" + itemKey + "\" style=\"margin-left: 10px;\"></span>";
  9265. }
  9266. var notifArea = document.getElementById('notifaction-area');
  9267. if (notifArea)
  9268. {
  9269. notifArea.appendChild(notifBox);
  9270. }
  9271. return notifBox;
  9272. }
  9273.  
  9274. function addWorker()
  9275. {
  9276. var notifBox = addNotifBox('workers', null, true);
  9277.  
  9278. function setVisibility()
  9279. {
  9280. var show = win.workersTimer === 1 && settings.get(settings.KEY.useWorkerNotif);
  9281. notifBox.style.display = show ? '' : 'none';
  9282. }
  9283. setVisibility();
  9284. observer.addTick(function ()
  9285. {
  9286. return setVisibility();
  9287. });
  9288. }
  9289. function addFaradoxCrystal()
  9290. {
  9291. var notifBox = addNotifBox('faradoxsLair/tombIcon', null, true);
  9292.  
  9293. function setVisibility()
  9294. {
  9295. var show = (win.tombCd == 0 && quest16 == -1) && settings.get(settings.KEY.useTombNotif);
  9296. notifBox.style.display = show ? '' : 'none';
  9297. }
  9298. setVisibility();
  9299. observer.addTick(function ()
  9300. {
  9301. return setVisibility();
  9302. });
  9303. }
  9304. function addBobsUncle()
  9305. {
  9306. var notifBox = addNotifBox('bobsUncle', null, true);
  9307.  
  9308. function setVisibility()
  9309. {
  9310. var show = win.farmingPatchStage7 == 4 && settings.get(settings.KEY.useBobsUncleNotif);
  9311. notifBox.style.display = show ? '' : 'none';
  9312. }
  9313. setVisibility();
  9314. observer.addTick(function ()
  9315. {
  9316. return setVisibility();
  9317. });
  9318. }
  9319. function addRedCombatLootOrb()
  9320. {
  9321. var notifBox = addNotifBox('redCombatLootOrb', null, true);
  9322.  
  9323. function setVisibility()
  9324. {
  9325. var show = (win.redCombatLootOrbTimer === 0 && win.boundRedCombatLootOrb === 1);
  9326. notifBox.style.display = show ? '' : 'none';
  9327. }
  9328. setVisibility();
  9329. observer.addTick(function ()
  9330. {
  9331. return setVisibility();
  9332. });
  9333. }
  9334. function addCharcoalFoundry()
  9335. {
  9336. var notifBox = addNotifBox('charcoalFoundry', null, true);
  9337.  
  9338. function setVisibility()
  9339. {
  9340. var show = (win.charcoalFoundry === 1 && win.charcoalFoundryPerc === 0);
  9341. notifBox.style.display = show ? '' : 'none';
  9342. }
  9343. setVisibility();
  9344. observer.addTick(function ()
  9345. {
  9346. return setVisibility();
  9347. });
  9348. }
  9349. function fixMixingStandTimer(){
  9350. function checkReady(){
  9351. if (mixingStandTimer > 1){
  9352. $("#notification-static-mixingStand").css("background", "linear-gradient(#801A00, #C15033)");
  9353. }else {
  9354. $("#notification-static-mixingStand").css("background", "linear-gradient(rgb(22, 22, 24), rgb(239, 255, 0))");
  9355. }
  9356. }
  9357. checkReady();
  9358. observer.addTick(function ()
  9359. {
  9360. return checkReady();
  9361. });
  9362. }
  9363.  
  9364. function init()
  9365. {
  9366. 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");
  9367.  
  9368. // remove pure text nodes
  9369. var notifArea = document.getElementById('notifaction-area');
  9370. if (notifArea)
  9371. {
  9372. removeWhitespaceChildNodes(notifArea);
  9373. }
  9374. //addWorker();
  9375. addBobsUncle();
  9376. //addFaradoxCrystal();
  9377. addRedCombatLootOrb();
  9378. addCharcoalFoundry();
  9379. fixMixingStandTimer();
  9380. }
  9381. notifBoxes.init = init;
  9382. })(notifBoxes || (notifBoxes = {}));
  9383.  
  9384.  
  9385. /**
  9386. * extend market
  9387. */
  9388. var market;
  9389. (function (market)
  9390. {
  9391. market.name = 'market';
  9392. // max limit age: 5min
  9393. var MAX_LIMIT_AGE = 5 * 60 * 1e3;
  9394. var PRICE_HISTORY_KEY = 'priceHistory';
  9395. // 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)
  9396. var MAX_ENTRIES_PER_ITEM = 2e3;
  9397. var SYNC_URL_REGEX = /^(?:https?:\/\/)?(?:(?:www\.)?myjson\.com\/|api\.myjson\.com\/bins\/)([^\/]+)$/i;
  9398. var detectedTedsUIOnce = false;
  9399.  
  9400. function detectTedsUI()
  9401. {
  9402. return detectedTedsUIOnce = detectedTedsUIOnce || typeof win.changeSetting === 'function';
  9403. }
  9404. market.detectTedsUI = detectTedsUI;
  9405. var priceHistory = store.has(PRICE_HISTORY_KEY) ? store.get(PRICE_HISTORY_KEY) :
  9406. {};
  9407. var getItemColor = function (H, S, L)
  9408. {
  9409. return [
  9410. "hsl(" + H + ", " + S + "%, " + L + "%)"
  9411. , "hsl(" + H + ", " + S + "%, " + (L < 35 ? L + 35 : L - 35) + "%)"
  9412. ];
  9413. };
  9414. var itemColor = {
  9415. 'blewitMushroom': getItemColor(255, 100, 78)
  9416. , 'bronzeBar': getItemColor(39, 100, 46)
  9417. , 'crystalLeaf': getItemColor(226, 100, 50)
  9418. , 'diamond': getItemColor(186, 76, 82)
  9419. , 'dottedGreenLeaf': getItemColor(92, 63, 19)
  9420. , 'emerald': getItemColor(110, 100, 48)
  9421. , 'goldLeaf': getItemColor(50, 100, 50)
  9422. , 'goldBar': getItemColor(54, 100, 46)
  9423. , 'greenLeaf': getItemColor(92, 63, 28)
  9424. , 'ironBar': getItemColor(44, 11, 46)
  9425. , 'limeLeaf': getItemColor(110, 72, 40)
  9426. , 'promethiumBar': getItemColor(354, 81, 46)
  9427. , 'redMushroom': getItemColor(0, 83, 48)
  9428. , 'ruby': getItemColor(5, 87, 45)
  9429. , 'sapphire': getItemColor(197, 100, 32)
  9430. , 'shrimp': getItemColor(17, 88, 50)
  9431. , 'silverBar': getItemColor(0, 0, 74)
  9432. , 'snapegrass': getItemColor(120, 99, 42)
  9433. , 'stardust': getItemColor(37, 100, 50)
  9434. //, 'strangeLeaf': getItemColor(195, 100, 40)
  9435. };
  9436. // use ambassadors to name the categories
  9437. var categoryAmbassador2CategoryName = {
  9438. 'stone': 'Ores' // 0
  9439. , 'emptyChisel': 'Crystals' // 1
  9440. , 'bronzeBar': 'Bars' // 2
  9441. , 'dottedGreenLeafSeeds': 'Seeds' // 3
  9442. , 'logs': 'Logs' // 4
  9443. , 'dottedGreenLeaf': 'Ingredients' // 5
  9444. , 'rawShrimp': 'Fish' // 6
  9445. , 'shrimp': 'Food' // 7
  9446. , 'stinger': 'Equipment' // 8
  9447. , 'promethiumHelmetMould': 'Mould' // 9
  9448. //, 'essence': 'Magic' // 10
  9449. , 'blueFishingRodOrb': 'Orbs' // 10
  9450. , 'stardust': 'Other' // 11
  9451. };
  9452. var item2Category = new Map();
  9453. var category2Name = new Map();
  9454. var item2Resolver = new Map();
  9455. var itemLimits = new Map();
  9456. var offerPerItem = new Map();
  9457. var offerList = new Array();
  9458. var lastSyncValue = '{}';
  9459.  
  9460. function getSyncUrl()
  9461. {
  9462. if (!settings.get(settings.KEY.syncPriceHistory))
  9463. {
  9464. return null;
  9465. }
  9466. var url = settings.getSub(settings.KEY.syncPriceHistory, 'url');
  9467. var match = url.match(SYNC_URL_REGEX);
  9468. if (!match)
  9469. {
  9470. console.error('URL "' + url + '" does not match the expected pattern: ' + SYNC_URL_REGEX.source);
  9471. return null;
  9472. }
  9473. return 'https://api.myjson.com/bins/' + match[1];
  9474. }
  9475.  
  9476. function integratePriceData(data, responseText)
  9477. {
  9478. var changed = recIntegrate(data, priceHistory);
  9479. lastSyncValue = responseText;
  9480. return changed;
  9481.  
  9482. function recIntegrate(source, target)
  9483. {
  9484. var changed = false;
  9485. if (typeof source !== typeof target)
  9486. {
  9487. console.error('Different data types. Could not integrate data into local price history.\nsource: ' + JSON.stringify(source) + '\ntarget: ' + JSON.stringify(target));
  9488. }
  9489. else if (typeof source === 'object')
  9490. {
  9491. for (var key in source)
  9492. {
  9493. if (source.hasOwnProperty(key))
  9494. {
  9495. if (!target.hasOwnProperty(key))
  9496. {
  9497. target[key] = source[key];
  9498. changed = true;
  9499. }
  9500. else if (recIntegrate(source[key], target[key]))
  9501. {
  9502. changed = true;
  9503. }
  9504. }
  9505. }
  9506. }
  9507. else
  9508. {
  9509. // do nothing and prefer the local value
  9510. }
  9511. return changed;
  9512. }
  9513. }
  9514.  
  9515. function loadPriceHistory()
  9516. {
  9517. var url = getSyncUrl();
  9518. if (url)
  9519. {
  9520. win.$.get(url, function (data, textStatus, jqXHR)
  9521. {
  9522. if (integratePriceData(data, jqXHR.responseText))
  9523. {
  9524. savePriceHistory(true);
  9525. }
  9526. });
  9527. }
  9528. }
  9529.  
  9530. function savePriceHistory(forceWrite)
  9531. {
  9532. if (forceWrite === void 0)
  9533. {
  9534. forceWrite = false;
  9535. }
  9536. for (var itemKey in priceHistory)
  9537. {
  9538. var history_1 = priceHistory[itemKey];
  9539. var timestampList = Object.keys(history_1).sort();
  9540. var i = 0;
  9541. for (var _i = 0, timestampList_1 = timestampList; _i < timestampList_1.length; _i++)
  9542. {
  9543. var timestamp = timestampList_1[_i];
  9544. i++;
  9545. if (i > MAX_ENTRIES_PER_ITEM)
  9546. {
  9547. delete history_1[timestamp];
  9548. }
  9549. }
  9550. }
  9551. store.set(PRICE_HISTORY_KEY, priceHistory);
  9552. var url = getSyncUrl();
  9553. if (url)
  9554. {
  9555. var doPut_1 = function ()
  9556. {
  9557. $.ajax(
  9558. {
  9559. url: url
  9560. , type: 'PUT'
  9561. , data: JSON.stringify(priceHistory)
  9562. , contentType: 'application/json; charset=utf-8'
  9563. , dataType: 'json'
  9564. , success: function (data, textStatus, jqXHR)
  9565. {
  9566. lastSyncValue = jqXHR.responseText;
  9567. }
  9568. });
  9569. };
  9570. if (forceWrite === true)
  9571. {
  9572. doPut_1();
  9573. }
  9574. else
  9575. {
  9576. win.$.get(url, function (data, textStatus, jqXHR)
  9577. {
  9578. if (lastSyncValue !== jqXHR.responseText)
  9579. {
  9580. integratePriceData(data, jqXHR.responseText);
  9581. }
  9582. doPut_1();
  9583. });
  9584. }
  9585. }
  9586. }
  9587.  
  9588. function processMarketData(data)
  9589. {
  9590. var nowKey = now();
  9591. offerPerItem = new Map();
  9592. offerList = new Array();
  9593. if (data != 'NONE')
  9594. {
  9595. offerList = data.split(';').map(function (offerData)
  9596. {
  9597. var values = offerData.split('~');
  9598. var itemId = Number(values[1]);
  9599. var itemKey = win.jsItemArray[itemId];
  9600. var itemName = key2Name(itemKey);
  9601. var categoryId = item2Category.has(itemKey) ? item2Category.get(itemKey) : -1;
  9602. var offer = {
  9603. offerId: Number(values[0])
  9604. , itemId: itemId
  9605. , itemKey: itemKey
  9606. , itemName: itemName
  9607. , categoryId: categoryId
  9608. , amount: Number(values[2])
  9609. , price: Number(values[3])
  9610. , timeLeft: values[4]
  9611. , playerId: Number(values[5])
  9612. };
  9613. if (!offerPerItem.has(itemKey))
  9614. {
  9615. offerPerItem.set(itemKey, []);
  9616. }
  9617. offerPerItem.get(itemKey).push(offer);
  9618. var history = priceHistory[itemKey];
  9619. if (!history)
  9620. {
  9621. history = {};
  9622. priceHistory[itemKey] = history;
  9623. }
  9624. if (!history.hasOwnProperty(nowKey)
  9625. || history[nowKey] > offer.price)
  9626. {
  9627. history[nowKey] = offer.price;
  9628. }
  9629. return offer;
  9630. });
  9631. }
  9632. savePriceHistory();
  9633. }
  9634.  
  9635. function processItemLimits(itemKey, lowerLimit, upperLimit)
  9636. {
  9637. var limit = {
  9638. timestamp: now()
  9639. , min: lowerLimit
  9640. , max: upperLimit
  9641. };
  9642. itemLimits.set(itemKey, limit);
  9643. if (item2Resolver.has(itemKey))
  9644. {
  9645. var limitArr_1 = [lowerLimit, upperLimit];
  9646. item2Resolver.get(itemKey).forEach(function (resolve)
  9647. {
  9648. return resolve(limitArr_1);
  9649. });
  9650. item2Resolver.delete(itemKey);
  9651. return false;
  9652. }
  9653. return true;
  9654. }
  9655.  
  9656. function showOfferCancelCooldown()
  9657. {
  9658. if (detectTedsUI())
  9659. {
  9660. return;
  9661. }
  9662. 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");
  9663.  
  9664. function slotCooldown(i, init)
  9665. {
  9666. if (init === void 0)
  9667. {
  9668. init = false;
  9669. }
  9670. var cooldownKey = 'marketCancelCooldownSlot' + i;
  9671. var btn = document.getElementById('market-slot-' + i + '-cancel-btn');
  9672. if (btn)
  9673. {
  9674. btn.dataset.cooldown = detectTedsUI() ? '0' : getGameValue(cooldownKey).toString();
  9675. }
  9676. if (init)
  9677. {
  9678. observer.add(cooldownKey, function ()
  9679. {
  9680. return slotCooldown(i);
  9681. });
  9682. }
  9683. }
  9684. for (var i = 1; i <= 3; i++)
  9685. {
  9686. slotCooldown(i, true);
  9687. }
  9688. }
  9689.  
  9690. function addExtraBtns()
  9691. {
  9692. var browseBtn = document.querySelector('.market-browse-button');
  9693. if (!browseBtn)
  9694. {
  9695. return;
  9696. }
  9697. var HISTORY_CLASS = 'local-history';
  9698. var paddingLeft = 30 + 42;
  9699. var paddingRight = 30;
  9700. 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");
  9701. var historyBtn = document.createElement('span');
  9702. historyBtn.className = 'market-browse-button ' + HISTORY_CLASS;
  9703. browseBtn.appendChild(historyBtn);
  9704. var historyItemKey = null;
  9705. var _postItemDialogue = win.postItemDialogue;
  9706. win.postItemDialogue = function (offerTypeEl, itemName, inputEl)
  9707. {
  9708. historyItemKey = itemName;
  9709. _postItemDialogue(offerTypeEl, itemName, inputEl);
  9710. };
  9711. var PRICE_HISTORY_DIALOG_ID = 'dialog-price-history';
  9712. var PRICE_HISTORY_ID = 'price-history';
  9713. var PRICE_HISTORY_ITEM_SELECT_ID = 'price-history-item-select';
  9714. 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");
  9715. var dialog = document.createElement('dialog');
  9716. dialog.id = PRICE_HISTORY_DIALOG_ID;
  9717. dialog.style.display = 'none';
  9718. dialog.style.overflowX = 'hidden';
  9719. 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";
  9720. document.body.appendChild(dialog);
  9721. var itemSelect = document.getElementById(PRICE_HISTORY_ITEM_SELECT_ID);
  9722. var $itemSelect = win.$(itemSelect);
  9723.  
  9724. function loadScripts(urlList, callback)
  9725. {
  9726. var url = urlList[0];
  9727. if (!url)
  9728. {
  9729. callback && callback();
  9730. return;
  9731. }
  9732. var script = document.createElement('script');
  9733. script.src = url;
  9734. script.onload = function ()
  9735. {
  9736. return loadScripts(urlList.slice(1), callback);
  9737. };
  9738. document.head.appendChild(script);
  9739. }
  9740. var monthArray = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  9741. var lastHistoryItemKey;
  9742. var itemKey2SeriesId = {};
  9743. var chart;
  9744. var stage;
  9745. // add style for select2
  9746. var style = document.createElement('link');
  9747. style.rel = 'stylesheet';
  9748. style.href = 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css';
  9749. document.head.appendChild(style);
  9750. loadScripts([
  9751. 'https://cdn.anychart.com/js/7.14.3/anychart.min.js'
  9752. , 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js'
  9753. ], function ()
  9754. {
  9755. chart = win.anychart.area();
  9756. // pass the container id, chart will be displayed there
  9757. stage = anychart.graphics.create(PRICE_HISTORY_ID);
  9758. chart.container(stage);
  9759. var tooltip = chart.tooltip();
  9760. tooltip.displayMode('union');
  9761. tooltip.format(passThis(function (context)
  9762. {
  9763. var name = context.seriesName || 'Price';
  9764. return name + ': ' + (isNaN(context.value) ? '-' : format.number(context.value));
  9765. }));
  9766. tooltip.titleFormat(passThis(function (context)
  9767. {
  9768. var d = new Date(context.x);
  9769. return monthArray[d.getMonth()] + ' ' + d.getDate() + ' @ ' + zeroPadLeft(d.getHours()) + ':' + zeroPadLeft(d.getMinutes()) + ':' + zeroPadLeft(d.getSeconds());
  9770. }));
  9771. var valueAxis = chart.yAxis();
  9772. valueAxis.title().text('Price').enabled(true);
  9773. valueAxis.labels().format(passThis(function (context)
  9774. {
  9775. return format.number(context.value);
  9776. }));
  9777. var timeAxis = chart.xAxis();
  9778. timeAxis.labels().format(passThis(function (context)
  9779. {
  9780. var d = new Date(context.tickValue);
  9781. return d.getDate() + '. ' + monthArray[d.getMonth()];
  9782. }));
  9783. var timeScale = win.anychart.scales.dateTime();
  9784. var ticks = timeScale.ticks();
  9785. ticks.interval(0, 0, 1);
  9786. chart.xScale(timeScale);
  9787. var timeScroller = chart.xScroller();
  9788. timeScroller.enabled(true);
  9789. chart.animation(true, 300);
  9790. chart.legend(true);
  9791. });
  9792. historyBtn.addEventListener('click', function (event)
  9793. {
  9794. event.preventDefault();
  9795. event.stopPropagation();
  9796. var height = Math.floor(.66 * window.innerHeight);
  9797. var width = Math.min(Math.floor(.66 * window.innerWidth), window.innerWidth - 30);
  9798. win.$(dialog).dialog(
  9799. {
  9800. title: 'Price history from local data'
  9801. , height: height
  9802. , width: width
  9803. });
  9804. dialog.style.height = (height) + 'px';
  9805. var itemKeyList = Object.keys(priceHistory).sort();
  9806. itemSelect.innerHTML = "";
  9807. var category2OptGroup = {};
  9808.  
  9809. function ensureOptGroup(categoryId)
  9810. {
  9811. var optGroup = category2OptGroup[categoryId];
  9812. if (!optGroup)
  9813. {
  9814. optGroup = document.createElement('optgroup');
  9815. optGroup.label = category2Name.get(categoryId) || 'Stuff';
  9816. itemSelect.appendChild(optGroup);
  9817. category2OptGroup[categoryId] = optGroup;
  9818. }
  9819. return optGroup;
  9820. }
  9821. var categoryList = Array.from(category2Name.keys()).map(function (id)
  9822. {
  9823. return Number(id);
  9824. }).sort();
  9825. for (var _i = 0, categoryList_1 = categoryList; _i < categoryList_1.length; _i++)
  9826. {
  9827. var categoryId = categoryList_1[_i];
  9828. ensureOptGroup(categoryId);
  9829. }
  9830. var itemKey2EnabledFn = {};
  9831.  
  9832. function replaceEnabled(itemKey, series)
  9833. {
  9834. var _enabled = series.enabled.bind(series);
  9835. itemKey2EnabledFn[itemKey] = _enabled;
  9836. series.enabled = function (value)
  9837. {
  9838. if (value !== undefined)
  9839. {
  9840. var itemList = $itemSelect.val();
  9841. var index = itemList.indexOf(itemKey);
  9842. if (index !== -1)
  9843. {
  9844. itemList.splice(index, 1);
  9845. }
  9846. else
  9847. {
  9848. itemList.push(itemKey);
  9849. }
  9850. $itemSelect.val(itemList).trigger('change');
  9851. }
  9852. return _enabled(value);
  9853. };
  9854. }
  9855. var min = Number.MAX_SAFE_INTEGER;
  9856. var max = 0;
  9857. var enabledSeriesList = [];
  9858. var _loop_1 = function (itemKey)
  9859. {
  9860. if (!itemColor[itemKey])
  9861. {
  9862. var baseColor = colorGenerator.getRandom(
  9863. {
  9864. format: 'hslArray'
  9865. });
  9866. var borderColor = baseColor.slice(0);
  9867. if (borderColor[2] < 35)
  9868. {
  9869. borderColor[2] += 35;
  9870. }
  9871. else
  9872. {
  9873. borderColor[2] -= 35;
  9874. }
  9875. itemColor[itemKey] = [
  9876. "hsl(" + baseColor[0] + ", " + baseColor[1] + "%, " + baseColor[2] + "%)"
  9877. , "hsl(" + borderColor[0] + ", " + borderColor[1] + "%, " + borderColor[2] + "%)"
  9878. ];
  9879. }
  9880. var history_2 = priceHistory[itemKey];
  9881. var keyList = Object.keys(history_2).sort();
  9882. var data = keyList
  9883. .map(function (n)
  9884. {
  9885. return ([
  9886. Number(n)
  9887. , history_2[n]
  9888. ]);
  9889. });
  9890. min = Math.min(Number(keyList[0]), min);
  9891. max = Math.max(Number(keyList[keyList.length - 1]), max);
  9892. var id = itemKey2SeriesId[itemKey];
  9893. var series = void 0;
  9894. if (id != null)
  9895. {
  9896. series = chart.getSeries(id);
  9897. series.data(data);
  9898. }
  9899. else
  9900. {
  9901. var hoverifyColor = function (hslColor)
  9902. {
  9903. return (
  9904. {
  9905. color: hslColor
  9906. , opacity: .8
  9907. });
  9908. };
  9909. series = chart.area(data);
  9910. itemKey2SeriesId[itemKey] = series.id();
  9911. series.name(key2Name(itemKey));
  9912. var bgColor = itemColor[itemKey][0];
  9913. var strokeColor = itemColor[itemKey][1];
  9914. series.fill(bgColor);
  9915. var bgColorHover = hoverifyColor(bgColor);
  9916. series.selectFill(bgColorHover);
  9917. series.hoverFill(bgColorHover);
  9918. series.stroke(strokeColor, 2);
  9919. var strokeColorHover = hoverifyColor(strokeColor);
  9920. series.hoverStroke(strokeColorHover, 2);
  9921. series.selectStroke(strokeColorHover, 2);
  9922. var markerOptions = {
  9923. fill: strokeColor
  9924. , size: 5
  9925. , type: 'circle'
  9926. };
  9927. series.hoverMarkers(markerOptions);
  9928. series.selectMarkers(markerOptions);
  9929. replaceEnabled(itemKey, series);
  9930. }
  9931. if (lastHistoryItemKey !== historyItemKey)
  9932. {
  9933. if (itemKey === historyItemKey)
  9934. {
  9935. enabledSeriesList.push(series);
  9936. }
  9937. series.enabled(false);
  9938. }
  9939. var categoryId = item2Category.has(itemKey) ? item2Category.get(itemKey) : -1;
  9940. var optGroup = ensureOptGroup(categoryId);
  9941. var option = document.createElement('option');
  9942. option.value = itemKey;
  9943. option.textContent = key2Name(itemKey);
  9944. optGroup.appendChild(option);
  9945. };
  9946. for (var _a = 0, itemKeyList_1 = itemKeyList; _a < itemKeyList_1.length; _a++)
  9947. {
  9948. var itemKey = itemKeyList_1[_a];
  9949. _loop_1(itemKey);
  9950. }
  9951. stage.listenOnce('renderfinish', function ()
  9952. {
  9953. enabledSeriesList.forEach(function (series)
  9954. {
  9955. return series.enabled(true);
  9956. });
  9957. });
  9958. var timeScale = chart.xScale();
  9959. timeScale.minimum(min);
  9960. timeScale.maximum(max);
  9961. var timeZoom = chart.xZoom();
  9962. var threeDaysLong = 3 * 24 * 60 * 60 * 1e3;
  9963. timeZoom.setToValues(Math.max(max - threeDaysLong, min), max);
  9964. // call the chart draw() method to initiate chart display
  9965. chart.draw(true);
  9966. // init item select
  9967. if ($itemSelect.data('select2'))
  9968. {
  9969. $itemSelect.select2('destroy');
  9970. }
  9971. $itemSelect.select2();
  9972.  
  9973. function getEnabledFn(event)
  9974. {
  9975. var data = event.params.data;
  9976. var itemKey = data.id;
  9977. var enabledFn = itemKey2EnabledFn[itemKey];
  9978. if (enabledFn)
  9979. {
  9980. return enabledFn;
  9981. }
  9982. else
  9983. {
  9984. var id = itemKey2SeriesId[itemKey];
  9985. var series = chart.getSeries(id);
  9986. return series.enabled.bind(series);
  9987. }
  9988. }
  9989. $itemSelect.on('select2:select', function (event)
  9990. {
  9991. getEnabledFn(event)(true);
  9992. });
  9993. $itemSelect.on('select2:unselect', function (event)
  9994. {
  9995. getEnabledFn(event)(false);
  9996. // close select menu when it was closed before an element has been removed
  9997. var openBefore = $itemSelect.data('select2').$container.hasClass('select2-container--open');
  9998. setTimeout(function ()
  9999. {
  10000. if (!openBefore && $itemSelect.data('select2').$container.hasClass('select2-container--open'))
  10001. {
  10002. $itemSelect.select2('close');
  10003. }
  10004. });
  10005. });
  10006. lastHistoryItemKey = historyItemKey;
  10007. });
  10008. }
  10009. var categoryList = [-1];
  10010. var itemListPerCategory = new Map();
  10011.  
  10012. function improveOfferList()
  10013. {
  10014. var itemArea = document.getElementById('dialogue-market-items-area');
  10015. if (itemArea)
  10016. {
  10017. var children = itemArea.children;
  10018. for (var i = 1; i < children.length; i++)
  10019. {
  10020. var categoryId = i - 1;
  10021. categoryList.push(categoryId);
  10022. var box = children.item(i);
  10023. var inputs = box.children;
  10024. for (var j = 0; j < inputs.length; j++)
  10025. {
  10026. var match = inputs.item(j).src.match(/images\/([^\/]+)\.(?:png|jpe?g|gif)/);
  10027. if (!match)
  10028. {
  10029. continue;
  10030. }
  10031. var itemKey = match[1];
  10032. item2Category.set(itemKey, categoryId);
  10033. if (categoryAmbassador2CategoryName[itemKey])
  10034. {
  10035. category2Name.set(categoryId, categoryAmbassador2CategoryName[itemKey]);
  10036. }
  10037. if (!itemListPerCategory.has(categoryId))
  10038. {
  10039. itemListPerCategory.set(categoryId, []);
  10040. }
  10041. itemListPerCategory.get(categoryId).push(itemKey);
  10042. }
  10043. }
  10044. }
  10045. }
  10046.  
  10047. function getItemLimit(itemKey)
  10048. {
  10049. // TODO: combine list of offers with min/max-boundries
  10050. var limit = itemLimits.get(itemKey);
  10051. if (limit && limit.timestamp > now() - MAX_LIMIT_AGE)
  10052. {
  10053. return Promise.resolve([limit.min, limit.max]);
  10054. }
  10055. else if (!win.jsTradalbeItems.hasOwnProperty(itemKey))
  10056. {
  10057. return Promise.resolve([0, 0]);
  10058. }
  10059. return new Promise(function (resolve, reject)
  10060. {
  10061. win.postItemDialogue(
  10062. {
  10063. value: 'sell'
  10064. }, itemKey, null);
  10065. if (!item2Resolver.has(itemKey))
  10066. {
  10067. item2Resolver.set(itemKey, []);
  10068. }
  10069. item2Resolver.get(itemKey).push(resolve);
  10070. setTimeout(function ()
  10071. {
  10072. return reject(new Error('Request timed out'));
  10073. }, 30e3);
  10074. });
  10075. }
  10076.  
  10077. function calcMarketValue(items)
  10078. {
  10079. var itemKeyList = Object.keys(items);
  10080. return Promise.all(itemKeyList.map(function (key)
  10081. {
  10082. return getItemLimit(key);
  10083. }))
  10084. .then(function (limitList)
  10085. {
  10086. var sum = [0, 0];
  10087. for (var i = 0; i < itemKeyList.length; i++)
  10088. {
  10089. var amount = items[itemKeyList[i]];
  10090. var limit = limitList[i];
  10091. sum[0] += amount * limit[0];
  10092. sum[1] += amount * limit[1];
  10093. }
  10094. return sum;
  10095. });
  10096. }
  10097. market.calcMarketValue = calcMarketValue;
  10098.  
  10099. function init()
  10100. {
  10101.  
  10102. showOfferCancelCooldown();
  10103. addExtraBtns();
  10104. improveOfferList();
  10105. var _chosenPostItemDialogue = win.chosenPostItemDialogue;
  10106. win.chosenPostItemDialogue = function (itemName, lowerLimit, upperLimit)
  10107. {
  10108. if (processItemLimits(itemName, Number(lowerLimit), Number(upperLimit)))
  10109. {
  10110. _chosenPostItemDialogue(itemName, lowerLimit, upperLimit);
  10111. }
  10112. };
  10113. var _addToPlayerMarket = win.addToPlayerMarket;
  10114. win.addToPlayerMarket = function (data)
  10115. {
  10116. processMarketData(data);
  10117. _addToPlayerMarket(data);
  10118. };
  10119. loadPriceHistory();
  10120. // delay (debounce) sending the request for 3s
  10121. var startDebouncedRequest = debounce(function ()
  10122. {
  10123. return loadPriceHistory();
  10124. }, 3e3);
  10125. settings.observe(settings.KEY.syncPriceHistory, function ()
  10126. {
  10127. return startDebouncedRequest();
  10128. });
  10129. settings.observeSub(settings.KEY.syncPriceHistory, 'url', function ()
  10130. {
  10131. return startDebouncedRequest();
  10132. });
  10133. }
  10134. market.init = init;
  10135. })(market || (market = {}));
  10136.  
  10137. var combat;
  10138. (function (combat)
  10139. {
  10140. combat.name = 'combat';
  10141. var LOOT_TABLE_URL = '/wiki/combat.php';
  10142. var COMBAT_LOOT_TABLES_ID = 'combat-loot-tables';
  10143. var CAT_2_NAME = {
  10144. 'always': 'Always'
  10145. , 'common': 'Common'
  10146. , 'uncommon': 'Uncommon'
  10147. , 'rare': 'Rare'
  10148. , 'veryrare': 'Very Rare'
  10149. };
  10150. var lootInfoInitialized = false;
  10151. var lootInfo = {};
  10152.  
  10153. function readLootTable(table)
  10154. {
  10155. var monsterImg = table.getElementsByTagName('img').item(0);
  10156. var src = monsterImg.getAttribute('src') || '';
  10157. var monsterId = src.replace(/.+npc\/(\d+)\.png$/, '$1');
  10158. var info = {
  10159. always: []
  10160. , common: []
  10161. , uncommon: []
  10162. , rare: []
  10163. , veryrare: []
  10164. };
  10165. for (var i = 2; i < table.rows.length; i++)
  10166. {
  10167. var row = table.rows.item(i);
  10168. var match = row.cells.item(0).innerHTML.match(/images\/(.+)\.png/) || row.cells.item(0).innerHTML.match(/images\/(.+)\.gif/);
  10169. if (!match)
  10170. {
  10171. console.error('no item key found:', row.innerHTML);
  10172. continue;
  10173. }
  10174. var itemKey = match[1];
  10175. var amount = row.cells.item(1).textContent || '';
  10176. var rarityCategory = row.cells.item(2).className;
  10177. var dropRate = (rarityCategory == 'Always') ? 'Always' : row.cells.item(2).textContent;
  10178. if (!info.hasOwnProperty(rarityCategory))
  10179. {
  10180. console.error('unknown rarity category:', rarityCategory);
  10181. continue;
  10182. }
  10183. info[rarityCategory].push(
  10184. {
  10185. key: itemKey
  10186. , amount: amount.split(' - ').map(function (s)
  10187. {
  10188. return Number(s.replace(/\D/g, ''));
  10189. })
  10190. , dropRate: dropRate
  10191. });
  10192. }
  10193. lootInfo[monsterId] = info;
  10194. lootInfoInitialized = true;
  10195. }
  10196.  
  10197. function updateLootTableInfo()
  10198. {
  10199. return doGet(LOOT_TABLE_URL)
  10200. .then(function (response)
  10201. {
  10202. var parser = new DOMParser();
  10203. var doc = parser.parseFromString(response, 'text/html');
  10204. var tables = doc.getElementsByTagName('table');
  10205. for (var i = 0; i < tables.length; i++)
  10206. {
  10207. readLootTable(tables.item(i));
  10208. }
  10209. return lootInfo;
  10210. })
  10211. .then(function (info)
  10212. {
  10213. setLootTableTabContent(info);
  10214. });
  10215. }
  10216.  
  10217. function addLootTableTab()
  10218. {
  10219. var subTabContainer = document.getElementById('tab-sub-container-combat');
  10220. var itemContainer = document.getElementById('tab-sub-container-combat-large-btns');
  10221. var afterEl = itemContainer && itemContainer.previousElementSibling;
  10222. if (!subTabContainer || !afterEl)
  10223. {
  10224. return;
  10225. }
  10226. 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");
  10227. var REFRESH_LOOT_TABLE_ID = 'refresh-loot-table';
  10228. var subTab = document.createElement('span');
  10229. subTab.className = 'large-button';
  10230. subTab.innerHTML = "<img class=\"image-icon-50\" src=\"images/combatDropTable.png\" style=\"filter: grayscale(100%);\">Loot";
  10231. subTab.addEventListener('click', function ()
  10232. {
  10233. var _confirmDialogue = win.confirmDialogue;
  10234. win.confirmDialogue = function () {};
  10235. win.clicksOpenDropTable();
  10236. win.confirmDialogue = _confirmDialogue;
  10237. win.openSubTab('loot');
  10238. });
  10239.  
  10240. function setLootTabVisibility()
  10241. {
  10242. var show = settings.get(settings.KEY.showLootTab);
  10243. subTab.style.display = show ? '' : 'none';
  10244. var dropTableItemBox = document.getElementById('item-box-combatDropTable');
  10245. if (dropTableItemBox)
  10246. {
  10247. dropTableItemBox.style.display = show ? 'none' : '';
  10248. }
  10249. if (show && !lootInfoInitialized)
  10250. {
  10251. updateLootTableInfo();
  10252. }
  10253. }
  10254. setLootTabVisibility();
  10255. settings.observe(settings.KEY.showLootTab, function ()
  10256. {
  10257. return setLootTabVisibility();
  10258. });
  10259. subTabContainer.insertBefore(subTab, afterEl);
  10260. var combatSubTab = document.getElementById('tab-sub-container-combat');
  10261. var equipSubTab = document.getElementById('tab-sub-container-equip');
  10262. var spellsSubTab = document.getElementById('tab-sub-container-spells');
  10263. var subPanelContainer = combatSubTab.parentElement;
  10264. var lootSubTab = document.createElement('div');
  10265. lootSubTab.id = 'tab-sub-container-loot';
  10266. lootSubTab.style.display = 'none';
  10267. 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>";
  10268. subPanelContainer.appendChild(lootSubTab);
  10269. var refreshBtn = document.getElementById(REFRESH_LOOT_TABLE_ID);
  10270. if (refreshBtn)
  10271. {
  10272. refreshBtn.addEventListener('click', function ()
  10273. {
  10274. if (refreshBtn.classList.contains('active'))
  10275. {
  10276. return;
  10277. }
  10278. refreshBtn.classList.add('active');
  10279. updateLootTableInfo()
  10280. .then(function ()
  10281. {
  10282. return refreshBtn.classList.remove('active');
  10283. })
  10284. .catch(function ()
  10285. {
  10286. return refreshBtn.classList.remove('active');
  10287. });
  10288. });
  10289. }
  10290. var _openSubTab = win.openSubTab;
  10291. win.openSubTab = function (tab)
  10292. {
  10293. combatSubTab.style.display = 'none';
  10294. equipSubTab.style.display = 'none';
  10295. spellsSubTab.style.display = 'none';
  10296. lootSubTab.style.display = 'none';
  10297. _openSubTab(tab);
  10298. if (tab == 'loot')
  10299. {
  10300. lootSubTab.style.display = 'block';
  10301. }
  10302. };
  10303. var _loadDefaultCombatTab = win.loadDefaultCombatTab;
  10304. win.loadDefaultCombatTab = function ()
  10305. {
  10306. _loadDefaultCombatTab();
  10307. lootSubTab.style.display = 'none';
  10308. };
  10309. }
  10310.  
  10311. function setLootTableTabContent(lootInfo)
  10312. {
  10313. var combatTableWrapper = document.getElementById(COMBAT_LOOT_TABLES_ID);
  10314. if (!combatTableWrapper)
  10315. {
  10316. return;
  10317. }
  10318. combatTableWrapper.innerHTML = "";
  10319. for (var monsterId in lootInfo)
  10320. {
  10321. var info = lootInfo[monsterId];
  10322. var monsterNum = Number(monsterId);
  10323. if (monsterNum > 1 && monsterNum % 3 === 1)
  10324. {
  10325. var lineBreak = document.createElement('div');
  10326. lineBreak.style.clear = 'both';
  10327. lineBreak.innerHTML = "<br>";
  10328. combatTableWrapper.appendChild(lineBreak);
  10329. }
  10330. var table = document.createElement('table');
  10331. table.className = 'hiscores-table';
  10332. var imgRow = table.insertRow(-1);
  10333. 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>";
  10334. var headerRow = table.insertRow(-1);
  10335. headerRow.innerHTML = "<th>Item</th><th>Amount</th><th>Rarity</th>";
  10336. for (var rarityCategory in info)
  10337. {
  10338. var itemList = info[rarityCategory];
  10339. for (var i = 0; i < itemList.length; i++)
  10340. {
  10341. var item = itemList[i];
  10342. var row = table.insertRow(-1);
  10343. row.innerHTML = "<td><img src=\"../images/" + item.key + ".png\" class=\"image-icon-40\"></td><td>" + item.amount.map(function (n){
  10344. return format.number(n);
  10345. }).join(' - ') + "</td><td class=\"" + rarityCategory + "\">" + item.dropRate + "</td>";
  10346. }
  10347. }
  10348. combatTableWrapper.appendChild(table);
  10349. }
  10350. var images = document.querySelectorAll('.hiscores-table .image-icon-40');
  10351. for (let i=0; i < images.length; i++){
  10352. var enchantSG = images[i];
  10353. var fixURL = enchantSG.src = enchantSG.src.replace('/images/enchantedStargemPotion.png','/images/enchantedStargemPotion.gif');
  10354. }
  10355. }
  10356.  
  10357.  
  10358. function init()
  10359. {
  10360. addLootTableTab();
  10361. if (settings.get(settings.KEY.showLootTab))
  10362. {
  10363. updateLootTableInfo();
  10364. }
  10365. }
  10366. combat.init = init;
  10367. })(combat || (combat = {}));
  10368.  
  10369. /**
  10370. * farming improvements
  10371. */
  10372. var farming;
  10373. (function (farming)
  10374. {
  10375. farming.name = 'farming';
  10376. var SEED_INFO_REGEX = {
  10377. minLevel: />\s*Level:/
  10378. , stopsDyingLevel: />\s*Stops\s+Dying\s+Level:/
  10379. , bonemeal: />\s*Bonemeal:/
  10380. , woodcuttingLevel: />\s*Woodcutting\s+Level:/
  10381. };
  10382. var seedInfoSpans = {};
  10383. var seedInfo = {};
  10384. var checkInfo = {
  10385. bonemeal: function (amount)
  10386. {
  10387. return amount <= win.bonemeal;
  10388. }
  10389. , minLevel: function (level)
  10390. {
  10391. return level <= win.getLevel(win.farmingXp);
  10392. }
  10393. , stopsDyingLevel: function (level)
  10394. {
  10395. return level <= win.getLevel(win.farmingXp);
  10396. }
  10397. , woodcuttingLevel: function (level)
  10398. {
  10399. return level <= win.getLevel(win.woodcuttingXp);
  10400. }
  10401. };
  10402. var RED = 'rgb(204, 0, 0)';
  10403.  
  10404. function addBetterStyle()
  10405. {
  10406. var CLASS_NAME = 'seedHighlight';
  10407. 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");
  10408. // seedHighlight
  10409. function updateHoverStyle()
  10410. {
  10411. document.body.classList[settings.get(settings.KEY.highlightUnplantableSeed) ? 'add' : 'remove'](CLASS_NAME);
  10412. }
  10413. updateHoverStyle();
  10414. settings.observe(settings.KEY.highlightUnplantableSeed, function ()
  10415. {
  10416. return updateHoverStyle();
  10417. });
  10418. }
  10419.  
  10420. function readSeedInfo(seedName, tooltipEl)
  10421. {
  10422. var spans = tooltipEl.querySelectorAll(':scope > span');
  10423. var infoSpans = {
  10424. bonemeal: null
  10425. , minLevel: null
  10426. , stopsDyingLevel: null
  10427. , woodcuttingLevel: null
  10428. };
  10429. var info = {
  10430. bonemeal: 0
  10431. , minLevel: 0
  10432. , stopsDyingLevel: 0
  10433. , woodcuttingLevel: 0
  10434. };
  10435. var i = 0;
  10436. for (var key in SEED_INFO_REGEX)
  10437. {
  10438. if (SEED_INFO_REGEX[key].test(spans[i].innerHTML))
  10439. {
  10440. infoSpans[key] = spans.item(i);
  10441. var textNode = spans.item(i).lastChild;
  10442. info[key] = parseInt(textNode.textContent || '', 10);
  10443. i++;
  10444. }
  10445. }
  10446. seedInfoSpans[seedName] = infoSpans;
  10447. seedInfo[seedName] = info;
  10448. }
  10449.  
  10450. function checkSpan(span, fulfilled)
  10451. {
  10452. span.style.color = fulfilled ? '' : RED;
  10453. span.style.fontWeight = fulfilled ? '' : 'bold';
  10454. }
  10455.  
  10456. function checkSeedInfo(seedName, init)
  10457. {
  10458. if (init === void 0)
  10459. {
  10460. init = false;
  10461. }
  10462. var highlight = settings.get(settings.KEY.highlightUnplantableSeed);
  10463. var info = seedInfo[seedName];
  10464. var spans = seedInfoSpans[seedName];
  10465. var canBePlanted = true;
  10466. for (var key in info)
  10467. {
  10468. var span = spans[key];
  10469. if (span)
  10470. {
  10471. var fulfilled = checkInfo[key](info[key]);
  10472. checkSpan(span, !highlight || fulfilled);
  10473. canBePlanted = !highlight || canBePlanted && (key == 'stopsDyingLevel' || fulfilled);
  10474. }
  10475. }
  10476. var itemBox = document.getElementById('item-box-' + seedName);
  10477. if (itemBox)
  10478. {
  10479. itemBox.style.opacity = (!highlight || canBePlanted) ? '' : '.5';
  10480. }
  10481. var plantInput = document.getElementById('dialogue-plant-' + seedName);
  10482. if (plantInput)
  10483. {
  10484. plantInput.style.backgroundColor = (!highlight || canBePlanted) ? '' : 'hsla(0, 100%, 50%, .5)';
  10485. }
  10486. if (init)
  10487. {
  10488. observer.add('bonemeal', function ()
  10489. {
  10490. return checkSeedInfo(seedName);
  10491. });
  10492. observer.add('farmingXp', function ()
  10493. {
  10494. return checkSeedInfo(seedName);
  10495. });
  10496. observer.add('woodcuttingXp', function ()
  10497. {
  10498. return checkSeedInfo(seedName);
  10499. });
  10500. settings.observe(settings.KEY.highlightUnplantableSeed, function ()
  10501. {
  10502. return checkSeedInfo(seedName);
  10503. });
  10504. }
  10505. }
  10506.  
  10507. function getSeedInfo(seedName)
  10508. {
  10509. return seedInfo[seedName];
  10510. }
  10511. farming.getSeedInfo = getSeedInfo;
  10512.  
  10513. function init()
  10514. {
  10515. addBetterStyle();
  10516. // read all seed information
  10517. var tooltipEls = document.querySelectorAll('div[id^="tooltip-"][id$="Seeds"]');
  10518. for (var i = 0; i < tooltipEls.length; i++)
  10519. {
  10520. var tooltipEl = tooltipEls[i];
  10521. var seedName = tooltipEl.id.replace(/^tooltip-/, '');
  10522. readSeedInfo(seedName, tooltipEl);
  10523. checkSeedInfo(seedName, true);
  10524. }
  10525. }
  10526. farming.init = init;
  10527. })(farming || (farming = {}));
  10528.  
  10529. /**
  10530. * add in-game calculators
  10531. */
  10532. var calc;
  10533. (function (calc)
  10534. {
  10535. var mining = {};
  10536. var crafting = {};
  10537. mining.XPConvert = 'xp-gain-pickaxe-convert';
  10538. mining.dialog = 'dialogue-id-boundPickaxe';
  10539. mining.name = 'mining';
  10540. crafting.XPConvert = 'xp-gain-hammer-convert';
  10541. crafting.dialog = 'dialogue-id-boundHammer';
  10542. crafting.name = 'crafting';
  10543.  
  10544. function doubleCalcs(skill){
  10545. var getXPConvert = document.getElementById(skill.XPConvert).innerHTML;
  10546. getXPConvert = getXPConvert.replace(/\,/g,'');
  10547. getXPConvert = parseInt(getXPConvert, 10);
  10548. var currentXP = getGameValue(skill.name + 'Xp');
  10549. var totalXP = currentXP + getXPConvert;
  10550. var level = getLevel(totalXP);
  10551.  
  10552. $('#'+skill.name+'-level').html(format.number(level));
  10553. $('#'+skill.name+'-xp').html(format.number(totalXP));
  10554. }
  10555. function doubleSkills(skill){
  10556. var getSkillDialog = document.getElementById(skill.dialog);
  10557. var div = document.createElement("div");
  10558. div.className = 'basic-smallbox';
  10559. 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)';
  10560.  
  10561. var smallboxes = getSkillDialog.querySelectorAll('div.basic-smallbox');
  10562. getSkillDialog.insertBefore(div, smallboxes[0]);
  10563. }
  10564.  
  10565. function magic(){
  10566.  
  10567. var getSkillDialog = document.getElementById("dialogue-id-meditate");
  10568. var div = document.createElement("div");
  10569. var div2 = document.createElement("div");
  10570. var title = document.createElement("h1");
  10571. title.className = 'container-title';
  10572. title.innerHTML = "Meditation Calculator";
  10573. var closeButton= '<br/><input type="button" value="Close"/>';
  10574.  
  10575. div2.className = 'basic-smallbox';
  10576. div.className = 'basic-smallbox';
  10577. div2.innerHTML = '<b>Target level: </b><input type="number" value="1" id="magic-level" size="4" min="1" max="100" style="width: 47px;">';
  10578. div.innerHTML = '<span> \
  10579. <input type="image" width="50px" id="stone" src="images/empoweredStone.png"> \
  10580. <input type="image" width="50px" id="moonstone" src="images/empoweredMoonstone.png"> \
  10581. <input type="image" width="50px" id="marsrock" src="images/empoweredMarsRock.png"> \
  10582. <input type="image" width="50px" id="promethium" src="images/empoweredPromethium.png"> \
  10583. <input type="image" width="50px" id="runite" src="images/empoweredRunite.png"> \
  10584. </span><br /><b>Empowered Rocks needed:</b> \
  10585. <input type="number" value="0" id="input-empowered-amount" size="4" min="0" max="9999" style="width: 67px;"> \
  10586. <br><img src="images/icons/wizardhat.png" class="image-icon-20"> +<span id="xp-gain-meditate-convert"></span> xp \
  10587. <br><span id="stone-display"><img src="images/stone.png" class="image-icon-20"> -<span id="stone-cost-meditate-convert"></span></span> \
  10588. <span id="moonstone-display" style="display: none"> \
  10589. <img src="images/moonstone.png" class="image-icon-20"> -<span id="moonstone-cost-meditate-convert"></span></span></span> \
  10590. <span id="marsrock-display" style="display: none"> \
  10591. <img src="images/marsRock.png" class="image-icon-20"> -<span id="marsrock-cost-meditate-convert"></span></span> \
  10592. <span id="promethium-display" style="display: none"> \
  10593. <img src="images/promethium.png" class="image-icon-20"> -<span id="promethium-cost-meditate-convert"></span></span> \
  10594. <span id="runite-display" style="display: none"><img src="images/runite.png" class="image-icon-20"> -<span id="runite-cost-meditate-convert"></span></span> \
  10595. <br><img src="images/icons/stardust.png" class="image-icon-20"> -<span id="stardust-cost-meditate-convert"></span> \
  10596. <br><img src="images/icons/hourglass.png" class="image-icon-20"> <span id="duration-meditate-convert"></span> hours \
  10597. ';
  10598. $(getSkillDialog).append(title, div2, div, closeButton);
  10599. }
  10600. function magicCalcXP(number, node){
  10601. if (!number){
  10602. return;
  10603. }
  10604. if (!node){
  10605. return;
  10606. }
  10607. var rock;
  10608. var inputLevel = $('#magic-level');
  10609. var inputRock = $('#input-empowered-amount');
  10610.  
  10611. var getRocks = inputRock.val();
  10612. var donorXPBoost = (win.donorXpBoost > win.currentTimeMillis) ? 1.1 : 1;
  10613. var greenRockOrb = (boundGreenEmpoweredRockOrb) ? 0.8 : 1;
  10614. var achvPerk = (achMagicMediumCompleted) ? 0.5 : 1;
  10615. var blueMeditateOrb = (boundBlueMeditationOrb) ? 0.5 : 1;
  10616.  
  10617. var materials = 1;
  10618. if (number === 1){
  10619. rock = 'stone';
  10620. materials = 1000000 * achvPerk;
  10621. }else if (number === 2){
  10622. rock = 'moonstone';
  10623. materials = 100 * achvPerk;
  10624. }else if (number === 3){
  10625. rock = 'marsrock';
  10626. materials = 10 * achvPerk;
  10627. }else if (number === 4){
  10628. rock = 'promethium';
  10629. materials = 30 * achvPerk;
  10630. }else if (number === 5){
  10631. rock = 'runite';
  10632. materials = 1;
  10633. }
  10634. //find meditate level and time
  10635. var meditateTime = 0;
  10636. for (var i = 1; i <= 9; i++){
  10637. if (getGameValue("meditate"+i) === 1){
  10638. meditateTime = 11 - i;
  10639. }
  10640. }
  10641.  
  10642. var gainXP = (getRocks > 9999) ? Number.NaN : getRocks*10000*donorXPBoost;
  10643. var sdCost = (getRocks > 9999) ? Number.NaN : getRocks*100000*greenRockOrb;
  10644. var matCost = (getRocks > 9999) ? Number.NaN : getRocks*materials;
  10645. var duration = (getRocks > 9999) ? Number.NaN : getRocks*meditateTime*blueMeditateOrb;
  10646. gainXP = parseInt(Math.round(gainXP), 10);
  10647. sdCost = parseInt(Math.round(sdCost), 10);
  10648. var totalXP = win.magicXp + gainXP;
  10649. var level = getLevel(totalXP);
  10650.  
  10651. $('#xp-gain-meditate-convert').html(format.number(gainXP));
  10652. $('#stardust-cost-meditate-convert').html(format.number(sdCost));
  10653. $('#'+node.id+'-cost-meditate-convert').html(format.number(matCost));
  10654. $('#duration-meditate-convert').html(format.number(duration));
  10655. inputLevel.val(level);
  10656.  
  10657. if (node.id == rock){
  10658. document.getElementById('stone').style.backgroundColor = '';
  10659. document.getElementById('moonstone').style.backgroundColor = '';
  10660. document.getElementById('marsrock').style.backgroundColor = '';
  10661. document.getElementById('promethium').style.backgroundColor = '';
  10662. document.getElementById('runite').style.backgroundColor = '';
  10663. node.style.backgroundColor = 'red';
  10664. document.getElementById('stone-display').style.display = "none";
  10665. document.getElementById('moonstone-display').style.display = "none";
  10666. document.getElementById('marsrock-display').style.display = "none";
  10667. document.getElementById('promethium-display').style.display = "none";
  10668. document.getElementById('runite-display').style.display = "none";
  10669. document.getElementById(node.id+'-display').style.display = "";
  10670. }
  10671. }
  10672.  
  10673. function magicCalcLevel(number, node){
  10674. if (!number){
  10675. return;
  10676. }
  10677. if (!node){
  10678. return;
  10679. }
  10680.  
  10681. var inputLevel = $('#magic-level');
  10682. var inputRock = $('#input-empowered-amount');
  10683.  
  10684. var desireLevel = inputLevel.val();
  10685. var donorXPBoost = (win.donorXpBoost > win.currentTimeMillis) ? 1.1 : 1;
  10686. var greenRockOrb = (boundGreenEmpoweredRockOrb) ? 0.8 : 1;
  10687. var achvPerk = (achMagicMediumCompleted) ? 0.5 : 1;
  10688. var blueMeditateOrb = (boundBlueMeditationOrb) ? 0.5 : 1;
  10689. var rock;
  10690. var materials = 1;
  10691. if (number === 1){
  10692. rock = 'stone';
  10693. materials = 1000000 * achvPerk;
  10694. }else if (number === 2){
  10695. rock = 'moonstone';
  10696. materials = 100 * achvPerk;
  10697. }else if (number === 3){
  10698. rock = 'marsrock';
  10699. materials = 10 * achvPerk;
  10700. }else if (number === 4){
  10701. rock = 'promethium';
  10702. materials = 30 * achvPerk;
  10703. }else if (number === 5){
  10704. rock = 'runite';
  10705. materials = 1;
  10706. }
  10707. //find meditate level and time
  10708. var meditateTime = 0;
  10709. for (var i = 1; i <= 9; i++){
  10710. if (getGameValue("meditate"+i) === 1){
  10711. meditateTime = 11 - i;
  10712. }
  10713. }
  10714.  
  10715. var desireXP = Math.round(Math.pow(desireLevel, 3 + desireLevel/200));
  10716. var actualXPneed = (desireLevel > 100) ? Number.NaN : (desireXP - win.magicXp);
  10717. var rockneed = Math.round(actualXPneed/(donorXPBoost * 10000));
  10718. var rockneed2 = (rockneed < 1) ? 1 : rockneed;
  10719. var sdneed = (desireLevel > 100) ? Number.NaN : rockneed2*100000*greenRockOrb;
  10720. var matneed = (desireLevel > 100) ? Number.NaN : rockneed2*materials;
  10721. var duration = (desireLevel > 100) ? Number.NaN : rockneed2*meditateTime*blueMeditateOrb;
  10722.  
  10723. inputRock.val(rockneed2);
  10724. $('#xp-gain-meditate-convert').html(format.number(actualXPneed));
  10725. $('#stardust-cost-meditate-convert').html(format.number(sdneed));
  10726. $('#'+node.id+'-cost-meditate-convert').html(format.number(matneed));
  10727. $('#duration-meditate-convert').html(format.number(duration));
  10728.  
  10729. if (node.id == rock){
  10730. document.getElementById('stone').style.backgroundColor = '';
  10731. document.getElementById('moonstone').style.backgroundColor = '';
  10732. document.getElementById('marsrock').style.backgroundColor = '';
  10733. document.getElementById('promethium').style.backgroundColor = '';
  10734. document.getElementById('runite').style.backgroundColor = '';
  10735. node.style.backgroundColor = 'red';
  10736. document.getElementById('stone-display').style.display = "none";
  10737. document.getElementById('moonstone-display').style.display = "none";
  10738. document.getElementById('marsrock-display').style.display = "none";
  10739. document.getElementById('promethium-display').style.display = "none";
  10740. document.getElementById('runite-display').style.display = "none";
  10741. document.getElementById(node.id+'-display').style.display = "";
  10742. }
  10743. }
  10744. function woodcuttingCalc(){
  10745. var treeXP = {0: 0, 1: 1000, 2: 2500, 3: 5000, 4: 10000, 5: 16000, 6: 20000, 7: 1000,
  10746. 8: 2500, 9: 5000, 10: 10000, 11: 16000, 12: 20000, 13: 40000, 14: 40000};
  10747. var getXP = 0;
  10748.  
  10749. for (var i = 1; i <= 6 ;i++){
  10750. getXP += treeXP[getGameValue('treeId'+ i)];
  10751. }
  10752. var donorXPBoost = (win.donorXpBoost > win.currentTimeMillis) ? 1.1 : 1;
  10753. getXP = getXP*donorXPBoost;
  10754. var bonusPerk = (achWoodcuttingMediumCompleted) ? 5 : 0;
  10755. var bonusGem;
  10756.  
  10757. if (boundEmptyAxe){
  10758. bonusGem = 0;
  10759. }else if (boundSapphireAxe){
  10760. bonusGem = 5;
  10761. }else if (boundEmeraldAxe){
  10762. bonusGem = 10;
  10763. }else if (boundRubyAxe){
  10764. bonusGem = 15;
  10765. }else if (boundDiamondAxe){
  10766. bonusGem = 20;
  10767. }
  10768. var bonusLevel = {};
  10769. bonusLevel = {max: 1, average: 1};
  10770. var WCLevel = win.getLevel(win.woodcuttingXp);
  10771. if (WCLevel < 20){
  10772. bonusLevel = {max: 1, average: 1};
  10773. }else if (WCLevel >= 20 && WCLevel < 30){
  10774. bonusLevel = {max: 2, average: 1};
  10775. }else if (WCLevel >= 30 && WCLevel < 40){
  10776. bonusLevel = {max: 3, average: 2};
  10777. }else if (WCLevel >= 40 && WCLevel < 50){
  10778. bonusLevel = {max: 4, average: 2};
  10779. }else if (WCLevel >= 50 && WCLevel < 60){
  10780. bonusLevel = {max: 5, average: 3};
  10781. }else if (WCLevel >= 60 && WCLevel < 70){
  10782. bonusLevel = {max: 6, average: 3};
  10783. }else if (WCLevel >= 70 && WCLevel < 80){
  10784. bonusLevel = {max: 7, average: 4};
  10785. }else if (WCLevel >= 80 && WCLevel < 90){
  10786. bonusLevel = {max: 8, average: 4};
  10787. }else if (WCLevel >= 90 && WCLevel < 100){
  10788. bonusLevel = {max: 9, average: 5};
  10789. }else if (WCLevel == 100){
  10790. bonusLevel = {max: 10, average: 5};
  10791. }
  10792. var totalMin = 15+bonusPerk+bonusGem+1;
  10793. var totalMax = 30+bonusPerk+bonusGem+bonusLevel.max;
  10794. var totalAverage = (totalMin+totalMax)/2;
  10795. $('#wc-xp').html(format.number(getXP));
  10796. $('#wc-logs-perk').html(format.number(bonusPerk));
  10797. $('#wc-logs-gem').html(format.number(bonusGem));
  10798. $('#wc-level-max').html(format.number(bonusLevel.max));
  10799. $('#wc-level-average').html(format.number(bonusLevel.average));
  10800. $('#wc-total-min').html(format.number(totalMin));
  10801. $('#wc-total-max').html(format.number(totalMax));
  10802. $('#wc-total-logs-average').html(format.number(totalAverage));
  10803. }
  10804. function woodcutting(){
  10805. addStyle('div.smallbox-fix-lines \n{\n\tline-height: 1.6;\n}');
  10806. $("#dialogue-axe-chance").parentsUntil("div").css({"display": "none"});
  10807. $("#dialogue-id-axe").find("br:first").remove();
  10808. var getSkillDialog = document.getElementById('dialogue-id-axe');
  10809. var div = document.createElement("div");
  10810. div.className = 'basic-smallbox';
  10811.  
  10812. 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 /> \
  10813. <b>Current total logs per tree: <x id="wc-total-min" style="color: blue"></x> - <x id="wc-total-max" style="color: blue"></x> \
  10814. (<x id="wc-total-logs-average" style="color: blue"></x> on average)</b><br/> \
  10815. Original logs per tree: 15 - 30 (22 on average)<br/> \
  10816. Bonus logs from woodcutting level: random between 1 - <x id="wc-level-max"></x> \
  10817. (<x id="wc-level-average"></x> on average)</b><br/> \
  10818. Bonus logs from gems: <x id="wc-logs-gem"></x><br/> \
  10819. Bonus logs from achievement perk: <x id="wc-logs-perk"></x></div><br/> \
  10820. <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> \
  10821. <tr><th>Tree</th><td><img src="images/woodcutting/tree4.png" width="65"></td><td><img src="images/woodcutting/oakTree4.png" width="65"></td> \
  10822. <td><img src="images/woodcutting/willowTree4.png" width="65"></td><td><img src="images/woodcutting/mapleTree4.png" width="65"></td> \
  10823. <td><img src="images/woodcutting/stardustTree4.png" width="65"></td><td><img src="images/woodcutting/strangeLeafTree4.png" width="65"></td> \
  10824. <td><img src="images/woodcutting/ancientTree4.png" width="65"></td> \
  10825. <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> \
  10826. <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> \
  10827. <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> \
  10828. </table>';
  10829.  
  10830. getSkillDialog.insertBefore(div, document.getElementById('dialgoue-axe-upgrade-with'));
  10831. }
  10832. function bonemealBinCalc(){
  10833. var stripedCrystalLeafSeeds = ['stripedCrystalLeafSeeds', 100];
  10834. var ancientTreeSeeds = ['ancientTreeSeeds', 100];
  10835. var strangeLeafTreeSeeds = ['strangeLeafTreeSeeds', 65];
  10836. var stardustTreeSeeds = ['stardustTreeSeeds', 50];
  10837. var crystalLeafSeeds = ['crystalLeafSeeds', 50];
  10838. var mapleTreeSeeds = ['mapleTreeSeeds', 30];
  10839. var willowTreeSeeds = ['willowTreeSeeds', 15];
  10840. var goldLeafSeeds = ['goldLeafSeeds', 10];
  10841. var stardustSeeds = ['stardustSeeds', 5];
  10842.  
  10843. var stripedCrystalBM = getGameValue(stripedCrystalLeafSeeds[0]) * stripedCrystalLeafSeeds[1];
  10844. var ancientTreeBM = getGameValue(ancientTreeSeeds[0]) * ancientTreeSeeds[1];
  10845. var strangeLeafTreeBM = getGameValue(strangeLeafTreeSeeds[0]) * strangeLeafTreeSeeds[1];
  10846. var stardustTreeBM = getGameValue(stardustTreeSeeds[0]) * stardustTreeSeeds[1];
  10847. var crystalLeafBM = getGameValue(crystalLeafSeeds[0]) * crystalLeafSeeds[1];
  10848. var mapleTreeBM = getGameValue(mapleTreeSeeds[0]) * mapleTreeSeeds[1];
  10849. var willowTreeBM = getGameValue(willowTreeSeeds[0]) * willowTreeSeeds[1];
  10850. var goldLeafBM = getGameValue(goldLeafSeeds[0]) * goldLeafSeeds[1];
  10851. var stardustBM = getGameValue(stardustSeeds[0]) * stardustSeeds[1];
  10852.  
  10853. var totalBM = stripedCrystalBM+ancientTreeBM+strangeLeafTreeBM+stardustTreeBM +crystalLeafBM +mapleTreeBM +willowTreeBM +goldLeafBM +stardustBM;
  10854. $("#bonemeal-need").text(format.number(totalBM));
  10855. }
  10856. function bonemealBin(){
  10857. $('#bonemeal-bones-input').css('width', "51px");
  10858. var getSkillDialog = document.getElementById('dialogue-bonemeal');
  10859. var div = document.createElement("div");
  10860. div.className = 'basic-smallbox';
  10861. div.innerHTML = '<div class="smallbox-fix-lines"><b>You will need <x id="bonemeal-need" style="color: blue"></x> bonemeal to grow all of your seeds</b><br /> \
  10862. Bone Amulet (Skeleton in Caves) or Bone Ring (Vendor) x2 bones in lootbags<br /> \
  10863. Green Bonemeal Bin Orb +1 bonemeal for every bonemeal item<br /></div> \
  10864. ';
  10865. $(div).insertAfter("#dialogue-bonemeal h2:first");
  10866. $("#dialogue-bonemeal h2:first").css("display", "none");
  10867. var boneSource = " <b>Source: </b><img title='Treasure Chest' src='images/treasureChest.png' class='image-icon-50'> \
  10868. <img title='Chicken' src='images/hero/npc/1.png' class='image-icon-50'> \
  10869. <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'> \
  10870. <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'> \
  10871. <img title='Vendor' src='images/vendor.png' class='image-icon-50'> \
  10872. ";
  10873. var ashesSource = " <b>Source: </b><img title='Green Treasure Chest' src='images/greenTreasureChest.png' class='image-icon-50'> \
  10874. <img title='Golem' src='images/hero/npc/10.png' class='image-icon-50'> \
  10875. <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'> \
  10876. ";
  10877. var iceBonesSource = " <b>Source: </b><img title='Lizard' src='images/hero/npc/13.png' class='image-icon-50'> \
  10878. <img title='Ice Bird' src='images/hero/npc/15.png' class='image-icon-50'> \
  10879. ";
  10880. var moonBonesSource = " <b>Source: </b><img title='Giant' src='images/hero/npc/19.png' class='image-icon-50'> \
  10881. <img title='Five Eyed' src='images/hero/npc/20.png' class='image-icon-50'> \
  10882. ";
  10883. var darkBonesSource = " <b>Source: </b><img title='Dark Mage' src='images/hero/npc/22.png' class='image-icon-50'> \
  10884. <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'> \
  10885. ";
  10886. $("#bonemeal-bones-box").append(boneSource);
  10887. $("#bonemeal-ashes-box").append(ashesSource);
  10888. $("#bonemeal-iceBones-box").append(iceBonesSource);
  10889. $("#bonemeal-moonBones-box").append(moonBonesSource);
  10890. $("#bonemeal-darkBones-box").append(darkBonesSource);
  10891. }
  10892. function brewing(){
  10893. var getSkillDialog = document.getElementById("dialogue-id-brewingkit");
  10894. 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' : '';
  10895. var title = "<h1 class='container-title'>Brewing Calculator</h1>";
  10896. var closeButton= '<br/><input type="button" value="Close"/>';
  10897. 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> \
  10898. to drink all of current potions</b> <br/>(click on headers to sort the table)<br/> \
  10899. 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/> \
  10900. <table id="brewing-calc-table" border="1" style="text-align:center"><thead><tr><th>Potion</th><th class="sortable ascending-sort number"> \
  10901. Current</th><th class="sortable ascending-sort number">Brewable</th><th class="sortable ascending-sort number">Total</th> \
  10902. <th class="sortable ascending-sort number"> \
  10903. Current XP</th><th class="sortable ascending-sort number">Brewable XP</th><th class="sortable ascending-sort number">Total XP</th> \
  10904. <th class="sortable ascending-sort time">Current Time</th></tr></thead><tbody></tbody></table></div>`;
  10905.  
  10906. $(getSkillDialog).append(title);
  10907. $(getSkillDialog).append(note);
  10908. $(getSkillDialog).append(div);
  10909. $(getSkillDialog).append(closeButton);
  10910. var allPots = ['stardust', 'tree', 'seed', 'smelting', 'oil', 'bar','supersd', 'cd', 'farmingspeed', 'stargem', 'mana', 'superoil',
  10911. 'supertree', 'supercombatcd', 'supercompost', 'supermana', 'dark', 'oxygen', 'crit', 'lootbag'];
  10912. var image = ['stardust', 'tree', 'seed', 'smelting', 'oil', 'bar','superStardust', 'combatCooldown', 'farmingSpeed', 'stargem', 'mana', 'superOil',
  10913. 'superTree', 'superCombatCooldown', 'superCompost', 'superMana', 'dark', 'oxygen', 'criticalStrike', 'lootBag'];
  10914.  
  10915. for (let i = 0; i < allPots.length; i++){
  10916. var potRow = `<tr><td><img src='images/`+image[i]+`Potion.png' class="image-icon-40"></td><td id ="`+allPots[i]+`-current"> \
  10917. </td><td id ="`+allPots[i]+`-brewable"></td><td id ="`+allPots[i]+`-total"></td><td id ="`+allPots[i]+`-current-xp"> \
  10918. </td><td id ="`+allPots[i]+`-brewable-xp"></td><td id ="`+allPots[i]+`-total-xp"></td> \
  10919. <td id ="`+allPots[i]+`-current-time"></td></tr>`;
  10920. $("#brewing-calc-table tbody").append(potRow);
  10921. }
  10922. }
  10923. function findMinPot(){
  10924. var arrPots = [];
  10925. for (let i = 0; i < arguments.length; i++) {
  10926. if (i % 2 == 0){
  10927. var x = arguments[i]/arguments[i+1];
  10928. arrPots.push(x);
  10929. }else {
  10930. continue;
  10931. }
  10932. }
  10933. var getMin = Math.min(...arrPots);
  10934. var min = Math.floor(getMin);
  10935. return min;
  10936. }
  10937. function formatRound(value){
  10938. return format.number(Math.floor(value));
  10939.  
  10940. }
  10941. function fullTime(timer)
  10942. {
  10943.  
  10944. if (typeof timer === 'string')
  10945. {
  10946. timer = parseInt(timer, 10);
  10947. }
  10948. timer = Math.max(timer, 0);
  10949. var days = Math.floor(timer / 86400);
  10950. var hours = Math.floor((timer % 86400) / 3600);
  10951. var minutes = Math.floor((timer % 3600) / 60);
  10952. var seconds = timer % 60;
  10953. return zeroPadLeft(days) + 'd ' + zeroPadLeft(hours) + ':' + zeroPadLeft(minutes) + ':' + zeroPadLeft(seconds) ;
  10954. }
  10955. function removeComma(string){
  10956. return parseInt(string.replace(/,/g,''), 10);
  10957. }
  10958. function convertTime(time){
  10959. return new Date("2018/01/01 "+ time.replace(/[0-9][0-9]d\s/g,'')).getTime() +
  10960. parseInt(time.replace(/d\s[0-2]?[0-3]:[0-5][0-9]:[0-5][0-9]/g,''), 10) * 86400000;
  10961. }
  10962.  
  10963. function brewingCalc(){
  10964.  
  10965. var donorXPBoost = (win.donorXpBoost > win.currentTimeMillis) ? 1.1 : 1;
  10966. var bonusDuration = 1;
  10967. var bonusAch = 0;
  10968. var bonusLevel = 0;
  10969. var brewingLevel = win.getLevel(win.brewingXp);
  10970. if (achBrewingHardCompleted){
  10971. bonusAch = 15;
  10972. }else if (achBrewingMediumCompleted){
  10973. bonusAch = 10;
  10974. }else if (achBrewingEasyCompleted){
  10975. bonusAch = 5;
  10976. }else{
  10977. bonusAch = 0;
  10978. }
  10979. for(let i = 0; i <= 100; i += 5){
  10980. if (brewingLevel >= i && brewingLevel < (i+5)){
  10981. bonusLevel = i/5;
  10982. }
  10983. }
  10984. bonusDuration = bonusDuration * (1 + (bonusAch+bonusLevel)/100);
  10985.  
  10986. var sdBrewable = findMinPot(dottedGreenLeaf, 1, redMushroom, 25);
  10987. var treeBrewable = findMinPot(dottedGreenLeaf, 2, redMushroom, 15);
  10988. var seedBrewable = findMinPot(dottedGreenLeaf, 1, redMushroom, 30);
  10989. var smeltingBrewable = findMinPot(dottedGreenLeaf, 3);
  10990. var oilBrewable = findMinPot(greenLeaf, 1, redMushroom, 50);
  10991. var barBrewable = findMinPot(greenLeaf, 3, blewitMushroom, 50);
  10992. var supersdBrewable = findMinPot(limeLeaf, 5, snapegrass, 50);
  10993. var cdBrewable = findMinPot(strangeBlueLeaf, 1, greenLeaf, 5);
  10994. var farmingspeedBrewable = findMinPot(redMushroom, 100, blewitMushroom, 50, snapegrass, 10);
  10995. var stargemBrewable = findMinPot(goldLeaf, 1, blewitMushroom, 100);
  10996. var manaBrewable = findMinPot(goldLeaf, 1, limeLeaf, 10, strangePurpleLeaf, 1);
  10997. var superoilBrewable = findMinPot(goldLeaf, 3, redMushroom, 150);
  10998. var supertreeBrewable = findMinPot(goldLeaf, 3, blewitMushroom, 50);
  10999. var supercombatcdBrewable = findMinPot(strangeBlueLeaf, 4, greenLeaf, 20);
  11000. var supercompostBrewable = findMinPot(crystalLeaf, 5, redMushroom, 200, blewitMushroom, 100, snapegrass, 50);
  11001. var supermanaBrewable = findMinPot(crystalLeaf, 5, limeLeaf, 25, strangePurpleLeaf, 5);
  11002. var darkBrewable = findMinPot(limeLeaf, 25, goldLeaf, 10, darkMushroomLair, 10);
  11003. var oxygenBrewable = findMinPot(greenLeaf, 100, limeLeaf, 50, goldLeaf, 20, crystalLeaf, 10, strangePinkLeaf, 1);
  11004. var critBrewable = findMinPot(crystalLeaf, 10, stripedCrystalLeaf, 1, strangeBlueLeaf, 5);
  11005. var lootbagBrewable = findMinPot(crystalLeaf, 10, stripedCrystalLeaf, 2, goldLeaf, 15, strangePurpleLeaf, 1);
  11006.  
  11007. var stardust = {"current" : win.stardustPotion, "brewable" : sdBrewable, "xp": 50, "time": 5};
  11008. var tree = {"current" : win.treePotion, "brewable" : treeBrewable, "xp": 70, "time": 10};
  11009. var seed = {"current" : win.seedPotion, "brewable" : seedBrewable, "xp": 75, "time": 30};
  11010. var smelting = {"current" : win.smeltingPotion, "brewable" : smeltingBrewable, "xp": 200, "time": 30};
  11011. var oil = {"current" : win.oilPotion, "brewable" : oilBrewable, "xp": 210, "time": 15};
  11012. var bar = {"current" : win.barPotion, "brewable" : barBrewable, "xp": 380, "time": 30};
  11013. var supersd = {"current" : win.superStardustPotion, "brewable" : supersdBrewable, "xp": 480, "time": 5};
  11014. var cd = {"current" : win.combatCooldownPotion, "brewable" : cdBrewable, "xp": 555, "time": 0};
  11015. var farmingspeed = {"current" : win.farmingSpeedPotion, "brewable" : farmingspeedBrewable, "xp": 900, "time": 30};
  11016. var stargem = {"current" : win.stargemPotion, "brewable" : stargemBrewable, "xp": 1000, "time": 0};
  11017. var mana = {"current" : win.manaPotion, "brewable" : manaBrewable, "xp": 1250, "time": 1};
  11018. var superoil = {"current" : win.superOilPotion, "brewable" : superoilBrewable, "xp": 2200, "time": 15};
  11019. var supertree = {"current" : win.superTreePotion, "brewable" : supertreeBrewable, "xp": 2350, "time": 30};
  11020. var supercombatcd = {"current" : win.superCombatCooldownPotion, "brewable" : supercombatcdBrewable, "xp": 2550, "time": 0};
  11021. var supercompost = {"current" : win.superCompostPotion, "brewable" : supercompostBrewable, "xp": 4550, "time": 0};
  11022. var supermana = {"current" : win.superManaPotion, "brewable" : supermanaBrewable, "xp": 5000, "time": 1};
  11023. var dark = {"current" : win.darkPotion, "brewable" : darkBrewable, "xp": 6000, "time": 1440};
  11024. var oxygen = {"current" : win.oxygenPotion, "brewable" : oxygenBrewable, "xp": 6650, "time": 0};
  11025. var crit = {"current" : win.criticalStrikePotion, "brewable" : critBrewable, "xp": 7000, "time": 1};
  11026. var lootbag = {"current" : win.lootBagPotion, "brewable" : lootbagBrewable, "xp": 15000, "time": 0};
  11027.  
  11028. var allPots = [stardust, tree, seed, smelting, oil, bar, supersd, cd, farmingspeed, stargem, mana, superoil,
  11029. supertree, supercombatcd, supercompost, supermana, dark, oxygen, crit, lootbag];
  11030. var allPotName = ['stardust', 'tree', 'seed', 'smelting', 'oil', 'bar','supersd', 'cd', 'farmingspeed', 'stargem', 'mana', 'superoil',
  11031. 'supertree', 'supercombatcd', 'supercompost', 'supermana', 'dark', 'oxygen', 'crit', 'lootbag'];
  11032.  
  11033. var durationList = [];
  11034.  
  11035. for (let i = 0; i < allPots.length; i++){
  11036. durationList.push(allPots[i].current * Math.floor(allPots[i].time * 60 * bonusDuration));
  11037.  
  11038. $('#'+allPotName[i]+'-current').html(formatRound(allPots[i].current));
  11039. $('#'+allPotName[i]+'-brewable').html(formatRound(allPots[i].brewable));
  11040. $('#'+allPotName[i]+'-total').html(formatRound(allPots[i].current + allPots[i].brewable));
  11041. $('#'+allPotName[i]+'-current-xp').html(formatRound(allPots[i].current * allPots[i].xp * donorXPBoost));
  11042. $('#'+allPotName[i]+'-brewable-xp').html(formatRound(allPots[i].brewable * allPots[i].xp * 2* donorXPBoost));
  11043. $('#'+allPotName[i]+'-total-xp').html(formatRound(allPots[i].current * allPots[i].xp* donorXPBoost +
  11044. allPots[i].brewable * allPots[i].xp * 2* donorXPBoost));
  11045. $('#'+allPotName[i]+'-current-time').html(fullTime(allPots[i].current * Math.floor(allPots[i].time * 60 * bonusDuration)));
  11046. }
  11047.  
  11048. $('#total-current-pot-xp').html(format.timer(Math.max(...durationList)));
  11049.  
  11050. }
  11051. function orbs(){
  11052. var getSkillDialog = document.getElementById("dialogue-id-orbs-tracking");
  11053. var title = "<h1 class='container-title'>Orbs tracking status</h1>";
  11054. var closeButton= '<br/><input type="button" value="Close"/>';
  11055. var blueOrbBox = `<br/><div class='basic-smallbox'> \
  11056. <table id="blue-orbs-table" style="text-align:center"><tr></tr><tr></tr></table></div>`;
  11057. var greenOrbBox = `<br/><div class='basic-smallbox'> \
  11058. <table id="green-orbs-table" style="text-align:center"><tr></tr><tr></tr></table></div>`;
  11059. var redOrbBox = `<br/><div class='basic-smallbox'> \
  11060. <table id="red-orbs-table" style="text-align:center"><tr></tr><tr></tr></table></div>`;
  11061. $(getSkillDialog).append(title);
  11062. $(getSkillDialog).append(blueOrbBox);
  11063. $(getSkillDialog).append(greenOrbBox);
  11064. $(getSkillDialog).append(redOrbBox);
  11065. $(getSkillDialog).append(closeButton);
  11066.  
  11067. var statusNo = "<td><img src='images/icons/x.png' class='image-icon-20'></td>";
  11068. var statusYes = "<td><img src='images/icons/check.png' class='image-icon-20'></td>";
  11069.  
  11070. var blueOrbs = ["FishingRod", "Shovel", "Axe", "Rake", "Trowel", "Pickaxe", "OilPipe", "Hammer", "Chisel", "Meditation"];
  11071. 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",
  11072. "10% chance of getting seeds back on harvest", "10% chance of getting food seeds back on harvest", "Ores will grant twice the XP \
  11073. 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 \
  11074. crystals", "Meditate twice as fast"];
  11075. for (let i = 0; i < blueOrbs.length; i++){
  11076. var orbRow1 = "<td><img title='"+blueTitles[i]+"' src='images/blue"+blueOrbs[i]+"Orb.png' class='image-icon-50'></td>";
  11077. $("#blue-orbs-table tr:first").append(orbRow1);
  11078. $("#blue-orbs-table tr:eq(1)").append((getGameValue("boundBlue"+blueOrbs[i]+"Orb")) ? statusYes : statusNo);
  11079. }
  11080. var greenOrbs = ["OilFactory", "Combat", "BrewingKit", "Bow", "BonemealBin", "Rocket", "OilStorage", "EmpoweredRock"];
  11081. var greenTitles = ["Doubles your oil income for each factory worker", "Increases your attack, accuracy, defence and magic by 1 permanently",
  11082. "Doubles the chances of getting two potions instead of one from the brewing kit", "50% chance to save an arrow every attack",
  11083. "+1 bonemeal on every bone", "Allows your rocket to travel to mars", "Doubles oil capacity on every oil \
  11084. storage", "Get 20% stardust back each time you use an empowered rock"];
  11085. for (let i = 0; i < greenOrbs.length; i++){
  11086. var orbRow2 = "<td><img title='"+greenTitles[i]+"' src='images/green"+greenOrbs[i]+"Orb.png' class='image-icon-50'></td>";
  11087. $("#green-orbs-table tr:first").append(orbRow2);
  11088. $("#green-orbs-table tr:eq(1)").append((getGameValue("boundGreen"+greenOrbs[i]+"Orb")) ? statusYes : statusNo);
  11089. }
  11090. var redOrbs = ["MagicWand", "CharcoalFactory", "ManaStar", "CombatLoot", "Axe", "FishingBait", "Rocket"];
  11091. var redTitles = ["Double damage on all magic spells", "Doubles oil income from the charcoal factory and uses much less charcoal \
  11092. ", "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 \
  11093. you to convert a fully grown tree into a shiny one every 72h", "Increases efficiency of bait on all boats", "Allows your rocket \
  11094. travelling into intesteller space to collect space dust."];
  11095. for (let i = 0; i < redOrbs.length; i++){
  11096. var orbRow3 = "<td><img title='"+redTitles[i]+"' src='images/red"+redOrbs[i]+"Orb.png' class='image-icon-50'></td>";
  11097. $("#red-orbs-table tr:first").append(orbRow3);
  11098. $("#red-orbs-table tr:eq(1)").append((getGameValue("boundRed"+redOrbs[i]+"Orb")) ? statusYes : statusNo);
  11099. }
  11100. }
  11101. function orbsCalc(){
  11102. var blueOrbs = ["FishingRod", "Shovel", "Axe", "Rake", "Trowel", "Pickaxe", "OilPipe", "Hammer", "Chisel", "Meditation"];
  11103. var greenOrbs = ["OilFactory", "Combat", "BrewingKit", "Bow", "BonemealBin", "Rocket", "OilStorage", "EmpoweredRock"];
  11104. var redOrbs = ["MagicWand", "CharcoalFactory", "ManaStar", "CombatLoot", "Axe", "FishingBait", "Rocket"];
  11105. var statusNo = "<img src='images/icons/x.png' class='image-icon-20'>";
  11106. var statusYes = "<img src='images/icons/check.png' class='image-icon-20'>";
  11107.  
  11108. for (let i = 0; i < blueOrbs.length; i++){
  11109. $("#blue-orbs-table tr:eq(1) td:eq("+i+")").html((getGameValue("boundBlue"+blueOrbs[i]+"Orb")) ? statusYes : statusNo);
  11110. }
  11111. for (let i = 0; i < greenOrbs.length; i++){
  11112. $("#green-orbs-table tr:eq(1) td:eq("+i+")").html((getGameValue("boundGreen"+greenOrbs[i]+"Orb")) ? statusYes : statusNo);
  11113. }
  11114. for (let i = 0; i < redOrbs.length; i++){
  11115. $("#red-orbs-table tr:eq(1) td:eq("+i+")").html((getGameValue("boundRed"+redOrbs[i]+"Orb")) ? statusYes : statusNo);
  11116. }
  11117.  
  11118. }
  11119. function levelDialog(){
  11120. var getDialog = $("#level-table-dialog");
  11121. var title = `<h1 class='container-title'>XP/level calculator</h1>`;
  11122. var box1 = `<br/><div class='basic-smallbox' style="line-height: 1.7;">Calculate the XP needed to upgrade <br/>
  11123. one of your skills<br/><table><tr><td><b>Target level: </b></td><td><input type="number" value="1" \
  11124. id="input-level-calc" size="4" min="1" max="100" style="width: 47px;"></td></tr> \
  11125. <tr><td><b>Current level: </b></td><td><input type="number" value="1" id="input-current-level-calc" \
  11126. size="4" min="1" max="100" style="width: 47px;"></td></tr></table></div>`;
  11127. 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> \
  11128. </tr><tr><td><b>Needed XP: </b></td><td><span id="output-needed-xp-calc" ></span></td></tr></table></div>`;
  11129.  
  11130. var closeButton= '<br/><input type="button" value="Close"/>';
  11131. getDialog.append(title);
  11132. getDialog.append(box1);
  11133. getDialog.append(box2);
  11134. getDialog.append(closeButton);
  11135. }
  11136. function levelCalc(){
  11137. var levelVal = $('#input-level-calc').val();
  11138. var XP = (levelVal > 100) ? Number.NaN : Math.pow(levelVal, 3+(levelVal/200));
  11139. XP = Math.floor(XP);
  11140. var currentLevel = $('#input-current-level-calc').val();
  11141. var currentXP = (currentLevel > 100) ? Number.NaN : Math.pow(currentLevel, 3+(currentLevel/200));
  11142. var needXP = XP - currentXP;
  11143. needXP = Math.floor(needXP);
  11144. $('#output-xp-calc').html(format.number(XP));
  11145. $('#output-needed-xp-calc').html(format.number(needXP));
  11146. }
  11147. function fightDialog(){
  11148. $("#dialogue-fight table tr:eq(0)").append("<th>Avg XP/energy</th><th>Avg XP/minute</th>");
  11149. $("#dialogue-fight table tr:eq(1)").append("<td>0.8</td><td>2.67</td>");
  11150. $("#dialogue-fight table tr:eq(2)").append("<td style='background-color: yellow'>1.6</td><td>5.33</td>");
  11151. $("#dialogue-fight table tr:eq(3)").append("<td style='background-color: #e4bf91'>1.23</td><td>20.56</td>");
  11152. $("#dialogue-fight table tr:eq(4)").append("<td style='background-color: #A9A9A9'>1.43</td><td>35.69</td>");
  11153. $("#dialogue-fight table tr:eq(5)").append("<td>0.82</td><td>31.85</td>");
  11154. $("#dialogue-fight table tr:eq(6)").append("<td>0.92</td><td style='background-color: #A9A9A9'>57.78</td>");
  11155. $("#dialogue-fight table tr:eq(7)").append("<td>0.41</td><td style='background-color: #e4bf91'>55.22</td>");
  11156. $("#dialogue-fight table tr:eq(8)").append("<td>0.41</td><td style='background-color: #e4bf91'>55.22</td>");
  11157. $("#dialogue-fight table tr:eq(9)").append("<td>0.37</td><td style='background-color: yellow'>76.04</td>");
  11158. $("#dialogue-fight table tr:eq(10)").append("<td>0.37</td><td style='background-color: yellow'>76.04</td>");
  11159. $("#dialogue-fight table tr:eq(11) td:first").attr("colspan", 7);
  11160. }
  11161. function fishingBait(){
  11162. var getSkillDialog = document.getElementById("dialogue-id-fishingbait-calc");
  11163. var title = "<h1 class='container-title'>Fishing Bait Calculator</h1>";
  11164. var closeButton= '<br/><input type="button" value="Close"/>';
  11165. 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/> \
  11166. <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>`;
  11167.  
  11168. $(getSkillDialog).append(title);
  11169. $(getSkillDialog).append(baitTable);
  11170. $(getSkillDialog).append(closeButton);
  11171.  
  11172. var areaList = {name : ["Fields", "Forests", "Caves", "Volcano", "Northern Fields", "Haunted Mansion", "Moon", "Dark Forest"],
  11173. baitPerhour: [1, 2.88, 1.7, 0.92, 0.61, 2, 0.71, 2.05],
  11174. energyPerbait: [200, 69, 588, 1620, 3825, 1875, 2000, 3902]};
  11175. for (let i = 0; i < areaList.name.length; i++){
  11176. var row = "<tr><td>"+areaList.name[i]+"</td><td>"+areaList.baitPerhour[i]+"</td><td>"+format.number(areaList.energyPerbait[i])+"</td></tr>";
  11177. $("#fishing-bait-table").append(row);
  11178. }
  11179. $("#fishing-bait-table tr:eq(2) td:eq(1)").css("background-color", "yellow");
  11180. $("#fishing-bait-table tr:eq(2) td:eq(2)").css("background-color", "yellow");
  11181. $("#fishing-bait-table tr:eq(8) td:eq(1)").css("background-color", "silver");
  11182. $("#fishing-bait-table tr:eq(1) td:eq(2)").css("background-color", "silver");
  11183. $("#fishing-bait-table tr:eq(6) td:eq(1)").css("background-color", "#e4bf91");
  11184. $("#fishing-bait-table tr:eq(3) td:eq(2)").css("background-color", "#e4bf91");
  11185. }
  11186.  
  11187. function initFishingBaitCalc(){
  11188. var box = $("#item-box-fishingBait");
  11189. var dialog = document.createElement('dialog');
  11190. dialog.id = 'dialogue-id-fishingbait-calc';
  11191. document.body.appendChild(dialog);
  11192.  
  11193. box.click(function(){
  11194. $(dialog).dialog(
  11195. {
  11196. title: 'Fishing Bait',
  11197. height: 'auto',
  11198. width: 'auto'
  11199. });
  11200. });
  11201. fishingBait();
  11202. $("#dialogue-id-fishingbait-calc :button").click(function(){
  11203. $(this).closest(".ui-dialog-content").dialog("close");
  11204. });
  11205. }
  11206. function initlevelCalc(){
  11207.  
  11208. $("<tr><td colspan='3'><span id='level-table-btn' class='market-browse-button' style='font-size:30px;font-weight:bold;color: \
  11209. #f57a90;'><img src='images/icons/skills.png' class='image-icon-50'>XP/level calculator</span></td></tr>").insertBefore("#view-full-profile-btn");
  11210.  
  11211. var btn = $("#level-table-btn");
  11212. var dialog = document.createElement('dialog');
  11213. dialog.id = 'level-table-dialog';
  11214. document.body.appendChild(dialog);
  11215. btn.click(function(){
  11216. $(dialog).dialog(
  11217. {
  11218. title: 'XP and level',
  11219. height: 'auto',
  11220. width: 'auto'
  11221. });
  11222. });
  11223. levelDialog();
  11224. var getDialog = $('#level-table-dialog');
  11225. $(":button", getDialog).click(function(){
  11226. $(this).closest(".ui-dialog-content").dialog("close");
  11227. });
  11228. document.getElementById("input-level-calc").addEventListener("keyup", function(){
  11229. levelCalc();
  11230. });
  11231. document.getElementById("input-level-calc").addEventListener("mouseup", function(){
  11232. levelCalc();
  11233. });
  11234. document.getElementById("input-current-level-calc").addEventListener("keyup", function(){
  11235. levelCalc();
  11236. });
  11237. document.getElementById("input-current-level-calc").addEventListener("mouseup", function(){
  11238. levelCalc();
  11239. });
  11240. }
  11241. function initOrbsCalc(){
  11242. var box = $("#item-box-pirate");
  11243. var dialog = document.createElement('dialog');
  11244. dialog.id = 'dialogue-id-orbs-tracking';
  11245. document.body.appendChild(dialog);
  11246.  
  11247. box.click(function(){
  11248. $(dialog).dialog(
  11249. {
  11250. title: 'Orb tracker',
  11251. height: 'auto',
  11252. width: 'auto'
  11253. });
  11254. orbsCalc();
  11255. });
  11256. orbs();
  11257. $("#dialogue-id-orbs-tracking :button").click(function(){
  11258. $(this).closest(".ui-dialog-content").dialog("close");
  11259. });
  11260. }
  11261. function initBrewingCalc(){
  11262. var brewingKit = $("#item-box-boundBrewingKit");
  11263. if(!boundBrewingKit){
  11264. brewingKit.css("display", "inline-block");
  11265. }
  11266. var dialog = document.createElement('dialog');
  11267. dialog.id = 'dialogue-id-brewingkit';
  11268. document.body.appendChild(dialog);
  11269.  
  11270. brewingKit.click(function(){
  11271. $(dialog).dialog(
  11272. {
  11273. title: 'Brewing Kit',
  11274. height: 'auto',
  11275. width: 'auto'
  11276.  
  11277. });
  11278. brewingCalc();
  11279. });
  11280. brewing();
  11281.  
  11282.  
  11283. $("#dialogue-id-brewingkit :button").click(function(){
  11284. $(this).closest(".ui-dialog-content").dialog("close");
  11285. });
  11286.  
  11287. $(".sortable").click(function(){
  11288. var header = this;
  11289. var table = document.getElementById("brewing-calc-table");
  11290. var rows = table.rows, arr = [];
  11291. var col = $(this).index();
  11292. for (let i = 1; i < rows.length; i++) {
  11293. var cells = rows[i].cells;
  11294. arr[i] = [];
  11295. for (let j = 0; j < cells.length; j++) {
  11296. arr[i][j] = cells[j].innerHTML;
  11297. }
  11298. }
  11299.  
  11300. if($(this).hasClass('ascending-sort')){
  11301. $(this).removeClass('ascending-sort').addClass("descending-sort");
  11302. arr.sort(function(a, b){
  11303. if($(header).hasClass('number')){
  11304. return removeComma(a[col]) - removeComma(b[col]);
  11305. }else if($(header).hasClass('time')){
  11306. return convertTime(a[col]) - convertTime(b[col]);
  11307. }
  11308. });
  11309.  
  11310. } else if($(this).hasClass('descending-sort')){
  11311. $(this).removeClass('descending-sort').addClass("ascending-sort");
  11312. arr.sort(function(a, b){
  11313. if($(header).hasClass('number')){
  11314. return removeComma(b[col]) - removeComma(a[col]);
  11315. }else if($(header).hasClass('time')){
  11316. return convertTime(b[col]) - convertTime(a[col]);
  11317. }
  11318. });
  11319. }
  11320. for (let i = 1; i < rows.length; i++) {
  11321. rows[i].innerHTML = "<td>" + arr[i-1].join("</td><td>") + "</td>";
  11322. }
  11323.  
  11324. var allPots = ['stardust', 'tree', 'seed', 'smelting', 'oil', 'bar','supersd', 'cd', 'farmingspeed', 'stargem', 'mana', 'superoil',
  11325. 'supertree', 'supercombatcd', 'supercompost', 'supermana', 'dark', 'oxygen', 'crit', 'lootbag'];
  11326. var image = ['stardust', 'tree', 'seed', 'smelting', 'oil', 'bar','superStardust', 'combatCooldown', 'farmingSpeed', 'stargem', 'mana', 'superOil',
  11327. 'superTree', 'superCombatCooldown', 'superCompost', 'superMana', 'dark', 'oxygen', 'criticalStrike', 'lootBag'];
  11328. for (let i = 1; i <= allPots.length; i++){
  11329. var getImageName1 = $('#brewing-calc-table tr:eq('+i+') td:eq(0)').html();
  11330. var getImageName2 = getImageName1.substr(17);
  11331. var pot = getImageName2.slice(0, -34);
  11332.  
  11333. for (let img in image){
  11334. for (let x in allPots){
  11335. if (pot == image[img] && x == img){
  11336. pot = allPots[x];
  11337. }
  11338. }
  11339. }
  11340. $('#brewing-calc-table tr:eq('+i+') td:eq(1)').attr('id', pot+'-current');
  11341. $('#brewing-calc-table tr:eq('+i+') td:eq(2)').attr('id', pot+'-brewable');
  11342. $('#brewing-calc-table tr:eq('+i+') td:eq(3)').attr('id', pot+'-total');
  11343. $('#brewing-calc-table tr:eq('+i+') td:eq(4)').attr('id', pot+'-current-xp');
  11344. $('#brewing-calc-table tr:eq('+i+') td:eq(5)').attr('id', pot+'-brewable-xp');
  11345. $('#brewing-calc-table tr:eq('+i+') td:eq(6)').attr('id', pot+'-total-xp');
  11346. $('#brewing-calc-table tr:eq('+i+') td:eq(7)').attr('id', pot+'-current-time');
  11347. }
  11348. });
  11349. }
  11350. function initBonemealBinCalc(){
  11351. bonemealBin();
  11352. var _clicksBonemealBin = win.clicksBonemealBin;
  11353. win.clicksBonemealBin = function()
  11354. {
  11355. _clicksBonemealBin();
  11356. bonemealBinCalc();
  11357. };
  11358. }
  11359. function initMagicCalc()
  11360. {
  11361.  
  11362. var dialog = document.createElement('dialog');
  11363. dialog.id = 'dialogue-id-meditate';
  11364. document.body.appendChild(dialog);
  11365.  
  11366. var _clicksMeditate = win.clicksMeditate;
  11367. win.clicksMeditate = function()
  11368. {
  11369. //openDialogue('dialogue-id-1');
  11370. var height = 430;
  11371. var width = 370;
  11372. $(dialog).dialog(
  11373. {
  11374. title: 'Magic Meditation',
  11375. height: height,
  11376. width: width
  11377. });
  11378. };
  11379. magic();
  11380. $("#stone").click(function(){
  11381. magicCalcXP(1, this);
  11382. });
  11383. $("#moonstone").click(function(){
  11384. magicCalcXP(2, this);
  11385. });
  11386. $("#marsrock").click(function(){
  11387. magicCalcXP(3, this);
  11388. });
  11389. $("#promethium").click(function(){
  11390. magicCalcXP(4, this);
  11391. });
  11392. $("#runite").click(function(){
  11393. magicCalcXP(5, this);
  11394. });
  11395. $("#dialogue-id-meditate :button").click(function(){
  11396. $(this).closest(".ui-dialog-content").dialog("close");
  11397. });
  11398.  
  11399. function checkRock(){
  11400. var rock = [];
  11401. var getstone = document.getElementById('stone');
  11402. var getmoonstone = document.getElementById('moonstone');
  11403. var getmarsrock = document.getElementById('marsrock');
  11404. var getpromethium = document.getElementById('promethium');
  11405. var getrunite = document.getElementById('runite');
  11406.  
  11407. if (getstone.style.backgroundColor == 'red'){
  11408. rock[0] = 1;
  11409. rock[1] = getstone;
  11410. }else if (getmoonstone.style.backgroundColor == 'red'){
  11411. rock[0] = 2;
  11412. rock[1] = getmoonstone;
  11413. }else if (getmarsrock.style.backgroundColor == 'red'){
  11414. rock[0] = 3;
  11415. rock[1] = getmarsrock;
  11416. }else if (getpromethium.style.backgroundColor == 'red'){
  11417. rock[0] = 4;
  11418. rock[1] = getpromethium;
  11419. }else if (getrunite.style.backgroundColor == 'red'){
  11420. rock[0] = 5;
  11421. rock[1] = getrunite;
  11422. }
  11423. return rock;
  11424. }
  11425.  
  11426. document.getElementById("magic-level").addEventListener("keyup", function(){
  11427. magicCalcLevel(checkRock()[0], checkRock()[1]);
  11428. });
  11429. document.getElementById("magic-level").addEventListener("mouseup", function(){
  11430.  
  11431. magicCalcLevel(checkRock()[0], checkRock()[1]);
  11432. });
  11433.  
  11434. document.getElementById("input-empowered-amount").addEventListener("keyup", function(){
  11435. magicCalcXP(checkRock()[0], checkRock()[1]);
  11436. });
  11437. document.getElementById("input-empowered-amount").addEventListener("mouseup", function(){
  11438.  
  11439. magicCalcXP(checkRock()[0], checkRock()[1]);
  11440. });
  11441.  
  11442. }
  11443.  
  11444. function initWoodcuttingCalc(){
  11445. woodcutting();
  11446. var _clicksAxe = win.clicksAxe;
  11447. win.clicksAxe = function()
  11448. {
  11449. _clicksAxe();
  11450. woodcuttingCalc();
  11451. };
  11452. }
  11453.  
  11454. function initMiningCalc()
  11455. {
  11456. doubleSkills(mining);
  11457. document.getElementById("xp-gain-pickaxe-convert").addEventListener("DOMSubtreeModified", function(){
  11458. doubleCalcs(mining);
  11459. });
  11460. }
  11461.  
  11462. function initCraftingCalc()
  11463. {
  11464. doubleSkills(crafting);
  11465. document.getElementById("xp-gain-hammer-convert").addEventListener("DOMSubtreeModified", function(){
  11466. doubleCalcs(crafting);
  11467. });
  11468. }
  11469. function settingColorCalcs(){
  11470. var gradientColorLight = '#00ff37';
  11471. var gradientColorDark = '#065b00';
  11472. // crafting
  11473. var gemHammer = 'Empty';
  11474. if (boundEmptyHammer){
  11475. gemHammer = 'Empty';
  11476. }else if (boundSapphireHammer){
  11477. gemHammer = 'Sapphire';
  11478. }else if (boundEmeraldHammer){
  11479. gemHammer = 'Emerald';
  11480. }else if (boundRubyHammer){
  11481. gemHammer = 'Ruby';
  11482. }else if (boundDiamondHammer){
  11483. gemHammer = 'Diamond';
  11484. }
  11485. var boxHammer = $("#item-box-bound"+gemHammer+"Hammer");
  11486. boxHammer.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11487. boxHammer.hover(function(){
  11488. boxHammer.css("background", ""+gradientColorDark+"");
  11489. }, function(){
  11490. boxHammer.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11491. });
  11492. $("#default-item-img-tag-bound"+gemHammer+"Hammer").hover(function(){
  11493. boxHammer.css("background", ""+gradientColorDark+"");
  11494. }, function(){
  11495. boxHammer.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11496. });
  11497. // mining
  11498. var gemPickaxe = 'Empty';
  11499. if (boundEmptyPickaxe){
  11500. gemPickaxe = 'Empty';
  11501. }else if (boundSapphirePickaxe){
  11502. gemPickaxe = 'Sapphire';
  11503. }else if (boundEmeraldPickaxe){
  11504. gemPickaxe = 'Emerald';
  11505. }else if (boundRubyPickaxe){
  11506. gemPickaxe = 'Ruby';
  11507. }else if (boundDiamondPickaxe){
  11508. gemPickaxe = 'Diamond';
  11509. }
  11510. var boxPickaxe = $("#item-box-bound"+gemPickaxe+"Pickaxe");
  11511. boxPickaxe.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11512. boxPickaxe.hover(function(){
  11513. boxPickaxe.css("background", ""+gradientColorDark+"");
  11514. }, function(){
  11515. boxPickaxe.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11516. });
  11517. $("#default-item-img-tag-bound"+gemPickaxe+"Pickaxe").hover(function(){
  11518. boxPickaxe.css("background", ""+gradientColorDark+"");
  11519. }, function(){
  11520. boxPickaxe.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11521. });
  11522. // woodcutting
  11523. var gemAxe = 'Empty';
  11524. if (boundEmptyAxe){
  11525. gemAxe = 'Empty';
  11526. }else if (boundSapphireAxe){
  11527. gemAxe = 'Sapphire';
  11528. }else if (boundEmeraldAxe){
  11529. gemAxe = 'Emerald';
  11530. }else if (boundRubyAxe){
  11531. gemAxe = 'Ruby';
  11532. }else if (boundDiamondAxe){
  11533. gemAxe = 'Diamond';
  11534. }
  11535.  
  11536. var boxAxe = $("#item-box-bound"+gemAxe+"Axe");
  11537. boxAxe.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11538. boxAxe.hover(function(){
  11539. boxAxe.css("background", ""+gradientColorDark+"");
  11540. }, function(){
  11541. boxAxe.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11542. });
  11543. $("#default-item-img-tag-bound"+gemAxe+"Axe").hover(function(){
  11544. boxAxe.css("background", ""+gradientColorDark+"");
  11545. }, function(){
  11546. boxAxe.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11547. });
  11548. // magic
  11549. var meditateLevel = 0;
  11550. for (var i = 1; i <= 9; i++){
  11551. if (getGameValue("meditate"+i) === 1){
  11552. meditateLevel = i;
  11553. }
  11554. }
  11555. var boxMagic = $("#item-box-meditate"+meditateLevel);
  11556. boxMagic.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11557. boxMagic.hover(function(){
  11558. boxMagic.css("background", ""+gradientColorDark+"");
  11559. }, function(){
  11560. boxMagic.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11561. });
  11562. $("#default-item-img-tag-meditate"+meditateLevel).hover(function(){
  11563. boxMagic.css("background", ""+gradientColorDark+"");
  11564. }, function(){
  11565. boxMagic.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11566. });
  11567. // bonemealbin
  11568. var boxBin = $("#item-box-boundBonemealBin");
  11569. boxBin.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11570. boxBin.hover(function(){
  11571. boxBin.css("background", ""+gradientColorDark+"");
  11572. }, function(){
  11573. boxBin.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11574. });
  11575. $("#default-item-img-tag-boundBonemealBin").hover(function(){
  11576. boxBin.css("background", ""+gradientColorDark+"");
  11577. }, function(){
  11578. boxBin.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11579. });
  11580. var box2 = $("#item-box-boundFilledBonemealBin");
  11581. box2.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11582. box2.hover(function(){
  11583. box2.css("background", ""+gradientColorDark+"");
  11584. }, function(){
  11585. box2.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11586. });
  11587. $("#default-item-img-tag-boundFilledBonemealBin").hover(function(){
  11588. box2.css("background", ""+gradientColorDark+"");
  11589. }, function(){
  11590. box2.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11591. });
  11592. // brewingkit
  11593. var brewingKit = $("#item-box-boundBrewingKit");
  11594. brewingKit.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11595. brewingKit.hover(function(){
  11596. brewingKit.css("background", ""+gradientColorDark+"");
  11597. }, function(){
  11598. brewingKit.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11599. });
  11600. $("#default-item-img-tag-boundBrewingKit").hover(function(){
  11601. brewingKit.css("background", ""+gradientColorDark+"");
  11602. }, function(){
  11603. brewingKit.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11604. });
  11605. // orb pirate
  11606. var boxPirate = $("#item-box-pirate");
  11607. boxPirate.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11608. boxPirate.hover(function(){
  11609. boxPirate.css("background", ""+gradientColorDark+"");
  11610. }, function(){
  11611. $(this).css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11612. });
  11613. $("#default-item-img-tag-pirate").hover(function(){
  11614. boxPirate.css("background", ""+gradientColorDark+"");
  11615. }, function(){
  11616. boxPirate.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11617. });
  11618. // fishingbait
  11619.  
  11620. var boxBait = $("#item-box-fishingBait");
  11621. boxBait.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11622. boxBait.hover(function(){
  11623. boxBait.css("background", ""+gradientColorDark+"");
  11624. }, function(){
  11625. $(this).css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11626. });
  11627. $("#default-item-img-tag-fishingBait").hover(function(){
  11628. boxBait.css("background", ""+gradientColorDark+"");
  11629. }, function(){
  11630. boxBait.css("background", "linear-gradient("+gradientColorLight+", "+gradientColorDark+")");
  11631. });
  11632. }
  11633. function init(){
  11634. initFishingBaitCalc();
  11635. initMiningCalc();
  11636. initCraftingCalc();
  11637. initMagicCalc();
  11638. initWoodcuttingCalc();
  11639. initBonemealBinCalc();
  11640. initBrewingCalc();
  11641. initOrbsCalc();
  11642. initlevelCalc();
  11643. settingColorCalcs();
  11644. fightDialog();
  11645. }
  11646. calc.init = init;
  11647.  
  11648. })(calc || (calc = {}));
  11649.  
  11650. /**
  11651. * general features which doesn't really belong anywhere
  11652. */
  11653. var general;
  11654. (function (general)
  11655. {
  11656. general.name = 'general';
  11657. // disable the drink button for 3 seconds
  11658. var DRINK_DELAY = 3;
  11659.  
  11660. function getSentBoat()
  11661. {
  11662. for (var i = 0; i < BOAT_LIST.length; i++)
  11663. {
  11664. if (getGameValue(BOAT_LIST[i] + 'Timer') > 0)
  11665. {
  11666. return BOAT_LIST[i];
  11667. }
  11668. }
  11669. return null;
  11670. }
  11671.  
  11672. function checkBoat(boat)
  11673. {
  11674. var boatDialog = null;
  11675. var sendBtn = null;
  11676. var initiatedDialogs = document.querySelectorAll('div[role="dialog"]');
  11677. for (var i = 0; i < initiatedDialogs.length; i++)
  11678. {
  11679. var dialog = initiatedDialogs[i];
  11680. if (dialog.style.display !== 'none')
  11681. {
  11682. var btn = dialog.querySelector('input[type="button"][value="Send Boat"]');
  11683. if (btn)
  11684. {
  11685. sendBtn = btn;
  11686. boatDialog = dialog;
  11687. break;
  11688. }
  11689. }
  11690. }
  11691. if (!boatDialog || !sendBtn)
  11692. {
  11693. return;
  11694. }
  11695. var smallboxes = boatDialog.querySelectorAll('div.basic-smallbox');
  11696. var baitBox = smallboxes[0];
  11697. var runningBox = smallboxes[1];
  11698. if (smallboxes.length === 1)
  11699. {
  11700. runningBox = document.createElement('div');
  11701. runningBox.className = 'basic-smallbox';
  11702. runningBox.style.display = 'none';
  11703. var parent_1 = baitBox.parentElement;
  11704. var next = baitBox.nextElementSibling;
  11705. if (parent_1)
  11706. {
  11707. if (next)
  11708. {
  11709. parent_1.insertBefore(runningBox, next);
  11710. }
  11711. else
  11712. {
  11713. parent_1.appendChild(runningBox);
  11714. }
  11715. }
  11716. }
  11717. var sentBoat = getSentBoat();
  11718. baitBox.style.display = sentBoat !== null ? 'none' : '';
  11719. runningBox.style.display = sentBoat !== null ? '' : 'none';
  11720. // just in case Smitty changes this game mechanic somehow, don't disable the button:
  11721. // sendBtn.disabled = sentBoat !== null;
  11722.  
  11723. sendBtn.style.color = sentBoat !== null ? 'gray' : '';
  11724. win.$(boatDialog).on('dialogclose', function ()
  11725. {
  11726. if (sendBtn)
  11727. {
  11728. sendBtn.style.color = '';
  11729. }
  11730. });
  11731. if (sentBoat === boat)
  11732. {
  11733. runningBox.innerHTML = "<b>Returning in:</b> <span data-item-display=\"" + boat + "Timer\">" + format.timer(getGameValue(boat + 'Timer')) + "</span>";
  11734. }
  11735.  
  11736. else if (sentBoat !== null)
  11737. {
  11738. runningBox.innerHTML = "Wait for the other boat to return.";
  11739. }
  11740.  
  11741. else
  11742. {
  11743. var enoughBaitAndCoal = win.fishingBait >= win.fishingBaitCost(boat)
  11744. && (boat !== 'steamBoat' || win.charcoal >= 300);
  11745. baitBox.style.color = enoughBaitAndCoal ? '' : 'red';
  11746. }
  11747.  
  11748. }
  11749.  
  11750. function initBoatDialog()
  11751. {
  11752. var _clicksBoat = win.clicksBoat;
  11753. win.clicksBoat = function (boat)
  11754. {
  11755. _clicksBoat(boat);
  11756. checkBoat(boat);
  11757. };
  11758. var _doCommand = win.doCommand;
  11759. win.doCommand = function (data)
  11760. {
  11761. _doCommand(data);
  11762. if (data.startsWith('RUN_FUNC=SAIL_BOAT_WIND'))
  11763. {
  11764. checkBoat('sailBoat');
  11765. }
  11766. };
  11767. }
  11768. var potionDrinkEnable = null;
  11769. var POTION_ACTIVE_HTML = "<br>It's already active.";
  11770. function updateDialogEls(timerKey, dialog, close)
  11771. {
  11772. if (close === void 0)
  11773. {
  11774. close = false;
  11775. }
  11776. var timer = getGameValue(timerKey);
  11777. var showActive = settings.get(settings.KEY.usePotionWarning) && timer > 0 && !close;
  11778. var confirmText = document.getElementById('dialogue-confirm-text');
  11779. var br = confirmText && confirmText.nextElementSibling;
  11780. if (confirmText && br)
  11781. {
  11782. if (showActive)
  11783. {
  11784. confirmText.innerHTML += POTION_ACTIVE_HTML;
  11785. }
  11786. else
  11787. {
  11788. confirmText.innerHTML = confirmText.innerHTML.replace(POTION_ACTIVE_HTML, '');
  11789. }
  11790. br.style.display = showActive ? 'none' : '';
  11791. }
  11792. var confirmBtn = document.getElementById('dialogue-confirm-yes');
  11793. if (confirmBtn && showActive)
  11794. {
  11795. confirmBtn.disabled = true;
  11796. var i_1 = DRINK_DELAY;
  11797. var updateValue_1 = function ()
  11798. {
  11799. confirmBtn.value = 'Drink' + (i_1 > 0 ? ' (' + i_1 + ')' : '');
  11800. if (i_1 === 0)
  11801. {
  11802. potionDrinkEnable && potionDrinkEnable();
  11803. }
  11804. else
  11805. {
  11806. i_1--;
  11807. }
  11808. };
  11809. var countDownInterval_1;
  11810. var dialogClose_1 = function ()
  11811. {
  11812. return potionDrinkEnable && potionDrinkEnable();
  11813. };
  11814. potionDrinkEnable = function ()
  11815. {
  11816. potionDrinkEnable = null;
  11817. win.$(dialog).off('dialogclose', dialogClose_1);
  11818. countDownInterval_1 && clearInterval(countDownInterval_1);
  11819. confirmBtn.disabled = false;
  11820. confirmBtn.value = 'Drink';
  11821. };
  11822. updateValue_1();
  11823. countDownInterval_1 = setInterval(function ()
  11824. {
  11825. return updateValue_1();
  11826. }, 1e3);
  11827. win.$(dialog).on('dialogclose', dialogClose_1);
  11828. }
  11829. else if (!showActive)
  11830. {
  11831. potionDrinkEnable && potionDrinkEnable();
  11832. }
  11833. }
  11834.  
  11835. function checkPotionActive(potion)
  11836. {
  11837. var dialog = document.getElementById('dialogue-confirm');
  11838. var parent = dialog && dialog.parentElement;
  11839. if (!dialog || !parent || parent.style.display === 'none')
  11840. {
  11841. return;
  11842. }
  11843. var timerKey = potion + 'Timer';
  11844. updateDialogEls(timerKey, dialog);
  11845. var fn = observer.add(timerKey, function (key, oldValue, newValue)
  11846. {
  11847. if (oldValue < newValue && oldValue === 0
  11848. || oldValue > newValue && newValue === 0)
  11849. {
  11850. updateDialogEls(timerKey, dialog);
  11851. }
  11852. });
  11853. win.$(dialog).on('dialogclose', function ()
  11854. {
  11855. updateDialogEls(timerKey, dialog, true);
  11856. observer.remove(timerKey, fn);
  11857. });
  11858. }
  11859.  
  11860. function initPotionDialog()
  11861. {
  11862. var _confirmDialogue = win.confirmDialogue;
  11863. win.confirmDialogue = function (width, text, btn1Text, btn2Text, cmd)
  11864. {
  11865. potionDrinkEnable && potionDrinkEnable();
  11866. _confirmDialogue(width, text, btn1Text, btn2Text, cmd);
  11867. };
  11868. var _clicksPotion = win.clicksPotion;
  11869. win.clicksPotion = function (potion)
  11870. {
  11871. _clicksPotion(potion);
  11872. checkPotionActive(potion);
  11873. };
  11874. }
  11875. function init()
  11876. {
  11877. //initBoatDialog();
  11878. initPotionDialog();
  11879. }
  11880. general.init = init;
  11881. })(general || (general = {}));
  11882.  
  11883. /**
  11884. * init
  11885. */
  11886. var scriptInitialized = false;
  11887.  
  11888. function init()
  11889. {
  11890. console.info('[%s] "DH2 Fixed %s" up and running.', (new Date).toLocaleTimeString(), version);
  11891.  
  11892. scriptInitialized = true;
  11893. var initModules = [
  11894. settings
  11895. , notifications
  11896. , log
  11897. , gameEvents
  11898. , temporaryFixes
  11899. , crafting
  11900. , itemBoxes
  11901. , chat
  11902. , timer
  11903. , smelting
  11904. , fishingInfo
  11905. //, recipeTooltips
  11906. //, fixNumbers
  11907. , machineDialog
  11908. , amountInputs
  11909. , newTopbar
  11910. , styleTweaks
  11911. , notifBoxes
  11912. , market
  11913. , combat
  11914. , farming
  11915. , general
  11916. , calc
  11917. ];
  11918. for (var _i = 0, initModules_1 = initModules; _i < initModules_1.length; _i++)
  11919. {
  11920. var module = initModules_1[_i];
  11921. try
  11922. {
  11923. module.init();
  11924. }
  11925. catch (error)
  11926. {
  11927. console.error('Error during initialization in module "' + module.name + '":', error);
  11928. }
  11929. }
  11930. }
  11931. document.addEventListener('DOMContentLoaded', function ()
  11932. {
  11933. var oldValues = new Map();
  11934. var _doCommand = win.doCommand;
  11935. win.doCommand = function (data)
  11936. {
  11937. if (data.startsWith('REFRESH_ITEMS='))
  11938. {
  11939. oldValues = new Map();
  11940. for (var _i = 0, _a = win.jsItemArray; _i < _a.length; _i++)
  11941. {
  11942. var key = _a[_i];
  11943. oldValues.set(key, getGameValue(key));
  11944. }
  11945. _doCommand(data);
  11946. if (!scriptInitialized)
  11947. {
  11948. init();
  11949. }
  11950. return;
  11951. }
  11952. else if (!scriptInitialized)
  11953. {
  11954. if (data.startsWith('CHAT='))
  11955. {
  11956. var parts = data.substr(5).split('~');
  11957. return chat.newAddToChatBox(parts[0], parts[1], parts[2], parts[3], 0);
  11958. }
  11959. else if (data.startsWith('PM='))
  11960. {
  11961. return chat.newAddToChatBox(win.username, '0', '0', data.substr(3), 1);
  11962. }
  11963. }
  11964. var ret = commands.process(data);
  11965. if (ret === void 0)
  11966. {
  11967. ret = _doCommand(commands.formatData(data));
  11968. }
  11969. return ret;
  11970. };
  11971. var _refreshItemValues = win.refreshItemValues;
  11972. win.refreshItemValues = function (itemKeyList, firstLoad)
  11973. {
  11974. _refreshItemValues(itemKeyList, firstLoad);
  11975. for (var _i = 0, itemKeyList_2 = itemKeyList; _i < itemKeyList_2.length; _i++)
  11976. {
  11977. var key = itemKeyList_2[_i];
  11978. observer.notify(key, oldValues.get(key));
  11979. }
  11980. observer.notifyTick();
  11981. };
  11982. });
  11983.  
  11984. /**
  11985. * fix web socket errors
  11986. */
  11987. var main;
  11988. (function (main)
  11989. {
  11990. var WS_TIMEOUT_SEC = 30;
  11991. var WS_TIMEOUT_CODE = 3000;
  11992. var WS_OPEN_TIMEOUT_SEC = 2 * 60; // 2 minutes
  11993. // reload the page after 5 consecutive reconnect attempts without successfully opening the websocket once
  11994. var MAX_RECONNECTS = 5;
  11995.  
  11996. function webSocketLoaded(event)
  11997. {
  11998. if (win.webSocket == null)
  11999. {
  12000. //console.error('WebSocket instance not initialized!');
  12001. return;
  12002. }
  12003. // cache old event listener
  12004. var _onClose = win.webSocket.onclose;
  12005. var _onError = win.webSocket.onerror;
  12006. var _onMessage = win.webSocket.onmessage;
  12007. var _onOpen = win.webSocket.onopen;
  12008. var commandQueue = [];
  12009. var _cBytes = win.cBytes;
  12010. win.cBytes = function (command)
  12011. {
  12012. if (win.webSocket && win.webSocket.readyState === WebSocket.OPEN)
  12013. {
  12014. _cBytes(command);
  12015. }
  12016. else
  12017. {
  12018. commandQueue.push(command);
  12019. }
  12020. };
  12021. var pageLoaded = false;
  12022. var wsTimeout = null;
  12023. var reconnectAttempts = 0;
  12024.  
  12025. function onTimeout()
  12026. {
  12027. wsTimeout = null;
  12028. // renew the websocket
  12029. if (reconnectAttempts <= MAX_RECONNECTS)
  12030. {
  12031. win.webSocket = new WebSocket(win.SSL_ENABLED);
  12032. win.ignoreBytesTracker = Date.now();
  12033. initWSListener(win.webSocket);
  12034. reconnectAttempts++;
  12035. }
  12036. if (win.webSocket)
  12037. {
  12038. win.webSocket.close(WS_TIMEOUT_CODE, 'Connection timed out after ' + WS_TIMEOUT_SEC + ' seconds');
  12039. }
  12040. }
  12041.  
  12042. function updateWSTimeout()
  12043. {
  12044. if (wsTimeout)
  12045. {
  12046. win.clearTimeout(wsTimeout);
  12047. }
  12048. wsTimeout = win.setTimeout(onTimeout, WS_TIMEOUT_SEC * 1e3);
  12049. }
  12050. var messageQueue = [];
  12051.  
  12052. function onMessage(event)
  12053. {
  12054. if (pageLoaded)
  12055. {
  12056. updateWSTimeout();
  12057. return _onMessage.call(this, event);
  12058. }
  12059. else
  12060. {
  12061. messageQueue.push(event);
  12062. }
  12063. };
  12064. var wsOpenTimeout = null;
  12065.  
  12066. function onOpenTimeout()
  12067. {
  12068. wsOpenTimeout = null;
  12069. location.reload();
  12070. }
  12071.  
  12072. function onOpen(event)
  12073. {
  12074. reconnectAttempts = 0;
  12075. if (wsOpenTimeout)
  12076. {
  12077. win.clearTimeout(wsOpenTimeout);
  12078. wsOpenTimeout = null;
  12079. }
  12080. // do the handshake first
  12081. _onOpen.call(this, event);
  12082. commandQueue.forEach(function (command)
  12083. {
  12084. return win.cBytes(command);
  12085. });
  12086. }
  12087.  
  12088. function onError(event)
  12089. {
  12090. console.error('error in websocket:', event);
  12091. return _onError.call(this, event);
  12092. }
  12093.  
  12094. function onClose(event)
  12095. {
  12096. console.info('websocket closed:', event);
  12097. if (event.code !== WS_TIMEOUT_CODE || reconnectAttempts > MAX_RECONNECTS)
  12098. {
  12099. location.reload();
  12100. }
  12101. return _onClose.call(this, event);
  12102. }
  12103.  
  12104. function initWSListener(ws)
  12105. {
  12106. if (ws.readyState === WebSocket.CONNECTING)
  12107. {
  12108. wsOpenTimeout = win.setTimeout(onOpenTimeout, WS_OPEN_TIMEOUT_SEC * 1e3);
  12109. }
  12110. ws.onclose = onClose;
  12111. ws.onerror = onError;
  12112. ws.onmessage = onMessage;
  12113. ws.onopen = onOpen;
  12114. }
  12115. initWSListener(win.webSocket);
  12116. document.addEventListener('DOMContentLoaded', function ()
  12117. {
  12118. pageLoaded = true;
  12119. messageQueue.forEach(function (event)
  12120. {
  12121. return win.webSocket.onmessage(event);
  12122. });
  12123. });
  12124. }
  12125.  
  12126. function isScriptElement(el)
  12127. {
  12128. return el.nodeName === 'SCRIPT';
  12129. }
  12130.  
  12131. function isWebSocketScript(script)
  12132. {
  12133. return script.src.includes('socket.js');
  12134. }
  12135. var found = false;
  12136. if (document.head)
  12137. {
  12138. var scripts = document.head.querySelectorAll('script');
  12139. for (var i = 0; i < scripts.length; i++)
  12140. {
  12141. if (isWebSocketScript(scripts[i]))
  12142. {
  12143. // does this work?
  12144. scripts[i].onload = webSocketLoaded;
  12145. found = true;
  12146. }
  12147. }
  12148. }
  12149. if (!found)
  12150. {
  12151. // create an observer instance
  12152. var mutationObserver_1 = new MutationObserver(function (mutationList)
  12153. {
  12154. mutationList.forEach(function (mutation)
  12155. {
  12156. if (mutation.addedNodes.length === 0)
  12157. {
  12158. return;
  12159. }
  12160. for (var i = 0; i < mutation.addedNodes.length; i++)
  12161. {
  12162. var node = mutation.addedNodes[i];
  12163. if (isScriptElement(node) && isWebSocketScript(node))
  12164. {
  12165. mutationObserver_1.disconnect();
  12166. node.onload = webSocketLoaded;
  12167. return;
  12168. }
  12169. }
  12170. });
  12171. });
  12172. mutationObserver_1.observe(document.head
  12173. , {
  12174. childList: true
  12175. });
  12176. }
  12177. // fix scrollText (e.g. when joining the game and receiving xp at that moment)
  12178. win.mouseX = win.innerWidth / 2;
  12179. win.mouseY = win.innerHeight / 2;
  12180. var _confirm = win.confirm;
  12181. win.confirm = function (message)
  12182. {
  12183. // don't show the annoying update confirm box (instead of a confirm box, an ingame dialog could be used...)
  12184. if (message && message.indexOf('Ted\'s Market Script') !== -1)
  12185. {
  12186. return false;
  12187. }
  12188. return _confirm(message);
  12189. };
  12190. })(main || (main = {}));
  12191.  
  12192. })();