DH2 Fixed's temporary fixed

Improve Diamond Hunt 2's DH2 Fixed

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

  1. // ==UserScript==
  2. // @name DH2 Fixed's temporary fixed
  3. // @namespace FileFace
  4. // @description Improve Diamond Hunt 2's DH2 Fixed
  5. // @version 1.2.74
  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. // @require https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
  13.  
  14. // ==/UserScript==
  15. /*jshint multistr: true */
  16. /*jslint es5: true */
  17. // This is a continue developing script from Zorbing's since he has been inactive for a long time, with help from other players
  18. // It might be removed once the author is back and he ask to put it down
  19. // Credits: bazzaspam, agrodon, ktnn
  20. /**
  21. * ISC License (ISC)
  22. *
  23. * Copyright (c) 2017, Martin Boekhoff
  24. *
  25. * Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby
  26. * granted, provided that the above copyright notice and this permission notice appear in all copies.
  27. *
  28. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  29. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  30. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  31. * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  32. * PERFORMANCE OF THIS SOFTWARE.
  33. *
  34. * Source: http://opensource.org/licenses/ISC
  35. */
  36. // tablesorter for brewing calc
  37. (function($){$.extend({tablesorter:new
  38. function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",cssChildRow:"expand-child",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,sortLocaleCompare:true,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'/\.|\,/g',onRenderHeader:null,selectorHeaders:'thead th',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}if(table.tBodies.length==0)return;var rows=table.tBodies[0].rows;if(rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i<l;i++){var p=false;if($.metadata&&($($headers[i]).metadata()&&$($headers[i]).metadata().sorter)){p=getParserById($($headers[i]).metadata().sorter);}else if((table.config.headers[i]&&table.config.headers[i].sorter)){p=getParserById(table.config.headers[i].sorter);}if(!p){p=detectParserForColumn(table,rows,-1,i);}if(table.config.debug){parsersDebug+="column:"+i+" parser:"+p.id+"\n";}list.push(p);}}if(table.config.debug){log(parsersDebug);}return list;};function detectParserForColumn(table,rows,rowIndex,cellIndex){var l=parsers.length,node=false,nodeValue=false,keepLooking=true;while(nodeValue==''&&keepLooking){rowIndex++;if(rows[rowIndex]){node=getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex);nodeValue=trimAndGetNodeText(table.config,node);if(table.config.debug){log('Checking if value was empty on row:'+rowIndex);}}else{keepLooking=false;}}for(var i=1;i<l;i++){if(parsers[i].is(nodeValue,table,node)){return parsers[i];}}return parsers[0];}function getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex){return rows[rowIndex].cells[cellIndex];}function trimAndGetNodeText(config,node){return $.trim(getElementText(config,node));}function getParserById(name){var l=parsers.length;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==name.toLowerCase()){return parsers[i];}}return false;}function buildCache(table){if(table.config.debug){var cacheTime=new Date();}var totalRows=(table.tBodies[0]&&table.tBodies[0].rows.length)||0,totalCells=(table.tBodies[0].rows[0]&&table.tBodies[0].rows[0].cells.length)||0,parsers=table.config.parsers,cache={row:[],normalized:[]};for(var i=0;i<totalRows;++i){var c=$(table.tBodies[0].rows[i]),cols=[];if(c.hasClass(table.config.cssChildRow)){cache.row[cache.row.length-1]=cache.row[cache.row.length-1].add(c);continue;}cache.row.push(c);for(var j=0;j<totalCells;++j){cols.push(parsers[j].format(getElementText(table.config,c[0].cells[j]),table,c[0].cells[j]));}cols.push(cache.normalized.length);cache.normalized.push(cols);cols=null;};if(table.config.debug){benchmark("Building cache for "+totalRows+" rows:",cacheTime);}return cache;};function getElementText(config,node){var text="";if(!node)return"";if(!config.supportsTextContent)config.supportsTextContent=node.textContent||false;if(config.textExtraction=="simple"){if(config.supportsTextContent){text=node.textContent;}else{if(node.childNodes[0]&&node.childNodes[0].hasChildNodes()){text=node.childNodes[0].innerHTML;}else{text=node.innerHTML;}}}else{if(typeof(config.textExtraction)=="function"){text=config.textExtraction(node);}else{text=$(node).text();}}return text;}function appendToTable(table,cache){if(table.config.debug){var appendTime=new Date()}var c=cache,r=c.row,n=c.normalized,totalRows=n.length,checkCell=(n[0].length-1),tableBody=$(table.tBodies[0]),rows=[];for(var i=0;i<totalRows;i++){var pos=n[i][checkCell];rows.push(r[pos]);if(!table.config.appender){var l=r[pos].length;for(var j=0;j<l;j++){tableBody[0].appendChild(r[pos][j]);}}}if(table.config.appender){table.config.appender(table,rows);}rows=null;if(table.config.debug){benchmark("Rebuilt table:",appendTime);}applyWidget(table);setTimeout(function(){$(table).trigger("sortEnd");},0);};function buildHeaders(table){if(table.config.debug){var time=new Date();}var meta=($.metadata)?true:false;var header_index=computeTableHeaderCellIndexes(table);$tableHeaders=$(table.config.selectorHeaders,table).each(function(index){this.column=header_index[this.parentNode.rowIndex+"-"+this.cellIndex];this.order=formatSortingOrder(table.config.sortInitialOrder);this.count=this.order;if(checkHeaderMetadata(this)||checkHeaderOptions(table,index))this.sortDisabled=true;if(checkHeaderOptionsSortingLocked(table,index))this.order=this.lockedOrder=checkHeaderOptionsSortingLocked(table,index);if(!this.sortDisabled){var $th=$(this).addClass(table.config.cssHeader);if(table.config.onRenderHeader)table.config.onRenderHeader.apply($th);}table.config.headerList[index]=this;});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders);}return $tableHeaders;};function computeTableHeaderCellIndexes(t){var matrix=[];var lookup={};var thead=t.getElementsByTagName('THEAD')[0];var trs=thead.getElementsByTagName('TR');for(var i=0;i<trs.length;i++){var cells=trs[i].cells;for(var j=0;j<cells.length;j++){var c=cells[j];var rowIndex=c.parentNode.rowIndex;var cellId=rowIndex+"-"+c.cellIndex;var rowSpan=c.rowSpan||1;var colSpan=c.colSpan||1
  39. var firstAvailCol;if(typeof(matrix[rowIndex])=="undefined"){matrix[rowIndex]=[];}for(var k=0;k<matrix[rowIndex].length+1;k++){if(typeof(matrix[rowIndex][k])=="undefined"){firstAvailCol=k;break;}}lookup[cellId]=firstAvailCol;for(var k=rowIndex;k<rowIndex+rowSpan;k++){if(typeof(matrix[k])=="undefined"){matrix[k]=[];}var matrixrow=matrix[k];for(var l=firstAvailCol;l<firstAvailCol+colSpan;l++){matrixrow[l]="x";}}}}return lookup;}function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i<c.length;i++){var cell=c[i];if(cell.colSpan>1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function checkHeaderOptionsSortingLocked(table,i){if((table.config.headers[i])&&(table.config.headers[i].lockedOrder))return table.config.headers[i].lockedOrder;return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i<l;i++){getWidgetById(c[i]).format(table);}}function getWidgetById(name){var l=widgets.length;for(var i=0;i<l;i++){if(widgets[i].id.toLowerCase()==name.toLowerCase()){return widgets[i];}}};function formatSortingOrder(v){if(typeof(v)!="Number"){return(v.toLowerCase()=="desc")?1:0;}else{return(v==1)?1:0;}}function isValueInArray(v,a){var l=a.length;for(var i=0;i<l;i++){if(a[i][0]==v){return true;}}return false;}function setHeadersCss(table,$headers,list,css){$headers.removeClass(css[0]).removeClass(css[1]);var h=[];$headers.each(function(offset){if(!this.sortDisabled){h[this.column]=$(this);}});var l=list.length;for(var i=0;i<l;i++){h[list[i][0]].addClass(css[list[i][1]]);}}function fixColumnWidth(table,$headers){var c=table.config;if(c.widthFixed){var colgroup=$('<colgroup>');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('<col>').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i<l;i++){var s=sortList[i],o=c.headerList[s[0]];o.count=s[1];o.count++;}}function multisort(table,sortList,cache){if(table.config.debug){var sortTime=new Date();}var dynamicExp="var sortWrapper = function(a,b) {",l=sortList.length;for(var i=0;i<l;i++){var c=sortList[i][0];var order=sortList[i][1];var s=(table.config.parsers[c].type=="text")?((order==0)?makeSortFunction("text","asc",c):makeSortFunction("text","desc",c)):((order==0)?makeSortFunction("numeric","asc",c):makeSortFunction("numeric","desc",c));var e="e"+i;dynamicExp+="var "+e+" = "+s;dynamicExp+="if("+e+") { return "+e+"; } ";dynamicExp+="else { ";}var orgOrderCol=cache.normalized[0].length-1;dynamicExp+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(var i=0;i<l;i++){dynamicExp+="}; ";}dynamicExp+="return 0; ";dynamicExp+="}; ";if(table.config.debug){benchmark("Evaling expression:"+dynamicExp,new Date());}eval(dynamicExp);cache.normalized.sort(sortWrapper);if(table.config.debug){benchmark("Sorting on "+sortList.toString()+" and dir "+order+" time:",sortTime);}return cache;};function makeSortFunction(type,direction,index){var a="a["+index+"]",b="b["+index+"]";if(type=='text'&&direction=='asc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+a+" < "+b+") ? -1 : 1 )));";}else if(type=='text'&&direction=='desc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+b+" < "+a+") ? -1 : 1 )));";}else if(type=='numeric'&&direction=='asc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+a+" - "+b+"));";}else if(type=='numeric'&&direction=='desc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+b+" - "+a+"));";}};function makeSortText(i){return"((a["+i+"] < b["+i+"]) ? -1 : ((a["+i+"] > b["+i+"]) ? 1 : 0));";};function makeSortTextDesc(i){return"((b["+i+"] < a["+i+"]) ? -1 : ((b["+i+"] > a["+i+"]) ? 1 : 0));";};function makeSortNumeric(i){return"a["+i+"]-b["+i+"];";};function makeSortNumericDesc(i){return"b["+i+"]-a["+i+"];";};function sortText(a,b){if(table.config.sortLocaleCompare)return a.localeCompare(b);return((a<b)?-1:((a>b)?1:0));};function sortTextDesc(a,b){if(table.config.sortLocaleCompare)return b.localeCompare(a);return((b<a)?-1:((b>a)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$.data(this,"tablesorter",config);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){$this.trigger("sortStart");var $cell=$(this);var i=this.column;this.order=this.count++%2;if(this.lockedOrder)this.order=this.lockedOrder;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j<a.length;j++){if(a[j][0]!=i){config.sortList.push(a[j]);}}}config.sortList.push([i,this.order]);}else{if(isValueInArray(i,config.sortList)){for(var j=0;j<config.sortList.length;j++){var s=config.sortList[j],o=config.headerList[s[0]];if(s[0]==i){o.count=s[1];o.count++;s[1]=o.count%2;}}}else{config.sortList.push([i,this.order]);}};setTimeout(function(){setHeadersCss($this[0],$headers,config.sortList,sortCSS);appendToTable($this[0],multisort($this[0],config.sortList,cache));},1);return false;}}).mousedown(function(){if(config.cancelSelection){this.onselectstart=function(){return false};return false;}});$this.bind("update",function(){var me=this;setTimeout(function(){me.config.parsers=buildParserCache(me,$headers);cache=buildCache(me);},1);}).bind("updateCell",function(e,cell){var config=this.config;var pos=[(cell.parentNode.rowIndex-1),cell.cellIndex];cache.normalized[pos[0]][pos[1]]=config.parsers[pos[1]].format(getElementText(config,cell),cell);}).bind("sorton",function(e,list){$(this).trigger("sortStart");config.sortList=list;var sortList=config.sortList;updateHeaderSortCount(this,sortList);setHeadersCss(this,$headers,sortList,sortCSS);appendToTable(this,multisort(this,sortList,cache));}).bind("appendCache",function(){appendToTable(this,cache);}).bind("applyWidgetId",function(e,id){getWidgetById(id).format(this);}).bind("applyWidgets",function(){applyWidget(this);});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){config.sortList=$(this).metadata().sortlist;}if(config.sortList.length>0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==parser.id.toLowerCase()){a=false;}}if(a){parsers.push(parser);};};this.addWidget=function(widget){widgets.push(widget);};this.formatFloat=function(s){var i=parseFloat(s);return(isNaN(i))?0:i;};this.formatInt=function(s){var i=parseInt(s);return(isNaN(i))?0:i;};this.isDigit=function(s,config){return/^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g,'')));};this.clearTableBody=function(table){if($.browser.msie){function empty(){while(this.firstChild)this.removeChild(this.firstChild);}empty.apply(table.tBodies[0]);}else{table.tBodies[0].innerHTML="";}};}});$.fn.extend({tablesorter:$.tablesorter.construct});var ts=$.tablesorter;ts.addParser({id:"text",is:function(s){return true;},format:function(s){return $.trim(s.toLocaleLowerCase());},type:"text"});ts.addParser({id:"digit",is:function(s,table){var c=table.config;return $.tablesorter.isDigit(s,c);},format:function(s){return $.tablesorter.formatFloat(s);},type:"numeric"});ts.addParser({id:"currency",is:function(s){return/^[£$€?.]/.test(s);},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g),""));},type:"numeric"});ts.addParser({id:"ipAddress",is:function(s){return/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);},format:function(s){var a=s.split("."),r="",l=a.length;for(var i=0;i<l;i++){var item=a[i];if(item.length==2){r+="0"+item;}else{r+=item;}}return $.tablesorter.formatFloat(r);},type:"numeric"});ts.addParser({id:"url",is:function(s){return/^(https?|ftp|file):\/\/$/.test(s);},format:function(s){return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));},type:"text"});ts.addParser({id:"isoDate",is:function(s){return/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);},format:function(s){return $.tablesorter.formatFloat((s!="")?new Date(s.replace(new RegExp(/-/g),"/")).getTime():"0");},type:"numeric"});ts.addParser({id:"percent",is:function(s){return/\%$/.test($.trim(s));},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));},type:"numeric"});ts.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"shortDate",is:function(s){return/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);},format:function(s,table){var c=table.config;s=s.replace(/\-/g,"/");if(c.dateFormat=="us"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$1/$2");}else if(c.dateFormat=="uk"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$2/$1");}else if(c.dateFormat=="dd/mm/yy"||c.dateFormat=="dd-mm-yy"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3");}return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"time",is:function(s){return/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);},format:function(s){return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime());},type:"numeric"});ts.addParser({id:"metadata",is:function(s){return false;},format:function(s,table,cell){var c=table.config,p=(!c.parserMetadataName)?'sortValue':c.parserMetadataName;return $(cell).metadata()[p];},type:"numeric"});ts.addWidget({id:"zebra",format:function(table){if(table.config.debug){var time=new Date();}var $tr,row=-1,odd;$("tr:visible",table.tBodies[0]).each(function(i){$tr=$(this);if(!$tr.hasClass(table.config.cssChildRow))row++;odd=(row%2==0);$tr.removeClass(table.config.widgetZebra.css[odd?0:1]).addClass(table.config.widgetZebra.css[odd?1:0])});if(table.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time);}}});})(jQuery);
  40. // main script
  41. (function ()
  42. {
  43. 'use strict';
  44. var version = '0.246.2';
  45. var buildTime = new Date('2017-08-12T16:37:11.942Z');
  46. var win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;
  47.  
  48.  
  49. /**
  50. * observer
  51. */
  52. var observer;
  53. (function (observer)
  54. {
  55. observer.GAME_TICK_KEY = 'dh2.gameTick';
  56. var observedKeys = new Map();
  57.  
  58. function add(key, fn)
  59. {
  60. if (key instanceof Array)
  61. {
  62. for (var _i = 0, key_1 = key; _i < key_1.length; _i++)
  63. {
  64. var k = key_1[_i];
  65. add(k, fn);
  66. }
  67. }
  68. else
  69. {
  70. if (!observedKeys.has(key))
  71. {
  72. observedKeys.set(key, new Set());
  73. }
  74. observedKeys.get(key).add(fn);
  75. }
  76. return fn;
  77. }
  78.  
  79. observer.add = add;
  80.  
  81. function notify(key, oldValue)
  82. {
  83. var newValue = getGameValue(key);
  84. if (observedKeys.has(key))
  85. {
  86. observedKeys.get(key).forEach(function (fn)
  87. {
  88. return fn(key, oldValue, newValue);
  89. });
  90. }
  91. }
  92. observer.notify = notify;
  93.  
  94. function notifyTick()
  95. {
  96. notify(observer.GAME_TICK_KEY, Math.floor(now() / 1000));
  97. }
  98. observer.notifyTick = notifyTick;
  99.  
  100. function remove(key, fn)
  101. {
  102. if (key instanceof Array)
  103. {
  104. var ret = [];
  105. for (var _i = 0, key_2 = key; _i < key_2.length; _i++)
  106. {
  107. var k = key_2[_i];
  108. ret.push(remove(k, fn));
  109. }
  110. return ret;
  111. }
  112. if (!observedKeys.has(key))
  113. {
  114. return false;
  115. }
  116. return observedKeys.get(key).delete(fn);
  117. }
  118. observer.remove = remove;
  119.  
  120. function addTick(fn)
  121. {
  122. return add(observer.GAME_TICK_KEY, fn);
  123. }
  124. observer.addTick = addTick;
  125.  
  126. function removeTick(fn)
  127. {
  128. return remove(observer.GAME_TICK_KEY, fn);
  129. }
  130. observer.removeTick = removeTick;
  131. })(observer || (observer = {}));
  132. /**
  133. * global constants
  134. */
  135. var PLUS_MINUS_SIGN = String.fromCharCode(177);
  136. var TIER_LEVELS = ['empty', 'sapphire', 'emerald', 'ruby', 'diamond'];
  137. var TIER_NAMES = ['Standard', 'Sapphire', 'Emerald', 'Ruby', 'Diamond'];
  138. var TIER_ITEMS = ['pickaxe', 'shovel', 'hammer', 'axe', 'rake', 'trowel', 'fishingRod', 'chisel'];
  139. var ORB_ITEMS = ['pickaxe', 'shovel', 'hammer', 'axe', 'rake', 'trowel', 'fishingRod', 'chisel', 'oilPipe'];
  140. var TIER_ITEMS_NOT_BINDABLE = ['rake', 'trowel'];
  141. var FURNACE_LEVELS = ['stone', 'bronze', 'iron', 'silver', 'gold', 'promethium', 'runite'];
  142. var OVEN_LEVELS = ['bronze', 'iron', 'silver', 'gold', 'promethium', 'runite'];
  143. var WAND_LEVELS = ['wooden', 'oak', 'willow', 'maple', 'stardust', 'strange', 'ancient'];
  144. var OIL_STORAGE_SIZES = [10e3, 50e3, 100e3, 300e3, 600e3, 2e6];
  145. var RECIPE_MAX = {
  146. 'brewing':
  147. {
  148. 'braveryPotion':
  149. {
  150. max: 1
  151. }
  152. , 'stardustCrystalPotion':
  153. {
  154. max: 1
  155. }
  156. }
  157. , 'cooksBook':
  158. {}
  159. , 'crafting':
  160. {
  161. 'drills':
  162. {
  163. max: 10
  164. }
  165. , 'crushers':
  166. {
  167. max: 10
  168. }
  169. , 'giantDrills':
  170. {
  171. max: 10
  172. }
  173. , 'excavators':
  174. {
  175. max: 10
  176. }
  177. , 'oilPipe':
  178. {
  179. max: 1
  180. }
  181. , 'pumpjacks':
  182. {
  183. max: 10
  184. }
  185. , 'rowBoat':
  186. {
  187. max: 1
  188. }
  189. , 'canoe':
  190. {
  191. max: 1
  192. }
  193. , 'sailBoat':
  194. {
  195. max: 1
  196. }
  197. , 'steamBoat':
  198. {
  199. max: 1
  200. }
  201. // thanks aguyd
  202. , 'bonemealBin':
  203. {
  204. extraKeys: ['boundFilledBonemealBin']
  205. , max: 1
  206. }
  207. , 'oilFactory':
  208. {
  209. max: 1
  210. }
  211. , 'brewingKit':
  212. {
  213. max: 1
  214. }
  215. , 'rocket':
  216. {
  217. max: 1
  218. }
  219. }
  220. , 'magic':
  221. {}
  222. };
  223. var SMELTING_REQUIREMENTS = {
  224. 'glass':
  225. {
  226. sand: 1
  227. , oil: 10
  228. }
  229. , 'bronzeBar':
  230. {
  231. copper: 1
  232. , tin: 1
  233. , oil: 10
  234. }
  235. , 'ironBar':
  236. {
  237. iron: 1
  238. , oil: 100
  239. }
  240. , 'silverBar':
  241. {
  242. silver: 1
  243. , oil: 300
  244. }
  245. , 'goldBar':
  246. {
  247. gold: 1
  248. , oil: 1e3
  249. }
  250. , 'promethiumBar':
  251. {
  252. promethium: 1
  253. , charcoal: 1
  254. }
  255. };
  256. var PLANT_NAME = {
  257. '1': 'Dark Mushrooms'
  258. , '2': 'Red Mushrooms'
  259. , '3': 'Dotted Green Leaves'
  260. , '4': 'Green Leaves'
  261. , '5': 'Lime Leaves'
  262. , '6': 'Gold Leaves'
  263. , '7': 'Striped Gold Leaves'
  264. , '8': 'Crystal Leaves'
  265. , '9': 'Striped Crystal Leaves'
  266. , '10': 'Blewit Mushrooms'
  267. , '11': 'Snapegrass'
  268. , '12': 'Tree'
  269. , '13': 'Oak Tree'
  270. , '14': 'Wheat'
  271. , '15': 'Willow Tree'
  272. , '16': 'Grass'
  273. , '17': 'Maple Tree'
  274. , '18': 'Stardust Tree'
  275. , '19': 'Carrots'
  276. , '20': 'Tomatoes'
  277. , '21': 'Potatoes'
  278. , '22': 'Strange Leaf Tree'
  279. , '23': 'Light Mushrooms'
  280. , '24': 'Pumpkins'
  281. , '25': 'Ancient Tree'
  282. , '26': 'Stardust Plant'
  283. , '27': 'White Leaf'
  284. };
  285. var SKILL_LIST = ['mining', 'crafting', 'woodcutting', 'farming', 'brewing', 'combat', 'fishing', 'cooking', 'magic'];
  286. var AREA_LIST = ['fields', 'forests', 'caves', 'volcano', 'northFields', 'hauntedMansion'];
  287. var AREA_NAMES = ['Fields', 'Forests', 'Caves', 'Volcano', 'Northern Fields', 'Haunted Mansion', 'Moon', 'Dark Forest'];
  288.  
  289. function getAreaName(areaId)
  290. {
  291. if (areaId === 33)
  292. {
  293. return 'Quest';
  294. }
  295. else if (areaId === 34)
  296. {
  297. return "Faradox's Tombs";
  298. }
  299. else if (areaId === 35)
  300. {
  301. return "Goblin Hideout";
  302. }
  303. else
  304. {
  305. return AREA_NAMES[areaId];
  306. }
  307. }
  308. 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'];
  309.  
  310. function getMonsterName(monsterId)
  311. {
  312. if (monsterId === 101)
  313. {
  314. return 'Ghostly Old Mage';
  315. }
  316. else if (monsterId === 99)
  317. {
  318. return 'Evil Snake';
  319. }
  320. else if (monsterId === 100)
  321. {
  322. return 'Easter Bunny';
  323. }
  324. else if (monsterId === 102)
  325. {
  326. return '1st Tomb Monster';
  327. }
  328. else if (monsterId === 103)
  329. {
  330. return '2nd Tomb Monster';
  331. }
  332. else if (monsterId === 104)
  333. {
  334. return '3rd Tomb Monster';
  335. }
  336. else if (monsterId === 105)
  337. {
  338. return '4th Tomb Monster';
  339. }
  340. else if (monsterId === 106)
  341. {
  342. return '5th Tomb Monster';
  343. }
  344. else if (monsterId === 107)
  345. {
  346. return 'Gem Goblin';
  347. }
  348. else
  349. {
  350. return MONSTER_NAMES[monsterId];
  351. }
  352. }
  353. var FISH_XP = {
  354. 'rawShrimp': 50
  355. , 'rawSardine': 500
  356. , 'rawSalmon': 700
  357. , 'rawTuna': 3e3
  358. , 'rawLobster': 5e3
  359. , 'rawSwordfish': 5e3
  360. , 'rawEel': 6e3
  361. , 'rawShark': 12e3
  362. , 'rawWhale': 20e3
  363. , 'rawRainbowFish': 30e3
  364. };
  365. var BOAT_LIST = ['rowBoat', 'canoe', 'sailBoat', 'steamBoat'];
  366. var TRIP_DURATION = {
  367. 'rowBoat': 3
  368. , 'canoe': 5
  369. , 'sailBoat': 7
  370. , 'steamBoat': 10
  371. };
  372. var MAX_ROCKET_MOON_KM = 384400;
  373. var MAX_ROCKET_MARS_KM = 54600000;
  374. var format;
  375. (function (format)
  376. {
  377. var UNITS = [
  378. {
  379. threshold: 10e3
  380. , factor: 1e3
  381. , token: 'k'
  382. }
  383. , {
  384. threshold: 1e6
  385. , factor: 1e6
  386. , token: 'M'
  387. }
  388. , {
  389. threshold: 1e9
  390. , factor: 1e9
  391. , token: 'B'
  392. }
  393. , {
  394. threshold: 1e12
  395. , factor: 1e12
  396. , token: 'T'
  397. }
  398. , {
  399. threshold: 1e15
  400. , factor: 1e15
  401. , token: 'Q'
  402. }];
  403. var TIME_STEPS = [
  404. {
  405. threshold: 1
  406. , name: 'second'
  407. , short: 'sec'
  408. , padp: 0
  409. }
  410. , {
  411. threshold: 60
  412. , name: 'minute'
  413. , short: 'min'
  414. , padp: 0
  415. }
  416. , {
  417. threshold: 3600
  418. , name: 'hour'
  419. , short: 'h'
  420. , padp: 1
  421. }
  422. , {
  423. threshold: 86400
  424. , name: 'day'
  425. , short: 'd'
  426. , padp: 2
  427. }];
  428.  
  429. function ensureNumber(num)
  430. {
  431. return (typeof num === 'number' ? num : Number(num));
  432. }
  433.  
  434. function number(num, shorten)
  435. {
  436. if (shorten === void 0)
  437. {
  438. shorten = false;
  439. }
  440. num = ensureNumber(num);
  441. if (shorten)
  442. {
  443. for (var i = UNITS.length - 1; i >= 0; i--)
  444. {
  445. var unit = UNITS[i];
  446. if (num >= unit.threshold)
  447. {
  448. return number(Math.round(num / unit.factor)) + unit.token;
  449. }
  450. }
  451. }
  452. return num.toLocaleString('en');
  453. }
  454. format.number = number;
  455.  
  456. function numbersInText(text)
  457. {
  458. return text.replace(/\d(?:[\d',\.]*\d)?/g, function (numStr)
  459. {
  460. return number(numStr.replace(/\D/g, ''));
  461. });
  462. }
  463. format.numbersInText = numbersInText;
  464. // use time format established in DHQoL (https://greasyfork.org/scripts/16041-dhqol)
  465. function timer(timer, shorten)
  466. {
  467. if (shorten === void 0)
  468. {
  469. shorten = true;
  470. }
  471. if (typeof timer === 'string')
  472. {
  473. timer = parseInt(timer, 10);
  474. }
  475. timer = Math.max(timer, 0);
  476. var days = Math.floor(timer / 86400); // 24 * 60 * 60
  477. var hours = Math.floor((timer % 86400) / 3600); // 60 * 60
  478. var minutes = Math.floor((timer % 3600) / 60);
  479. var seconds = timer % 60;
  480. return (shorten && days === 0 ? '' : days + 'd ')
  481. + (shorten && days === 0 && hours === 0 ? '' : zeroPadLeft(hours) + ':')
  482. + zeroPadLeft(minutes) + ':'
  483. + zeroPadLeft(seconds);
  484. }
  485. format.timer = timer;
  486.  
  487. function time2NearestUnit(time, long)
  488. {
  489. if (long === void 0)
  490. {
  491. long = false;
  492. }
  493. var step = TIME_STEPS[0];
  494. for (var i = TIME_STEPS.length - 1; i > 0; i--)
  495. {
  496. if (time >= TIME_STEPS[i].threshold)
  497. {
  498. step = TIME_STEPS[i];
  499. break;
  500. }
  501. }
  502. var factor = Math.pow(10, step.padp);
  503. var num = Math.round(time / step.threshold * factor) / factor;
  504. var unit = long ? step.name + (num === 1 ? '' : 's') : step.short;
  505. return num + ' ' + unit;
  506. }
  507. format.time2NearestUnit = time2NearestUnit;
  508.  
  509. function sec2Str(seconds)
  510. {
  511. seconds = Number(seconds);
  512. if (seconds < 0)
  513. {
  514. return seconds.toString();
  515. }
  516. var s = seconds % 60;
  517. var m = Math.floor(seconds / 60) % 60;
  518. var h = Math.floor(seconds / 3600);
  519. var strs = [];
  520. if (h > 0)
  521. {
  522. strs.push(h + ' hour' + (h == 1 ? '' : 's'));
  523. }
  524. if (m > 0)
  525. {
  526. strs.push(m + ' minute' + (m == 1 ? '' : 's'));
  527. }
  528. if (s > 0)
  529. {
  530. strs.push(s + ' second' + (s == 1 ? '' : 's'));
  531. }
  532. if (strs.length > 1)
  533. {
  534. var glue = ' and ';
  535. for (var i = strs.length - 2; i >= 0; i--)
  536. {
  537. strs[i] = strs[i] + glue + strs[i + 1];
  538. glue = ', ';
  539. }
  540. return strs[0];
  541. }
  542. else
  543. {
  544. return strs[0] || '';
  545. }
  546. }
  547. format.sec2Str = sec2Str;
  548.  
  549. function min2Str(minutes)
  550. {
  551. return sec2Str(Number(minutes) * 60);
  552. }
  553. format.min2Str = min2Str;
  554. })(format || (format = {}));
  555.  
  556. /**
  557. * general functions
  558. */
  559. function getStyle(elId)
  560. {
  561. var id = elId != null ? 'style-' + elId : null;
  562. var styleElement = id != null ? document.getElementById(id) : null;
  563. if (styleElement == null)
  564. {
  565. styleElement = document.createElement('style');
  566. if (id != null)
  567. {
  568. styleElement.id = id;
  569. }
  570. styleElement.type = 'text/css';
  571. document.head.appendChild(styleElement);
  572. }
  573. return styleElement;
  574. }
  575.  
  576. function addStyle(styleCode, elId)
  577. {
  578. var styleElement = getStyle(elId);
  579. styleElement.innerHTML += styleCode;
  580. }
  581.  
  582. function zeroPadLeft(num)
  583. {
  584. return (num < 10 ? '0' : '') + num;
  585. }
  586.  
  587. function capitalize(str)
  588. {
  589. return str[0].toUpperCase() + str.substr(1);
  590. }
  591.  
  592. function key2Name(key, lowerCase)
  593. {
  594. if (lowerCase === void 0)
  595. {
  596. lowerCase = false;
  597. }
  598. var name = key.replace(/[A-Z]/g, function (c)
  599. {
  600. return ' ' + (lowerCase ? c.toLowerCase() : c);
  601. });
  602. return lowerCase ? name : capitalize(name);
  603. }
  604.  
  605. function pluralize(name)
  606. {
  607. return name.replace(/([^aeiou])y$/, '$1ie').replace(/s?$/, '') + 's';
  608. }
  609.  
  610. function split2Words(str, char)
  611. {
  612. if (char === void 0)
  613. {
  614. char = ' ';
  615. }
  616. return str.replace(/[A-Z]/g, char + '$&');
  617. }
  618.  
  619. function getBoundKey(key)
  620. {
  621. return 'bound' + capitalize(key);
  622. }
  623.  
  624. function getTierKey(key, tierLevel)
  625. {
  626. return TIER_LEVELS[tierLevel] + capitalize(key);
  627. }
  628.  
  629. function getWikiaKey(key)
  630. {
  631. return key2Name(key.replace(/^bound-?|^special-case-/i, '').replace(/\d+[km]?$/i, ''))
  632. .replace(/^\s/, '').replace(/[ -]/g, '_')
  633. .replace(/^(?:Empty|Sapphire|Emerald|Ruby|Diamond|Raw|Uncooked|Filled)_/, '')
  634. .replace(/^(?:Bronze|Iron|Silver|Gold|Promethium|Runite)_(?!Bar)/, '')
  635. .replace(/^Npc_/, 'Monster_')
  636. .replace(/_(?:Unlocked|Quest)$/, '');
  637. }
  638.  
  639. function getWikiaLink(key)
  640. {
  641. return 'http://diamondhuntonline.wikia.com/wiki/' + getWikiaKey(key);
  642. }
  643.  
  644. function now()
  645. {
  646. return (new Date()).getTime();
  647. }
  648.  
  649. function ensureTooltip(id, target)
  650. {
  651. var tooltipId = 'tooltip-' + id;
  652. var tooltipEl = document.getElementById(tooltipId);
  653. if (!tooltipEl)
  654. {
  655. tooltipEl = document.createElement('div');
  656. tooltipEl.id = tooltipId;
  657. tooltipEl.style.display = 'none';
  658. var tooltipList = document.getElementById('tooltip-list');
  659. tooltipList.appendChild(tooltipEl);
  660. }
  661. // ensure binded events to show the tooltip
  662. if (target.dataset.tooltipId == null)
  663. {
  664. target.dataset.tooltipId = tooltipId;
  665. win.$(target).bind(
  666. {
  667. mousemove: win.changeTooltipPosition
  668. , mouseenter: win.showTooltip
  669. , mouseleave: function (event)
  670. {
  671. var target = event.target;
  672. var parent = target.parentElement;
  673. // ensure tooltips inside an tooltip element is possible
  674. if (!!target.dataset.tooltipId && parent && !!parent.dataset.tooltipId)
  675. {
  676. win.showTooltip.call(parent, event);
  677. }
  678. else
  679. {
  680. win.hideTooltip(event);
  681. }
  682. }
  683. });
  684. }
  685. return tooltipEl;
  686. }
  687. var timeStr2Sec = (function ()
  688. {
  689. var unitFactors = {
  690. 'd': 24 * 60 * 60
  691. , 'h': 60 * 60
  692. , 'm': 60
  693. , 's': 1
  694. };
  695. return function timeStr2Sec(str)
  696. {
  697. return str
  698. .replace(/(\d+)([hms])/g, function (wholeMatch, num, unit)
  699. {
  700. return parseInt(num) * (unitFactors[unit] || 1) + '+';
  701. })
  702. .split('+')
  703. .map(function (s)
  704. {
  705. return parseInt(s, 10);
  706. })
  707. .filter(function (n)
  708. {
  709. return !isNaN(n);
  710. })
  711. .reduce(function (p, c)
  712. {
  713. return p + c;
  714. }, 0);
  715. };
  716. })();
  717.  
  718. function getGameValue(key)
  719. {
  720. return win[key];
  721. }
  722.  
  723. function getFurnaceLevel()
  724. {
  725. for (var i = FURNACE_LEVELS.length - 1; i >= 0; i--)
  726. {
  727. if (getGameValue(getBoundKey(FURNACE_LEVELS[i] + 'Furnace')) > 0)
  728. {
  729. return i;
  730. }
  731. }
  732. return -1;
  733. }
  734.  
  735. function getFurnaceLevelName()
  736. {
  737. return FURNACE_LEVELS[getFurnaceLevel()] || '';
  738. }
  739.  
  740. function getPrice(item)
  741. {
  742. var price = win.getPrice(item);
  743. if (typeof price === 'number')
  744. {
  745. return price;
  746. }
  747. var match = price.match(/(\d+)([kM])/);
  748. if (!match)
  749. {
  750. return parseInt(price, 10);
  751. }
  752. var FACTORS = {
  753. 'k': 1e3
  754. , 'M': 1e6
  755. };
  756. return parseInt(match[1], 10) * (FACTORS[match[2]] || 1);
  757. }
  758.  
  759. function doGet(url)
  760. {
  761. return new Promise(function (resolve, reject)
  762. {
  763. var request = new XMLHttpRequest();
  764. request.onreadystatechange = function (event)
  765. {
  766. if (request.readyState != XMLHttpRequest.DONE)
  767. {
  768. return;
  769. }
  770. if (request.status != 200)
  771. {
  772. return reject(event);
  773. }
  774. resolve(request.responseText);
  775. };
  776. request.open('GET', url);
  777. request.send();
  778. });
  779. }
  780.  
  781. function removeWhitespaceChildNodes(el)
  782. {
  783. for (var i = 0; i < el.childNodes.length; i++)
  784. {
  785. var child = el.childNodes.item(i);
  786. if (child.nodeType === Node.TEXT_NODE && /^\s*$/.test(child.textContent || ''))
  787. {
  788. el.removeChild(child);
  789. i--;
  790. }
  791. }
  792. }
  793.  
  794. function debounce(func, wait, immediate)
  795. {
  796. var timeout;
  797. return function ()
  798. {
  799. var _this = this;
  800. var args = [];
  801. for (var _i = 0; _i < arguments.length; _i++)
  802. {
  803. args[_i] = arguments[_i];
  804. }
  805. var callNow = immediate && !timeout;
  806. timeout && clearTimeout(timeout);
  807. timeout = setTimeout(function ()
  808. {
  809. timeout = null;
  810. if (!immediate)
  811. {
  812. func.apply(_this, args);
  813. }
  814. }, wait);
  815. if (callNow)
  816. {
  817. func.apply(this, args);
  818. }
  819. };
  820. }
  821.  
  822. function passThis(fn)
  823. {
  824. return function ()
  825. {
  826. var args = [];
  827. for (var _i = 0; _i < arguments.length; _i++)
  828. {
  829. args[_i] = arguments[_i];
  830. }
  831. return fn.apply(void 0, [this].concat(args));
  832. };
  833. }
  834. /**
  835. * persistence store
  836. */
  837. var store;
  838. (function (store)
  839. {
  840. var oldPrefix = 'dh2-';
  841. var storePrefix = 'dh2.';
  842.  
  843. function update(key, keepOldValue)
  844. {
  845. if (keepOldValue === void 0)
  846. {
  847. keepOldValue = true;
  848. }
  849. if (localStorage.hasOwnProperty(oldPrefix + key))
  850. {
  851. if (keepOldValue)
  852. {
  853. localStorage.setItem(storePrefix + key, localStorage.getItem(oldPrefix + key));
  854. }
  855. localStorage.removeItem(oldPrefix + key);
  856. }
  857. }
  858. var changeListener = new Map();
  859.  
  860. function changeDetected(key, oldValue, newValue)
  861. {
  862. if (changeListener.has(key))
  863. {
  864. setTimeout(function ()
  865. {
  866. changeListener.get(key).forEach(function (fn)
  867. {
  868. return fn(key, oldValue, newValue);
  869. });
  870. });
  871. }
  872. }
  873.  
  874. function watchFn(fnName)
  875. {
  876. var _fn = localStorage[fnName];
  877. localStorage[fnName] = function (key)
  878. {
  879. var args = [];
  880. for (var _i = 1; _i < arguments.length; _i++)
  881. {
  882. args[_i - 1] = arguments[_i];
  883. }
  884. var oldValue = localStorage.getItem(key);
  885. _fn.apply(localStorage, [key].concat(args));
  886. var newValue = localStorage.getItem(key);
  887. if (oldValue !== newValue)
  888. {
  889. changeDetected(key, oldValue, newValue);
  890. }
  891. };
  892. }
  893. watchFn('setItem');
  894. watchFn('removeItem');
  895. var _clear = localStorage.clear;
  896. localStorage.clear = function ()
  897. {
  898. var oldValues = new Map();
  899. for (var i = 0; i < localStorage.length; i++)
  900. {
  901. var key = localStorage.key(i);
  902. oldValues.set(key, localStorage.getItem(key));
  903. }
  904. _clear();
  905. for (var key in oldValues)
  906. {
  907. var newValue = localStorage.getItem(key);
  908. if (oldValues.get(key) !== newValue)
  909. {
  910. changeDetected(key, oldValues.get(key), newValue);
  911. }
  912. }
  913. };
  914.  
  915. function addChangeListener(key, fn)
  916. {
  917. if (!changeListener.has(key))
  918. {
  919. changeListener.set(key, new Set());
  920. }
  921. changeListener.get(key).add(fn);
  922. }
  923. store.addChangeListener = addChangeListener;
  924.  
  925. function removeChangeListener(key, fn)
  926. {
  927. if (changeListener.has(key))
  928. {
  929. changeListener.get(key).delete(fn);
  930. }
  931. }
  932. store.removeChangeListener = removeChangeListener;
  933.  
  934. function get(key)
  935. {
  936. update(key);
  937. var value = localStorage.getItem(storePrefix + key);
  938. if (value != null)
  939. {
  940. try
  941. {
  942. return JSON.parse(value);
  943. }
  944. catch (e)
  945. {}
  946. }
  947. return value;
  948. }
  949. store.get = get;
  950.  
  951. function has(key)
  952. {
  953. update(key);
  954. return localStorage.hasOwnProperty(storePrefix + key);
  955. }
  956. store.has = has;
  957.  
  958. function remove(key)
  959. {
  960. update(key, false);
  961. localStorage.removeItem(storePrefix + key);
  962. }
  963. store.remove = remove;
  964.  
  965. function set(key, value)
  966. {
  967. update(key, false);
  968. localStorage.setItem(storePrefix + key, JSON.stringify(value));
  969. }
  970. store.set = set;
  971. })(store || (store = {}));
  972.  
  973. var settings;
  974. (function (settings)
  975. {
  976. settings.name = 'settings';
  977. var DIALOG_WIDTH = 450;
  978. var KEY;
  979. (function (KEY)
  980. {
  981. KEY[KEY["hideCraftingRecipes"] = 0] = "hideCraftingRecipes";
  982. KEY[KEY["hideUselessItems"] = 1] = "hideUselessItems";
  983. KEY[KEY["useNewChat"] = 2] = "useNewChat";
  984. KEY[KEY["colorizeChat"] = 3] = "colorizeChat";
  985. KEY[KEY["intelligentScrolling"] = 4] = "intelligentScrolling";
  986. KEY[KEY["showTimestamps"] = 5] = "showTimestamps";
  987. KEY[KEY["showIcons"] = 6] = "showIcons";
  988. KEY[KEY["showTags"] = 7] = "showTags";
  989. KEY[KEY["enableSpamDetection"] = 8] = "enableSpamDetection";
  990. KEY[KEY["useTombNotif"] = 9] = "useTombNotif";
  991. KEY[KEY["useWorkerNotif"] = 10] = "useWorkerNotif";
  992. KEY[KEY["useBobsUncleNotif"] = 11] = "useBobsUncleNotif";
  993. KEY[KEY["showNotifications"] = 12] = "showNotifications";
  994. KEY[KEY["wikiaLinks"] = 13] = "wikiaLinks";
  995. KEY[KEY["newXpAnimation"] = 14] = "newXpAnimation";
  996. KEY[KEY["amountSymbol"] = 15] = "amountSymbol";
  997. KEY[KEY["showTabTimer"] = 16] = "showTabTimer";
  998. KEY[KEY["showLootTab"] = 17] = "showLootTab";
  999. KEY[KEY["useEfficiencyStyle"] = 18] = "useEfficiencyStyle";
  1000. KEY[KEY["makeNumberInputs"] = 19] = "makeNumberInputs";
  1001. KEY[KEY["addKeepInput"] = 20] = "addKeepInput";
  1002. KEY[KEY["addMaxBtn"] = 21] = "addMaxBtn";
  1003. KEY[KEY["highlightUnplantableSeed"] = 22] = "highlightUnplantableSeed";
  1004. KEY[KEY["showSdChange"] = 23] = "showSdChange";
  1005. KEY[KEY["usePotionWarning"] = 24] = "usePotionWarning";
  1006. KEY[KEY["showCaptions"] = 25] = "showCaptions";
  1007. KEY[KEY["syncPriceHistory"] = 26] = "syncPriceHistory";
  1008. KEY[KEY["useNewToolbar"] = 27] = "useNewToolbar";
  1009. KEY[KEY["changeMachineDialog"] = 28] = "changeMachineDialog";
  1010. })(KEY = settings.KEY || (settings.KEY = {}));;
  1011. var CFG = (_a = {}
  1012. , _a[KEY.hideCraftingRecipes] = {
  1013. name: 'Hide crafting recipes of finished items'
  1014. , 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>"
  1015. , defaultValue: true
  1016. }
  1017. , _a[KEY.hideUselessItems] = {
  1018. name: 'Hide useless items'
  1019. , 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>"
  1020. , defaultValue: false
  1021. }
  1022. , _a[KEY.useNewChat] = {
  1023. name: 'Use the new chat'
  1024. , 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"
  1025. , defaultValue: true
  1026. }
  1027. , _a[KEY.colorizeChat] = {
  1028. name: 'Colorize chat messages'
  1029. , description: "Colorize chat messages according to a unique color for each user"
  1030. , defaultValue: false
  1031. , sub:
  1032. {
  1033. 'colorizer':
  1034. {
  1035. defaultValue: 0
  1036. , label: ['Equally Distributed', 'Random (light colors)', 'Random (dark colors)']
  1037. , options: ['equallyDistributed', 'random1', 'random2']
  1038. }
  1039. }
  1040. }
  1041. , _a[KEY.intelligentScrolling] = {
  1042. name: 'Intelligent scrolling'
  1043. , 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."
  1044. , defaultValue: true
  1045. }
  1046. , _a[KEY.showTimestamps] = {
  1047. name: 'Show timestamps'
  1048. , description: "Enables showing timestamps in chat"
  1049. , defaultValue: true
  1050. }
  1051. , _a[KEY.showIcons] = {
  1052. name: 'Show user-icons'
  1053. , description: "Enables showing icons (formerly sigils) for each user in chat"
  1054. , defaultValue: true
  1055. }
  1056. , _a[KEY.showTags] = {
  1057. name: 'Show user-tags'
  1058. , description: "Enables showing tags (Dev, Mod, Contributor) and colors for messages in chat"
  1059. , defaultValue: true
  1060. }
  1061. , _a[KEY.enableSpamDetection] = {
  1062. name: 'Enable spam detection'
  1063. , description: "Enables simple spam detection"
  1064. , defaultValue: true
  1065. }
  1066. , _a[KEY.useTombNotif] = {
  1067. name: 'Use Tomb notification'
  1068. , description: "Shows notification when Faradox's tomb is ready to fight"
  1069. , defaultValue: false
  1070. }
  1071. , _a[KEY.useWorkerNotif] = {
  1072. name: 'Use Worker notification'
  1073. , description: "Shows notification when workers come back"
  1074. , defaultValue: true
  1075. }
  1076. , _a[KEY.useBobsUncleNotif] = {
  1077. name: 'Use Bobs uncle notification'
  1078. , description: "Shows notification when Bob's uncle farm is ready to harvest"
  1079. , defaultValue: true
  1080. }
  1081. , _a[KEY.showNotifications] = {
  1082. name: 'Show browser notifications'
  1083. , description: "Shows browser notifications for enabled events (click the little gear for more options)"
  1084. , defaultValue: true
  1085. , sub:
  1086. {
  1087. 'showType':
  1088. {
  1089. defaultValue: 0
  1090. , label: ['only when window inactive', 'always']
  1091. , options: ['whenInactive', 'always']
  1092. }
  1093. , 'smelting':
  1094. {
  1095. defaultValue: true
  1096. , label: 'Smelting finishes'
  1097. }
  1098. , 'chopping':
  1099. {
  1100. defaultValue: true
  1101. , label: 'A tree is fully grown'
  1102. }
  1103. , 'harvest':
  1104. {
  1105. defaultValue: true
  1106. , label: 'A plant can be harvested'
  1107. }
  1108. , 'potionEffect':
  1109. {
  1110. defaultValue: true
  1111. , label: 'A potion\'s effect ends'
  1112. }
  1113. , 'boatReturned':
  1114. {
  1115. defaultValue: true
  1116. , label: 'A boat returns'
  1117. }
  1118. , 'heroReady':
  1119. {
  1120. defaultValue: true
  1121. , label: 'The hero is fully recovered and ready to fight'
  1122. }
  1123. , 'itemsSold':
  1124. {
  1125. defaultValue: true
  1126. , label: 'Items are sold on the market'
  1127. }
  1128. , 'pirate':
  1129. {
  1130. defaultValue: true
  1131. , label: 'A pirate has found a treasure map'
  1132. }
  1133. , 'rocket':
  1134. {
  1135. defaultValue: true
  1136. , label: 'The rocket has landed on the moon or earth'
  1137. }
  1138. , 'wind':
  1139. {
  1140. defaultValue: true
  1141. , label: 'The wind for the sail boat has changed'
  1142. }
  1143. , 'perk':
  1144. {
  1145. defaultValue: true
  1146. , label: 'A new perk is unlocked (achievement set completed)'
  1147. }
  1148. , 'pm':
  1149. {
  1150. defaultValue: true
  1151. , label: 'A private messages (pm) arrives'
  1152. }
  1153. , 'mention':
  1154. {
  1155. defaultValue: true
  1156. , label: 'The username is mentioned in chat'
  1157. }
  1158. , 'keyword':
  1159. {
  1160. defaultValue: true
  1161. , label: 'A keyword is mentioned in chat'
  1162. }
  1163. , 'serverMsg':
  1164. {
  1165. defaultValue: true
  1166. , label: 'Server messages (like <em>Server is restarting...</em>)'
  1167. }
  1168. }
  1169. }
  1170. , _a[KEY.wikiaLinks] = {
  1171. name: 'Show wikia links'
  1172. , description: "Show wikia links for every item on hover (the little icon in the upper left corner)"
  1173. , defaultValue: true
  1174. }
  1175. , _a[KEY.newXpAnimation] = {
  1176. name: 'New XP-gain animation'
  1177. , description: "Show gained xp on top skill bar instead on the position of the mouse"
  1178. , defaultValue: true
  1179. }
  1180. , _a[KEY.amountSymbol] = {
  1181. name: 'Show \u00D7 on items'
  1182. , description: "Show a tiny \u00D7-symbol before amount numbers of items"
  1183. , defaultValue: true
  1184. }
  1185. , _a[KEY.showTabTimer] = {
  1186. name: 'Show tab timer and info'
  1187. , description: "Show timer on tabs for trees, plants and hero"
  1188. , defaultValue: true
  1189. }
  1190. , _a[KEY.showLootTab] = {
  1191. name: 'Show sub tab for loot table'
  1192. , description: "Show a sub tab for combat drop table in combat"
  1193. , defaultValue: true
  1194. }
  1195. , _a[KEY.useEfficiencyStyle] = {
  1196. name: 'Use space efficient style'
  1197. , description: "Use a space efficient style with less blank space"
  1198. , defaultValue: false
  1199. }
  1200. , _a[KEY.makeNumberInputs] = {
  1201. name: 'Turn text inputs into number inputs'
  1202. , description: "Number inputs allow you to change the amount via arrow buttons"
  1203. , defaultValue: true
  1204. }
  1205. , _a[KEY.addKeepInput] = {
  1206. name: 'Add keep input for selling to npc shop'
  1207. , description: "A keep input allows you to set the amount of items you want to keep when selling"
  1208. , defaultValue: true
  1209. }
  1210. , _a[KEY.addMaxBtn] = {
  1211. name: 'Add max button for some crafting inputs'
  1212. , description: "Add max button for crafting (e.g. vials), brewing potions and cooking food"
  1213. , defaultValue: true
  1214. }
  1215. , _a[KEY.highlightUnplantableSeed] = {
  1216. name: 'Show whether a seed can be planted'
  1217. , description: "Fades the item box of a seed when it's not plantable"
  1218. , defaultValue: true
  1219. }
  1220. , _a[KEY.showSdChange] = {
  1221. name: 'Show stardust change'
  1222. , description: "Shows the amount of stardust earned or spent in the last tick"
  1223. , defaultValue: true
  1224. }
  1225. , _a[KEY.usePotionWarning] = {
  1226. name: 'Use drink warning for active potions'
  1227. , description: "Disable drink button for 3 seconds if the potion is already active"
  1228. , defaultValue: true
  1229. }
  1230. , _a[KEY.showCaptions] = {
  1231. name: 'Show item captions'
  1232. , description: "Show item captions for some items instead of the number of owned items"
  1233. , defaultValue: true
  1234. }
  1235. , _a[KEY.syncPriceHistory] = {
  1236. name: 'Sync price history'
  1237. , description: "Synchronize the local price history"
  1238. , defaultValue: false
  1239. , sub:
  1240. {
  1241. 'url':
  1242. {
  1243. defaultValue: ''
  1244. , label: 'paste url here'
  1245. }
  1246. }
  1247. }
  1248. , _a[KEY.useNewToolbar] = {
  1249. name: 'Use new toolbar'
  1250. , description: "Use new reordered toolbar"
  1251. , defaultValue: true
  1252. , requiresReload: true
  1253. }
  1254. , _a[KEY.changeMachineDialog] = {
  1255. name: 'Use slider for machine dialog'
  1256. , description: "Change buttons in machine dialog into slider"
  1257. , defaultValue: true
  1258. , requiresReload: true
  1259. }
  1260. , _a);
  1261. var SETTINGS_TABLE_ID = 'dh2-settings';
  1262. var SETTING_ID_PREFIX = 'dh2-setting-';
  1263. var settings2Init = Object.keys(CFG);
  1264. /**
  1265. * settings
  1266. */
  1267. function toName(key, subKey)
  1268. {
  1269. var name = typeof key === 'string' ? key : KEY[key];
  1270. if (subKey !== undefined)
  1271. {
  1272. return name + '.' + subKey;
  1273. }
  1274. return name;
  1275. }
  1276.  
  1277. function getStoreKey(key, subKey)
  1278. {
  1279. return 'setting.' + toName(key, subKey);
  1280. }
  1281. var observedSettings = new Map();
  1282. var observedSubSettings = new Map();
  1283.  
  1284. function observe(key, fn)
  1285. {
  1286. var n = toName(key);
  1287. if (!observedSettings.has(n))
  1288. {
  1289. observedSettings.set(n, new Set());
  1290. }
  1291. observedSettings.get(n).add(fn);
  1292. }
  1293. settings.observe = observe;
  1294.  
  1295. function observeSub(key, subKey, fn)
  1296. {
  1297. var n = toName(key, subKey);
  1298. if (!observedSubSettings.has(n))
  1299. {
  1300. observedSubSettings.set(n, new Set());
  1301. }
  1302. observedSubSettings.get(n).add(fn);
  1303. }
  1304. settings.observeSub = observeSub;
  1305.  
  1306. function unobserve(key, fn)
  1307. {
  1308. var n = toName(key);
  1309. if (!observedSettings.has(n))
  1310. {
  1311. return false;
  1312. }
  1313. return observedSettings.get(n).delete(fn);
  1314. }
  1315. settings.unobserve = unobserve;
  1316.  
  1317. function unobserveSub(key, subKey, fn)
  1318. {
  1319. var n = toName(key, subKey);
  1320. if (!observedSubSettings.has(n))
  1321. {
  1322. return false;
  1323. }
  1324. return observedSubSettings.get(n).delete(fn);
  1325. }
  1326. settings.unobserveSub = unobserveSub;
  1327. var settingsProxies = new Map();
  1328.  
  1329. function get(key)
  1330. {
  1331. if (!CFG.hasOwnProperty(key))
  1332. {
  1333. return false;
  1334. }
  1335. if (settingsProxies.has(key))
  1336. {
  1337. var proxy = settingsProxies.get(key);
  1338. return proxy.get(key);
  1339. }
  1340. var name = getStoreKey(key);
  1341. return store.has(name) ? store.get(name) : CFG[key].defaultValue;
  1342. }
  1343. settings.get = get;
  1344.  
  1345. function getSub(key, subKey)
  1346. {
  1347. if (!CFG.hasOwnProperty(key))
  1348. {
  1349. return null;
  1350. }
  1351. var name = getStoreKey(key, subKey);
  1352. var def = CFG[key].sub[subKey].defaultValue;
  1353. if (store.has(name))
  1354. {
  1355. var stored = store.get(name);
  1356. if (def instanceof Array)
  1357. {
  1358. for (var i = 0; i < def.length; i++)
  1359. {
  1360. if (stored.indexOf(def[i]) === -1)
  1361. {
  1362. stored.push(def[i]);
  1363. }
  1364. }
  1365. for (var i = 0; i < stored.length; i++)
  1366. {
  1367. if (def.indexOf(stored[i]) === -1)
  1368. {
  1369. stored.splice(i, 1);
  1370. i--;
  1371. }
  1372. }
  1373. }
  1374. return stored;
  1375. }
  1376. else
  1377. {
  1378. return def;
  1379. }
  1380. }
  1381. settings.getSub = getSub;
  1382.  
  1383. function set(key, newValue)
  1384. {
  1385. if (!CFG.hasOwnProperty(key))
  1386. {
  1387. return;
  1388. }
  1389. var oldValue = get(key);
  1390. var n = toName(key);
  1391. if (settingsProxies.has(key))
  1392. {
  1393. var proxy = settingsProxies.get(key);
  1394. proxy.set(key, oldValue, newValue);
  1395. }
  1396. else
  1397. {
  1398. store.set(getStoreKey(key), newValue);
  1399. }
  1400. if (oldValue !== newValue && observedSettings.has(n))
  1401. {
  1402. observedSettings.get(n).forEach(function (fn)
  1403. {
  1404. return fn(key, oldValue, newValue);
  1405. });
  1406. }
  1407. }
  1408. settings.set = set;
  1409.  
  1410. function setSub(key, subKey, newValue)
  1411. {
  1412. if (!CFG.hasOwnProperty(key))
  1413. {
  1414. return;
  1415. }
  1416. var oldValue = getSub(key, subKey);
  1417. var n = toName(key, subKey);
  1418. store.set(getStoreKey(key, subKey), newValue);
  1419. if (oldValue !== newValue && observedSubSettings.has(n))
  1420. {
  1421. observedSubSettings.get(n).forEach(function (fn)
  1422. {
  1423. return fn(key, subKey, oldValue, newValue);
  1424. });
  1425. }
  1426. }
  1427. settings.setSub = setSub;
  1428.  
  1429. function getSubCfg(key)
  1430. {
  1431. if (!CFG.hasOwnProperty(key))
  1432. {
  1433. return;
  1434. }
  1435. return CFG[key].sub;
  1436. }
  1437. settings.getSubCfg = getSubCfg;
  1438.  
  1439. function initSettingsStyle()
  1440. {
  1441. 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");
  1442. }
  1443.  
  1444. function getSettingId(key, subKey)
  1445. {
  1446. var name = toName(key) + (subKey !== undefined ? '-' + subKey : '');
  1447. return SETTING_ID_PREFIX + split2Words(name, '-').toLowerCase();
  1448. }
  1449.  
  1450. function initSettingTable()
  1451. {
  1452. function insertAfter(newChild, oldChild)
  1453. {
  1454. var parent = oldChild.parentElement;
  1455. if (oldChild.nextElementSibling == null)
  1456. {
  1457. parent.appendChild(newChild);
  1458. }
  1459. else
  1460. {
  1461. parent.insertBefore(newChild, oldChild.nextElementSibling);
  1462. }
  1463. }
  1464.  
  1465. function getCheckImageSrc(value)
  1466. {
  1467. return 'images/icons/' + (value ? 'check' : 'x') + '.png';
  1468. }
  1469. var profileTable = document.getElementById('profile-toggleTable');
  1470. if (!profileTable)
  1471. {
  1472. return;
  1473. }
  1474. var settingsHeader = document.createElement('h2');
  1475. settingsHeader.className = 'section-title';
  1476. 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>";
  1477. var requiresReloadNote = settingsHeader.querySelector('.note');
  1478. insertAfter(settingsHeader, profileTable);
  1479. var settingsTable = document.createElement('table');
  1480. settingsTable.id = SETTINGS_TABLE_ID;
  1481. settingsTable.className = 'table-style1';
  1482. settingsTable.width = '40%';
  1483. 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";
  1484.  
  1485. function addRowClickListener(row, key, settingId)
  1486. {
  1487. row.addEventListener('click', function ()
  1488. {
  1489. var newValue = !get(key);
  1490. set(key, newValue);
  1491. document.getElementById(settingId).src = getCheckImageSrc(newValue);
  1492. });
  1493. }
  1494.  
  1495. function addSubClickListener(btn, dialog)
  1496. {
  1497. btn.addEventListener('click', function (event)
  1498. {
  1499. initJQueryDialog(dialog);
  1500. event.stopPropagation();
  1501. event.preventDefault();
  1502. });
  1503. }
  1504. for (var _i = 0, settings2Init_1 = settings2Init; _i < settings2Init_1.length; _i++)
  1505. {
  1506. var k = settings2Init_1[_i];
  1507. // convert it into a KEY
  1508. var key = parseInt(k, 10);
  1509. var setting = CFG[key];
  1510. if (setting == null)
  1511. {
  1512. console.error('missing setting entry:', key, toName(key));
  1513. continue;
  1514. }
  1515. var settingId = getSettingId(key);
  1516. var row = settingsTable.insertRow(-1);
  1517. row.classList.add('setting');
  1518. if (setting.requiresReload)
  1519. {
  1520. row.classList.add('reload');
  1521. requiresReloadNote.style.display = '';
  1522. }
  1523. row.setAttribute('onclick', '');
  1524. 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";
  1525. if (setting.sub)
  1526. {
  1527. row.classList.add('sub');
  1528. var subBtn = document.createElement('button');
  1529. subBtn.innerHTML = "<img src=\"images/icons/gearOff.gif\" class=\"image-icon-15\">";
  1530. row.cells.item(0).appendChild(subBtn);
  1531. var dialog = createSubSettingDialog(key);
  1532. addSubClickListener(subBtn, dialog);
  1533. }
  1534. var tooltipEl = ensureTooltip(settingId, row);
  1535. tooltipEl.innerHTML = setting.description;
  1536. if (setting.requiresReload)
  1537. {
  1538. 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>";
  1539. }
  1540. addRowClickListener(row, key, settingId);
  1541. }
  1542. insertAfter(settingsTable, settingsHeader);
  1543. }
  1544.  
  1545. function initProxies()
  1546. {
  1547. var row = document.querySelector('tr[data-tooltip-id="tooltip-profile-removeCraftingFilter"]');
  1548. if (row)
  1549. {
  1550. var valueCache_1 = getGameValue('profileRemoveCraftingFilter') != 1;
  1551. settingsProxies.set(KEY.hideCraftingRecipes
  1552. , {
  1553. get: function (key)
  1554. {
  1555. return getGameValue('profileRemoveCraftingFilter') != 1;
  1556. }
  1557. , set: function (key, oldValue, newValue)
  1558. {
  1559. if (valueCache_1 != newValue)
  1560. {
  1561. row.click();
  1562. valueCache_1 = newValue;
  1563. }
  1564. }
  1565. });
  1566. observer.add('profileRemoveCraftingFilter', function ()
  1567. {
  1568. set(KEY.hideCraftingRecipes, getGameValue('profileRemoveCraftingFilter') != 1);
  1569. });
  1570. }
  1571. }
  1572. var subDialog;
  1573. (function (subDialog)
  1574. {
  1575. function defaultHandler(key, dialog)
  1576. {
  1577. var setting = CFG[key];
  1578. var subSettings = setting.sub;
  1579. var settingContainer = createSubSettingsContainer(key, subSettings);
  1580. dialog.appendChild(settingContainer);
  1581. }
  1582.  
  1583. function colorizeChat(dialog)
  1584. {
  1585. defaultHandler(KEY.colorizeChat, dialog);
  1586. }
  1587. subDialog.colorizeChat = colorizeChat;
  1588.  
  1589. function showNotifications(dialog)
  1590. {
  1591. dialog.appendChild(document.createTextNode('Show notifications\u2026'));
  1592. defaultHandler(KEY.showNotifications, dialog);
  1593. dialog.appendChild(document.createTextNode('Events for which notifications are shown:'));
  1594. var ulNotifType = dialog.lastElementChild;
  1595. var ulEvents = ulNotifType.cloneNode(false);
  1596. while (ulNotifType.children.length > 1)
  1597. {
  1598. ulEvents.appendChild(ulNotifType.children.item(1));
  1599. }
  1600. dialog.appendChild(ulEvents);
  1601. }
  1602. subDialog.showNotifications = showNotifications;
  1603.  
  1604. function syncPriceHistory(dialog)
  1605. {
  1606. var setting = CFG[KEY.syncPriceHistory];
  1607. var subSettings = setting.sub;
  1608. var instructionEl = document.createElement('div');
  1609. instructionEl.className = 'instruction';
  1610. 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:";
  1611. dialog.appendChild(instructionEl);
  1612. var settingContainer = createSubSettingsContainer(KEY.syncPriceHistory, subSettings);
  1613. dialog.appendChild(settingContainer);
  1614. }
  1615. subDialog.syncPriceHistory = syncPriceHistory;
  1616. })(subDialog || (subDialog = {}));
  1617.  
  1618. function createSubSettingDialog(key)
  1619. {
  1620. var settingId = getSettingId(key);
  1621. var setting = CFG[key];
  1622. var dialog = document.createElement('div');
  1623. dialog.id = 'dialog-' + settingId;
  1624. dialog.style.display = 'none';
  1625. dialog.innerHTML = "<h2>" + setting.name + "</h2>";
  1626. var name = toName(key);
  1627. if (subDialog.hasOwnProperty(name))
  1628. {
  1629. subDialog[name](dialog);
  1630. }
  1631. else
  1632. {
  1633. console.warn('missing setting handler for "%s"', name);
  1634. var todoEl = document.createElement('span');
  1635. todoEl.textContent = 'TODO';
  1636. dialog.appendChild(todoEl);
  1637. }
  1638. document.body.appendChild(dialog);
  1639. return dialog;
  1640. }
  1641.  
  1642. function createSubSettingsContainer(parentKey, subSettings)
  1643. {
  1644. var settingsContainer = document.createElement('ul');
  1645. settingsContainer.className = 'settings-container';
  1646.  
  1647. function addCheckbox(listEl, subKey, id, setting)
  1648. {
  1649. var checkbox = document.createElement('input');
  1650. checkbox.type = 'checkbox';
  1651. checkbox.id = id;
  1652. checkbox.name = id;
  1653. checkbox.checked = getSub(parentKey, subKey);
  1654. var label = document.createElement('label');
  1655. label.htmlFor = id;
  1656. label.innerHTML = setting.label;
  1657. checkbox.addEventListener('change', function ()
  1658. {
  1659. return setSub(parentKey, subKey, checkbox.checked);
  1660. });
  1661. listEl.appendChild(checkbox);
  1662. listEl.appendChild(label);
  1663. }
  1664.  
  1665. function addSelectmenu(listEl, subKey, id, setting)
  1666. {
  1667. var select = document.createElement('select');
  1668. select.id = id;
  1669. select.name = id;
  1670. var options = setting.options;
  1671. var selectedIndex = getSub(parentKey, subKey);
  1672. for (var i = 0; i < options.length; i++)
  1673. {
  1674. var option = document.createElement('option');
  1675. option.value = options[i];
  1676. if (setting.label)
  1677. {
  1678. option.innerHTML = setting.label[i];
  1679. }
  1680. else
  1681. {
  1682. option.innerHTML = key2Name(options[i]);
  1683. }
  1684. option.selected = i == selectedIndex;
  1685. select.appendChild(option);
  1686. }
  1687. select.addEventListener('change', function ()
  1688. {
  1689. return setSub(parentKey, subKey, select.selectedIndex);
  1690. });
  1691. listEl.appendChild(select);
  1692. }
  1693.  
  1694. function addInput(listEl, subKey, id, setting)
  1695. {
  1696. var input = document.createElement('input');
  1697. input.type = 'text';
  1698. input.placeholder = setting.label || '';
  1699. input.value = getSub(parentKey, subKey);
  1700. var onChange = function ()
  1701. {
  1702. return setSub(parentKey, subKey, input.value);
  1703. };
  1704. input.addEventListener('click', onChange);
  1705. input.addEventListener('change', onChange);
  1706. input.addEventListener('keyup', onChange);
  1707. listEl.appendChild(input);
  1708. }
  1709. var keyList = Object.keys(subSettings);
  1710. var orderIndex = keyList.findIndex(function (k)
  1711. {
  1712. return subSettings[k].defaultValue instanceof Array;
  1713. });
  1714. var isSortable = orderIndex != -1;
  1715. if (isSortable)
  1716. {
  1717. keyList = getSub(parentKey, keyList[orderIndex]);
  1718. }
  1719. for (var _i = 0, keyList_1 = keyList; _i < keyList_1.length; _i++)
  1720. {
  1721. var subKey = keyList_1[_i];
  1722. var settingId = getSettingId(parentKey, subKey);
  1723. var setting = subSettings[subKey];
  1724. var listEl = document.createElement('li');
  1725. listEl.classList.add('setting');
  1726. if (isSortable)
  1727. {
  1728. listEl.dataset.subKey = subKey;
  1729. var sortableIcon = document.createElement('span');
  1730. sortableIcon.className = 'ui-icon ui-icon-arrowthick-2-n-s handle';
  1731. listEl.appendChild(sortableIcon);
  1732. }
  1733. if (setting.options)
  1734. {
  1735. addSelectmenu(listEl, subKey, settingId, setting);
  1736. }
  1737. else if (typeof setting.defaultValue === 'boolean')
  1738. {
  1739. addCheckbox(listEl, subKey, settingId, setting);
  1740. }
  1741. else if (typeof setting.defaultValue === 'string')
  1742. {
  1743. addInput(listEl, subKey, settingId, setting);
  1744. }
  1745. settingsContainer.appendChild(listEl);
  1746. }
  1747. return settingsContainer;
  1748. }
  1749.  
  1750. function initJQueryDialog(dialog)
  1751. {
  1752. var $dialog = win.$(dialog);
  1753. $dialog.dialog(
  1754. {
  1755. width: DIALOG_WIDTH + 'px'
  1756. });
  1757. $dialog.find('input[type="checkbox"]').checkboxradio()
  1758. .next().children(':first-child').removeClass('ui-state-hover');
  1759. $dialog.find('button:not(.sub)').button();
  1760. $dialog.find('input:text').button()
  1761. .addClass('ui-textfield')
  1762. .off('mouseenter').off('mousedown').off('keydown');
  1763. $dialog.find('select').selectmenu(
  1764. {
  1765. change: function (event, ui)
  1766. {
  1767. var changeEvent = document.createEvent('HTMLEvents');
  1768. changeEvent.initEvent('change', false, true);
  1769. event.target.dispatchEvent(changeEvent);
  1770. }
  1771. });
  1772. $dialog.find('.sortable').sortable(
  1773. {
  1774. handle: '.handle'
  1775. , update: function (event, ui)
  1776. {
  1777. var newOrder = [];
  1778. var children = event.target.children;
  1779. for (var i = 0; i < children.length; i++)
  1780. {
  1781. var child = children[i];
  1782. newOrder.push(child.dataset.subKey);
  1783. }
  1784. var updateEvent = new CustomEvent('sortupdate'
  1785. , {
  1786. detail: newOrder
  1787. });
  1788. event.target.dispatchEvent(updateEvent);
  1789. }
  1790. });
  1791. return $dialog;
  1792. }
  1793.  
  1794. function createSettingsContainer(settingList)
  1795. {
  1796. var settingsContainer = document.createElement('ul');
  1797. settingsContainer.className = 'settings-container';
  1798.  
  1799. function addOpenDialogClickListener(el, dialog)
  1800. {
  1801. el.addEventListener('click', function (event)
  1802. {
  1803. initJQueryDialog(dialog);
  1804. event.stopPropagation();
  1805. event.preventDefault();
  1806. });
  1807. }
  1808.  
  1809. function addChangeListener(key, checkbox)
  1810. {
  1811. checkbox.addEventListener('change', function ()
  1812. {
  1813. set(key, checkbox.checked);
  1814. });
  1815. }
  1816. for (var _i = 0, settingList_1 = settingList; _i < settingList_1.length; _i++)
  1817. {
  1818. var key = settingList_1[_i];
  1819. var settingId = getSettingId(key);
  1820. var setting = CFG[key];
  1821. var index = settings2Init.indexOf(key.toString());
  1822. if (index != -1)
  1823. {
  1824. settings2Init.splice(index, 1);
  1825. }
  1826. var listEl = document.createElement('li');
  1827. listEl.classList.add('setting');
  1828. if (setting.requiresReload)
  1829. {
  1830. listEl.classList.add('reload');
  1831. }
  1832. var checkbox = document.createElement('input');
  1833. checkbox.type = 'checkbox';
  1834. checkbox.id = settingId;
  1835. checkbox.checked = get(key);
  1836. var label = document.createElement('label');
  1837. label.htmlFor = settingId;
  1838. label.textContent = setting.name;
  1839. addChangeListener(key, checkbox);
  1840. listEl.appendChild(checkbox);
  1841. listEl.appendChild(label);
  1842. if (setting.sub)
  1843. {
  1844. var moreBtn = document.createElement('button');
  1845. moreBtn.className = 'sub';
  1846. moreBtn.innerHTML = "<img src=\"images/icons/gearOff.gif\" class=\"image-icon-20\" />";
  1847. listEl.appendChild(moreBtn);
  1848. var dialog = createSubSettingDialog(key);
  1849. addOpenDialogClickListener(moreBtn, dialog);
  1850. }
  1851. settingsContainer.appendChild(listEl);
  1852. var tooltipEl = ensureTooltip(settingId, listEl);
  1853. tooltipEl.innerHTML = setting.description;
  1854. if (setting.requiresReload)
  1855. {
  1856. 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>";
  1857. }
  1858. }
  1859. return settingsContainer;
  1860. }
  1861.  
  1862. function initCraftingSettings()
  1863. {
  1864. var craftingItems = document.getElementById('tab-sub-container-crafting');
  1865. if (!craftingItems)
  1866. {
  1867. return;
  1868. }
  1869. var br = craftingItems.nextElementSibling;
  1870. var after = br.nextElementSibling;
  1871. var parent = after.parentElement;
  1872. var settingList = [KEY.hideCraftingRecipes, KEY.hideUselessItems];
  1873. var settingsContainer = createSettingsContainer(settingList);
  1874. parent.insertBefore(settingsContainer, after);
  1875. }
  1876.  
  1877. function initMuteDialog(settingsContainer)
  1878. {
  1879. // muted people dialog
  1880. var dialog = document.createElement('div');
  1881. dialog.id = 'dialog-chat-muted-people';
  1882. dialog.style.display = 'none';
  1883. dialog.innerHTML = "<h2>Muted people</h2>";
  1884. var input = document.createElement('input');
  1885. input.type = 'text';
  1886. input.placeholder = 'username';
  1887. dialog.appendChild(input);
  1888. var addBtn = document.createElement('button');
  1889. addBtn.textContent = '+';
  1890. dialog.appendChild(addBtn);
  1891. var listEl = document.createElement('ul');
  1892. listEl.className = 'settings-container list';
  1893. var username2Item = {};
  1894. var username2Btn = {};
  1895.  
  1896. function removeListener(event)
  1897. {
  1898. var target = event.target;
  1899. var username = target.dataset.username || '';
  1900. var index = win.mutedPeople.indexOf(username);
  1901. if (index !== -1)
  1902. {
  1903. win.mutedPeople.splice(index, 1);
  1904. }
  1905. }
  1906.  
  1907. function add2List(username)
  1908. {
  1909. var item = document.createElement('li');
  1910. item.innerHTML = "<span class=\"content\">" + username + "</span>";
  1911. var removeBtn = document.createElement('button');
  1912. removeBtn.dataset.username = username;
  1913. removeBtn.textContent = '-';
  1914. win.$(removeBtn).button();
  1915. removeBtn.addEventListener('click', removeListener);
  1916. username2Btn[username] = removeBtn;
  1917. item.appendChild(removeBtn);
  1918. username2Item[username] = item;
  1919. listEl.appendChild(item);
  1920. }
  1921. var _push = win.mutedPeople.push;
  1922. win.mutedPeople.push = function ()
  1923. {
  1924. var items = [];
  1925. for (var _i = 0; _i < arguments.length; _i++)
  1926. {
  1927. items[_i] = arguments[_i];
  1928. }
  1929. items.forEach(function (username)
  1930. {
  1931. return add2List(username);
  1932. });
  1933. return _push.call.apply(_push, [win.mutedPeople].concat(items));
  1934. };
  1935. var _splice = win.mutedPeople.splice;
  1936. win.mutedPeople.splice = function (start, deleteCount)
  1937. {
  1938. var items = [];
  1939. for (var _i = 2; _i < arguments.length; _i++)
  1940. {
  1941. items[_i - 2] = arguments[_i];
  1942. }
  1943. for (var i = 0; i < deleteCount; i++)
  1944. {
  1945. var username = win.mutedPeople[start + i];
  1946. var item = username2Item[username];
  1947. delete username2Item[username];
  1948. listEl.removeChild(item);
  1949. var btn = username2Btn[username];
  1950. delete username2Btn[username];
  1951. btn.removeEventListener('click', removeListener);
  1952. }
  1953. items.forEach(function (username)
  1954. {
  1955. return add2List(username);
  1956. });
  1957. return _splice.call.apply(_splice, [win.mutedPeople, start, deleteCount].concat(items));
  1958. };
  1959. dialog.appendChild(listEl);
  1960. addBtn.addEventListener('click', function ()
  1961. {
  1962. win.mutedPeople.push(input.value);
  1963. input.value = '';
  1964. });
  1965. document.body.appendChild(dialog);
  1966. var listItem = document.createElement('li');
  1967. listItem.classList.add('setting');
  1968. var dialogBtn = document.createElement('button');
  1969. dialogBtn.innerHTML = "List of muted people";
  1970. dialogBtn.addEventListener('click', function ()
  1971. {
  1972. initJQueryDialog(dialog);
  1973. });
  1974. listItem.appendChild(dialogBtn);
  1975. settingsContainer.appendChild(listItem);
  1976. }
  1977.  
  1978. function initKeywordDialog(settingsContainer)
  1979. {
  1980. // keyword dialog
  1981. var dialog = document.createElement('div');
  1982. dialog.id = 'dialog-chat-keyword-list';
  1983. dialog.style.display = 'none';
  1984. dialog.innerHTML = "<h2>Keywords</h2>";
  1985. var input = document.createElement('input');
  1986. input.type = 'text';
  1987. input.placeholder = 'keyword';
  1988. dialog.appendChild(input);
  1989. var addBtn = document.createElement('button');
  1990. addBtn.textContent = '+';
  1991. dialog.appendChild(addBtn);
  1992. var listEl = document.createElement('ul');
  1993. listEl.className = 'settings-container list';
  1994.  
  1995. function add2List(keyword)
  1996. {
  1997. var item = document.createElement('li');
  1998. item.innerHTML = "<span class=\"content\">" + keyword + "</span>";
  1999. var removeBtn = document.createElement('button');
  2000. removeBtn.textContent = '-';
  2001. win.$(removeBtn).button();
  2002. var remove = function ()
  2003. {
  2004. if (chat.removeKeyword(keyword))
  2005. {
  2006. listEl.removeChild(item);
  2007. removeBtn.removeEventListener('click', remove);
  2008. }
  2009. };
  2010. removeBtn.addEventListener('click', remove);
  2011. item.appendChild(removeBtn);
  2012. listEl.appendChild(item);
  2013. }
  2014. // add all keywords
  2015. chat.keywordList.forEach(function (keyword)
  2016. {
  2017. return add2List(keyword);
  2018. });
  2019. dialog.appendChild(listEl);
  2020. addBtn.addEventListener('click', function ()
  2021. {
  2022. var keyword = input.value;
  2023. if (chat.addKeyword(keyword))
  2024. {
  2025. add2List(keyword);
  2026. input.value = '';
  2027. }
  2028. });
  2029. document.body.appendChild(dialog);
  2030. var listItem = document.createElement('li');
  2031. listItem.classList.add('setting');
  2032. var dialogBtn = document.createElement('button');
  2033. dialogBtn.innerHTML = "Manage list of keywords";
  2034. dialogBtn.addEventListener('click', function ()
  2035. {
  2036. initJQueryDialog(dialog);
  2037. });
  2038. listItem.appendChild(dialogBtn);
  2039. settingsContainer.appendChild(listItem);
  2040. }
  2041.  
  2042. function initChatSettings()
  2043. {
  2044. var controlDiv = document.querySelector('#div-chat > div:first-child');
  2045. if (!controlDiv)
  2046. {
  2047. return;
  2048. }
  2049. var btn = document.createElement('button');
  2050. btn.textContent = 'Chat Settings';
  2051. controlDiv.appendChild(btn);
  2052. var dialog = document.createElement('div');
  2053. dialog.id = 'dialog-chat-settings';
  2054. dialog.style.display = 'none';
  2055. dialog.innerHTML = "<h2>Chat Settings</h2>";
  2056. var settingList = [KEY.useNewChat, KEY.colorizeChat, KEY.intelligentScrolling, KEY.showTimestamps, KEY.showIcons, KEY.showTags, KEY.enableSpamDetection];
  2057. var settingsContainer = createSettingsContainer(settingList);
  2058. initMuteDialog(settingsContainer);
  2059. initKeywordDialog(settingsContainer);
  2060. dialog.appendChild(settingsContainer);
  2061. document.body.appendChild(dialog);
  2062. btn.addEventListener('click', function ()
  2063. {
  2064. initJQueryDialog(dialog);
  2065. });
  2066. }
  2067.  
  2068. function init()
  2069. {
  2070. initProxies();
  2071. initSettingsStyle();
  2072. initCraftingSettings();
  2073. initChatSettings();
  2074. initSettingTable();
  2075. }
  2076. settings.init = init;
  2077. var _a;
  2078. })(settings || (settings = {}));
  2079. /**
  2080. * Code from https://github.com/davidmerfield/randomColor
  2081. */
  2082. var colorGenerator;
  2083. (function (colorGenerator)
  2084. {
  2085. // seed to get repeatable colors
  2086. var seed = null;
  2087. var COLOR_NOT_FOUND = {
  2088. hueRange: []
  2089. , lowerBounds: []
  2090. , saturationRange: []
  2091. , brightnessRange: []
  2092. };
  2093. var COLOR_BOUNDS = {
  2094. 'monochrome':
  2095. {
  2096. hueRange: []
  2097. , lowerBounds: [
  2098. [0, 0]
  2099. , [100, 0]
  2100. ]
  2101. }
  2102. , 'red':
  2103. {
  2104. hueRange: [-26, 18]
  2105. , lowerBounds: [
  2106. [20, 100]
  2107. , [30, 92]
  2108. , [40, 89]
  2109. , [50, 85]
  2110. , [60, 78]
  2111. , [70, 70]
  2112. , [80, 60]
  2113. , [90, 55]
  2114. , [100, 50]
  2115. ]
  2116. }
  2117. , 'orange':
  2118. {
  2119. hueRange: [19, 46]
  2120. , lowerBounds: [
  2121. [20, 100]
  2122. , [30, 93]
  2123. , [40, 88]
  2124. , [50, 86]
  2125. , [60, 85]
  2126. , [70, 70]
  2127. , [100, 70]
  2128. ]
  2129. }
  2130. , 'yellow':
  2131. {
  2132. hueRange: [47, 62]
  2133. , lowerBounds: [
  2134. [25, 100]
  2135. , [40, 94]
  2136. , [50, 89]
  2137. , [60, 86]
  2138. , [70, 84]
  2139. , [80, 82]
  2140. , [90, 80]
  2141. , [100, 75]
  2142. ]
  2143. }
  2144. , 'green':
  2145. {
  2146. hueRange: [63, 178]
  2147. , lowerBounds: [
  2148. [30, 100]
  2149. , [40, 90]
  2150. , [50, 85]
  2151. , [60, 81]
  2152. , [70, 74]
  2153. , [80, 64]
  2154. , [90, 50]
  2155. , [100, 40]
  2156. ]
  2157. }
  2158. , 'blue':
  2159. {
  2160. hueRange: [179, 257]
  2161. , lowerBounds: [
  2162. [20, 100]
  2163. , [30, 86]
  2164. , [40, 80]
  2165. , [50, 74]
  2166. , [60, 60]
  2167. , [70, 52]
  2168. , [80, 44]
  2169. , [90, 39]
  2170. , [100, 35]
  2171. ]
  2172. }
  2173. , 'purple':
  2174. {
  2175. hueRange: [258, 282]
  2176. , lowerBounds: [
  2177. [20, 100]
  2178. , [30, 87]
  2179. , [40, 79]
  2180. , [50, 70]
  2181. , [60, 65]
  2182. , [70, 59]
  2183. , [80, 52]
  2184. , [90, 45]
  2185. , [100, 42]
  2186. ]
  2187. }
  2188. , 'pink':
  2189. {
  2190. hueRange: [283, 334]
  2191. , lowerBounds: [
  2192. [20, 100]
  2193. , [30, 90]
  2194. , [40, 86]
  2195. , [60, 84]
  2196. , [80, 80]
  2197. , [90, 75]
  2198. , [100, 73]
  2199. ]
  2200. }
  2201. };
  2202. // shared color dictionary
  2203. var colorDictionary = {};
  2204.  
  2205. function defineColor(name, hueRange, lowerBounds)
  2206. {
  2207. var _a = lowerBounds[0]
  2208. , sMin = _a[0]
  2209. , bMax = _a[1];
  2210. var _b = lowerBounds[lowerBounds.length - 1]
  2211. , sMax = _b[0]
  2212. , bMin = _b[1];
  2213. colorDictionary[name] = {
  2214. hueRange: hueRange
  2215. , lowerBounds: lowerBounds
  2216. , saturationRange: [sMin, sMax]
  2217. , brightnessRange: [bMin, bMax]
  2218. };
  2219. }
  2220.  
  2221. function loadColorBounds()
  2222. {
  2223. for (var name_1 in COLOR_BOUNDS)
  2224. {
  2225. defineColor(name_1, COLOR_BOUNDS[name_1].hueRange, COLOR_BOUNDS[name_1].lowerBounds);
  2226. }
  2227. }
  2228.  
  2229. function randomWithin(min, max)
  2230. {
  2231. if (min === void 0)
  2232. {
  2233. min = 0;
  2234. }
  2235. if (max === void 0)
  2236. {
  2237. max = 0;
  2238. }
  2239. if (seed === null)
  2240. {
  2241. return Math.floor(min + Math.random() * (max + 1 - min));
  2242. }
  2243. else
  2244. {
  2245. // seeded random algorithm from http://indiegamr.com/generate-repeatable-random-numbers-in-js/
  2246. seed = (seed * 9301 + 49297) % 233280;
  2247. var rnd = seed / 233280.0;
  2248. return Math.floor(min + rnd * (max - min));
  2249. }
  2250. }
  2251.  
  2252. function getColorInfo(hue)
  2253. {
  2254. // maps red colors to make picking hue easier
  2255. if (hue >= 334 && hue <= 360)
  2256. {
  2257. hue -= 360;
  2258. }
  2259. for (var colorName in colorDictionary)
  2260. {
  2261. var color = colorDictionary[colorName];
  2262. if (color.hueRange.length > 0
  2263. && hue >= color.hueRange[0]
  2264. && hue <= color.hueRange[1])
  2265. {
  2266. return colorDictionary[colorName];
  2267. }
  2268. }
  2269. return COLOR_NOT_FOUND;
  2270. }
  2271.  
  2272. function getHueRange(colorInput)
  2273. {
  2274. var number = typeof colorInput === 'undefined' ? Number.NaN : colorInput;
  2275. if (typeof number === 'string')
  2276. {
  2277. number = parseInt(number, 10);
  2278. }
  2279. if (colorInput && isNaN(number) && colorDictionary.hasOwnProperty(colorInput))
  2280. {
  2281. var color = colorDictionary[colorInput];
  2282. if (color.hueRange.length > 0)
  2283. {
  2284. return color.hueRange;
  2285. }
  2286. }
  2287. else if (!isNaN(number) && number < 360 && number > 0)
  2288. {
  2289. return [number, number];
  2290. }
  2291. return [0, 360];
  2292. }
  2293.  
  2294. function pickHue(options)
  2295. {
  2296. var hueRange = getHueRange(options.hue);
  2297. var hue = randomWithin(hueRange[0], hueRange[1]);
  2298. // instead of storing red as two seperate ranges, we group them, using negative numbers
  2299. if (hue < 0)
  2300. {
  2301. return 360 + hue;
  2302. }
  2303. return hue;
  2304. }
  2305.  
  2306. function getSaturationRange(hue)
  2307. {
  2308. return getColorInfo(hue).saturationRange;
  2309. }
  2310.  
  2311. function pickSaturation(hue, options)
  2312. {
  2313. if (options.luminosity === 'random')
  2314. {
  2315. return randomWithin(0, 100);
  2316. }
  2317. if (options.hue === 'monochrome')
  2318. {
  2319. return 0;
  2320. }
  2321. var _a = getSaturationRange(hue)
  2322. , sMin = _a[0]
  2323. , sMax = _a[1];
  2324. switch (options.luminosity)
  2325. {
  2326. case 'bright':
  2327. sMin = 55;
  2328. break;
  2329. case 'dark':
  2330. sMin = sMax - 10;
  2331. break;
  2332. case 'light':
  2333. sMax = 55;
  2334. break;
  2335. }
  2336. return randomWithin(sMin, sMax);
  2337. }
  2338.  
  2339. function getMinimumBrightness(H, S)
  2340. {
  2341. var lowerBounds = getColorInfo(H).lowerBounds;
  2342. for (var i = 0; i < lowerBounds.length - 1; i++)
  2343. {
  2344. var _a = lowerBounds[i]
  2345. , s1 = _a[0]
  2346. , v1 = _a[1];
  2347. var _b = lowerBounds[i + 1]
  2348. , s2 = _b[0]
  2349. , v2 = _b[1];
  2350. if (S >= s1 && S <= s2)
  2351. {
  2352. var m = (v2 - v1) / (s2 - s1);
  2353. var b = v1 - m * s1;
  2354. return m * S + b;
  2355. }
  2356. }
  2357. return 0;
  2358. }
  2359.  
  2360. function pickBrightness(H, S, options)
  2361. {
  2362. var bMin = getMinimumBrightness(H, S);
  2363. var bMax = 100;
  2364. switch (options.luminosity)
  2365. {
  2366. case 'dark':
  2367. bMax = bMin + 20;
  2368. break;
  2369. case 'light':
  2370. bMin = (bMax + bMin) / 2;
  2371. break;
  2372. case 'random':
  2373. bMin = 0;
  2374. bMax = 100;
  2375. break;
  2376. }
  2377. return randomWithin(bMin, bMax);
  2378. }
  2379. var HSVColor = (function ()
  2380. {
  2381. function HSVColor(H, S, V)
  2382. {
  2383. this.H = H;
  2384. this.S = S;
  2385. this.V = V;
  2386. }
  2387. HSVColor.fromHSVArray = function (hsv)
  2388. {
  2389. return new HSVColor(hsv[0], hsv[1], hsv[2]);
  2390. };
  2391. HSVColor.prototype.toHex = function ()
  2392. {
  2393. var rgb = this.toRGB();
  2394. return '#' + this.componentToHex(rgb[0]) + this.componentToHex(rgb[1]) + this.componentToHex(rgb[2]);
  2395. };
  2396. HSVColor.prototype.toHSL = function ()
  2397. {
  2398. var h = this.H;
  2399. var s = this.S / 100;
  2400. var v = this.V / 100;
  2401. var k = (2 - s) * v;
  2402. return [
  2403. h
  2404. , Math.round(s * v / (k < 1 ? k : 2 - k) * 10e3) / 100
  2405. , k / 2 * 100
  2406. ];
  2407. };
  2408. HSVColor.prototype.toHSLString = function (alpha)
  2409. {
  2410. var hsl = this.toHSL();
  2411. if (alpha !== undefined)
  2412. {
  2413. return "hsla(" + hsl[0] + ", " + hsl[1] + "%, " + hsl[2] + "%, " + alpha + ")";
  2414. }
  2415. else
  2416. {
  2417. return "hsl(" + hsl[0] + ", " + hsl[1] + "%, " + hsl[2] + "%)";
  2418. }
  2419. };
  2420. HSVColor.prototype.toRGB = function ()
  2421. {
  2422. // this doesn't work for the values of 0 and 360 here's the hacky fix
  2423. var h = Math.min(Math.max(this.H, 1), 359);
  2424. // Rebase the h,s,v values
  2425. h = h / 360;
  2426. var s = this.S / 100;
  2427. var v = this.V / 100;
  2428. var h_i = Math.floor(h * 6);
  2429. var f = h * 6 - h_i;
  2430. var p = v * (1 - s);
  2431. var q = v * (1 - f * s);
  2432. var t = v * (1 - (1 - f) * s);
  2433. var r = 256;
  2434. var g = 256;
  2435. var b = 256;
  2436. switch (h_i)
  2437. {
  2438. case 0:
  2439. r = v;
  2440. g = t;
  2441. b = p;
  2442. break;
  2443. case 1:
  2444. r = q;
  2445. g = v;
  2446. b = p;
  2447. break;
  2448. case 2:
  2449. r = p;
  2450. g = v;
  2451. b = t;
  2452. break;
  2453. case 3:
  2454. r = p;
  2455. g = q;
  2456. b = v;
  2457. break;
  2458. case 4:
  2459. r = t;
  2460. g = p;
  2461. b = v;
  2462. break;
  2463. case 5:
  2464. r = v;
  2465. g = p;
  2466. b = q;
  2467. break;
  2468. }
  2469. return [Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)];
  2470. };
  2471. HSVColor.prototype.toRGBString = function (alpha)
  2472. {
  2473. var rgb = this.toRGB();
  2474. if (alpha !== undefined)
  2475. {
  2476. return "rgba(" + rgb.join(', ') + ", " + alpha + ")";
  2477. }
  2478. else
  2479. {
  2480. return "rgb(" + rgb.join(', ') + ")";
  2481. }
  2482. };
  2483. HSVColor.prototype.componentToHex = function (c)
  2484. {
  2485. var hex = c.toString(16);
  2486. return hex.length == 1 ? '0' + hex : hex;
  2487. };
  2488. return HSVColor;
  2489. }());
  2490. colorGenerator.HSVColor = HSVColor;
  2491.  
  2492. function setFormat(hsv, options)
  2493. {
  2494. var color = HSVColor.fromHSVArray(hsv);
  2495. switch (options.format)
  2496. {
  2497. case 'object':
  2498. return color;
  2499. case 'hsvArray':
  2500. return hsv;
  2501. case 'hslArray':
  2502. return color.toHSL();
  2503. case 'hsl':
  2504. return color.toHSLString();
  2505. case 'hsla':
  2506. return color.toHSLString(options.alpha || Math.random());
  2507. case 'rgbArray':
  2508. return color.toRGB();
  2509. case 'rgb':
  2510. return color.toRGBString();
  2511. case 'rgba':
  2512. return color.toRGBString(options.alpha || Math.random());
  2513. case 'hex':
  2514. default:
  2515. return color.toHex();
  2516. }
  2517. }
  2518.  
  2519. function generateColor(options)
  2520. {
  2521. // pick a hue (H)
  2522. var H = pickHue(options);
  2523. // use H to determine saturation (S)
  2524. var S = pickSaturation(H, options);
  2525. // use S and H to determine brightness (B)
  2526. var B = pickBrightness(H, S, options);
  2527. // return the HSB color in the desired format
  2528. return setFormat([H, S, B], options);
  2529. }
  2530.  
  2531. function getRandom(options)
  2532. {
  2533. options = options ||
  2534. {};
  2535. seed = options.seed == null ? null : options.seed;
  2536. // check if we need to generate multiple colors
  2537. if (options.count !== null && options.count !== undefined)
  2538. {
  2539. var colors = [];
  2540. while (options.count > colors.length)
  2541. {
  2542. // Since we're generating multiple colors, the seed has to be incrememented.
  2543. // Otherwise we'd just generate the same color each time...
  2544. if (seed !== null)
  2545. {
  2546. seed += 1;
  2547. }
  2548. colors.push(generateColor(options));
  2549. }
  2550. return colors;
  2551. }
  2552. return generateColor(options);
  2553. }
  2554. colorGenerator.getRandom = getRandom;
  2555. var ColorInterval = (function ()
  2556. {
  2557. function ColorInterval(start, end)
  2558. {
  2559. this.start = start;
  2560. this.end = end;
  2561. this.left = null;
  2562. this.right = null;
  2563. this.value = null;
  2564. }
  2565. ColorInterval.prototype.getNextValue = function ()
  2566. {
  2567. if (this.value == null)
  2568. {
  2569. this.value = (this.start + this.end) / 2;
  2570. return this.value;
  2571. }
  2572. if (this.left == null)
  2573. {
  2574. this.left = new ColorInterval(this.start, this.value);
  2575. return this.left.getNextValue();
  2576. }
  2577. if (this.right == null)
  2578. {
  2579. this.right = new ColorInterval(this.value, this.end);
  2580. return this.right.getNextValue();
  2581. }
  2582. if (this.left.getHeight() <= this.right.getHeight())
  2583. {
  2584. return this.left.getNextValue();
  2585. }
  2586. else
  2587. {
  2588. return this.right.getNextValue();
  2589. }
  2590. };
  2591. ColorInterval.prototype.getHeight = function ()
  2592. {
  2593. return 1
  2594. + (this.left == null ? 0 : this.left.getHeight())
  2595. + (this.right == null ? 0 : this.right.getHeight());
  2596. };
  2597. return ColorInterval;
  2598. }());
  2599. colorGenerator.ColorInterval = ColorInterval;
  2600. var defaultRootInterval = new ColorInterval(0, 360);
  2601.  
  2602. function getEquallyDistributed(rootInterval)
  2603. {
  2604. if (rootInterval === void 0)
  2605. {
  2606. rootInterval = defaultRootInterval;
  2607. }
  2608. return 'hsl(' + rootInterval.getNextValue() + ', 100%, 80%)';
  2609. }
  2610. colorGenerator.getEquallyDistributed = getEquallyDistributed;
  2611. var Color = (function ()
  2612. {
  2613. function Color(r, g, b)
  2614. {
  2615. this.r = r;
  2616. this.g = g;
  2617. this.b = b;
  2618. }
  2619. Color.fromHex = function (hex)
  2620. {
  2621. return new Color(parseInt(hex.substr(1, 2), 16), parseInt(hex.substr(3, 2), 16), parseInt(hex.substr(5, 2), 16));
  2622. };
  2623. Color.fromRgb = function (rgb)
  2624. {
  2625. var match = rgb.match(this.rgbRegex);
  2626. return new Color(parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3], 10));
  2627. };
  2628. Color.fromString = function (str)
  2629. {
  2630. if (this.hexRegex.test(str))
  2631. {
  2632. return this.fromHex(str);
  2633. }
  2634. else if (this.rgbRegex.test(str))
  2635. {
  2636. return this.fromRgb(str);
  2637. }
  2638. else
  2639. {
  2640. throw new Error('Unexpected color format: ' + str);
  2641. }
  2642. };
  2643. Color.prototype.toString = function (hex)
  2644. {
  2645. if (hex === void 0)
  2646. {
  2647. hex = true;
  2648. }
  2649. return '#' + this.toHex(this.r) + this.toHex(this.g) + this.toHex(this.b);
  2650. };
  2651. Color.prototype.toHex = function (x)
  2652. {
  2653. var xStr = x.toString(16);
  2654. return (xStr.length == 1 ? '0' : '') + xStr;
  2655. };
  2656. Color.hexRegex = /^#(?:[0-9a-f]{3}){1,2}$/i;
  2657. Color.rgbRegex = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i;
  2658. return Color;
  2659. }());
  2660.  
  2661. function ratioColor(color1, color2, ratio)
  2662. {
  2663. 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));
  2664. return color.toString();
  2665. }
  2666.  
  2667. function getColorTransition(value, colorStrings)
  2668. {
  2669. var smallerValue = -1;
  2670. var biggerValue = Number.MAX_SAFE_INTEGER;
  2671. var colors = {};
  2672. for (var v in colorStrings)
  2673. {
  2674. var vNum = Number(v);
  2675. if (vNum === value)
  2676. {
  2677. return colorStrings[v];
  2678. }
  2679. else if (vNum < value)
  2680. {
  2681. smallerValue = Math.max(smallerValue, vNum);
  2682. }
  2683. else
  2684. {
  2685. biggerValue = Math.min(biggerValue, vNum);
  2686. }
  2687. colors[v] = Color.fromString(colorStrings[v]);
  2688. }
  2689. if (smallerValue === -1)
  2690. {
  2691. return colorStrings[biggerValue];
  2692. }
  2693. if (biggerValue === Number.MAX_SAFE_INTEGER)
  2694. {
  2695. return colorStrings[smallerValue];
  2696. }
  2697. var ratio = (value - smallerValue) / (biggerValue - smallerValue);
  2698. return ratioColor(colors[smallerValue], colors[biggerValue], ratio);
  2699. }
  2700. colorGenerator.getColorTransition = getColorTransition;
  2701. // populate the color dictionary
  2702. loadColorBounds();
  2703. })(colorGenerator || (colorGenerator = {}));
  2704.  
  2705. /**
  2706. * provides icons
  2707. */
  2708. var icons;
  2709. (function (icons)
  2710. {
  2711. 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';
  2712. 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"/>';
  2713.  
  2714. function getSvgAsUrl(svg)
  2715. {
  2716. return "url('data:image/svg+xml;base64," + btoa(svg) + "')";
  2717. }
  2718. icons.getSvgAsUrl = getSvgAsUrl;
  2719.  
  2720. function wrapCodeWithSvg(code, viewBox, width, height)
  2721. {
  2722. return "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"" + width + "\" height=\"" + height + "\" viewBox=\"" + viewBox + "\">" + code + "</svg>";
  2723. }
  2724. icons.wrapCodeWithSvg = wrapCodeWithSvg;
  2725.  
  2726. function getMd(pathDots, color, width, height)
  2727. {
  2728. if (color === void 0)
  2729. {
  2730. color = 'black';
  2731. }
  2732. if (width === void 0)
  2733. {
  2734. width = '30';
  2735. }
  2736. if (height === void 0)
  2737. {
  2738. height = '30';
  2739. }
  2740. return getSvgAsUrl(wrapCodeWithSvg("<path fill=\"" + color + "\" d=\"" + pathDots + "\" />", '0 0 24 24', width, height));
  2741. }
  2742. icons.getMd = getMd;
  2743. })(icons || (icons = {}));
  2744.  
  2745. /**
  2746. * notifications
  2747. */
  2748. var notifications;
  2749. (function (notifications)
  2750. {
  2751. notifications.name = 'notifications';
  2752.  
  2753. function event(title, options)
  2754. {
  2755. if ((!options || options.whenActive !== true)
  2756. && !document.hidden && document.hasFocus()
  2757. && settings.getSub(settings.KEY.showNotifications, 'showType') !== 1)
  2758. {
  2759. return;
  2760. }
  2761. if (!settings.get(settings.KEY.showNotifications))
  2762. {
  2763. // notifications disabled: return stub notification
  2764. return Promise.resolve(
  2765. {
  2766. close: function () {}
  2767. });
  2768. }
  2769. if (!("Notification" in win))
  2770. {
  2771. return Promise.reject('Your browser does not support notifications.');
  2772. }
  2773. return Notification.requestPermission()
  2774. .then(function (permission)
  2775. {
  2776. if (permission === 'granted')
  2777. {
  2778. var n_1 = new Notification(title, options);
  2779. n_1.onclick = function (event)
  2780. {
  2781. if (options && options.autoFocus !== false)
  2782. {
  2783. win.focus();
  2784. }
  2785. if (options && options.autoClose !== false)
  2786. {
  2787. n_1.close();
  2788. }
  2789. if (options && options.onclick)
  2790. {
  2791. options.onclick(n_1, event);
  2792. }
  2793. };
  2794. return Promise.resolve(n_1);
  2795. }
  2796. else
  2797. {
  2798. return Promise.reject('Notification permission denied');
  2799. }
  2800. });
  2801. }
  2802. notifications.event = event;
  2803.  
  2804. function requestPermission()
  2805. {
  2806. if (settings.get(settings.KEY.showNotifications))
  2807. {
  2808. Notification.requestPermission();
  2809. }
  2810. }
  2811.  
  2812. function init()
  2813. {
  2814. requestPermission();
  2815. settings.observe(settings.KEY.showNotifications, function ()
  2816. {
  2817. return requestPermission();
  2818. });
  2819. }
  2820. notifications.init = init;
  2821. })(notifications || (notifications = {}));
  2822.  
  2823. /**
  2824. * process commands
  2825. */
  2826. var commands;
  2827. (function (commands)
  2828. {
  2829. var XP_GAIN_KEY = 'xpGain';
  2830. var MAX_XP_GAIN_HISTORY_LENGTH = 100;
  2831. var IMAGE2SKILL = {
  2832. // mining = #cc0000
  2833. 'icons/pickaxe': 'mining'
  2834. // crafting = #cc0000
  2835. , 'icons/anvil': 'crafting'
  2836. // woodcutting = cyan
  2837. , 'icons/woodcutting': 'woodcutting'
  2838. // farming = green
  2839. , 'icons/watering-can': 'farming'
  2840. // brewing = #800080
  2841. , 'vialOfWater': 'brewing'
  2842. , 'largeVialOfWater': 'brewing'
  2843. , 'hugeVialOfWater': 'brewing'
  2844. // combat = lime
  2845. , 'icons/combat': 'combat'
  2846. // magic = blue
  2847. , 'icons/wizardhat': 'magic'
  2848. // fishing = blue
  2849. , 'tuna': 'fishing'
  2850. // cooking = yellow
  2851. , 'icons/cooking': 'cooking'
  2852. };
  2853. var xpGainHistory = store.has(XP_GAIN_KEY) ? store.get(XP_GAIN_KEY) :
  2854. {};
  2855. addStyle("\n.scroller.xp\n{\n\tfont-size: 18pt;\n\tposition: absolute;\n\ttext-align: center;\n}\n\t");
  2856.  
  2857. function minutes2String(data)
  2858. {
  2859. return data.replace(/Your account has been running for: (\d+) minutes./, function (wholeMatch, minutes)
  2860. {
  2861. return 'Your account has been running for ' + format.min2Str(minutes) + '.';
  2862. });
  2863. }
  2864. var LOOT_MSG_PREFIX = 'SHOW_LOOT_DIAG=';
  2865.  
  2866. function processLoot(data)
  2867. {
  2868. if (!/^SM=Your boat found nothing\.$|^SHOW_LOOT_DIAG=/.test(data))
  2869. {
  2870. return false;
  2871. }
  2872. var loot = {
  2873. type: 'loot'
  2874. , title: ''
  2875. , itemList: []
  2876. };
  2877. if (data.startsWith('SM='))
  2878. {
  2879. loot.title = 'Boat';
  2880. loot.emptyText = 'Your boat found nothing.';
  2881. }
  2882. else if (data.startsWith(LOOT_MSG_PREFIX))
  2883. {
  2884. var split = data.substr(LOOT_MSG_PREFIX.length).split('~');
  2885. loot.title = split[0];
  2886. for (var i = 1; i < split.length; i += 2)
  2887. {
  2888. loot.itemList.push(
  2889. {
  2890. icon: split[i]
  2891. , text: split[i + 1]
  2892. });
  2893. }
  2894. }
  2895. log.add(loot);
  2896. return true;
  2897. }
  2898. var XP_GAIN_REGEX = /^ST=([^~]+)\.png~([^~]+)~\+(\d+)\s*xp(.*)$/;
  2899. var animationQueue = {};
  2900.  
  2901. function queueXpAnimation(skill, cell, color, xpAmount, extraXp)
  2902. {
  2903. if (!settings.get(settings.KEY.newXpAnimation))
  2904. {
  2905. return;
  2906. }
  2907. animationQueue[skill] = animationQueue[skill] || [];
  2908. animationQueue[skill].push(
  2909. {
  2910. cell: cell
  2911. , color: color
  2912. , xpAmount: xpAmount
  2913. , extraXp: extraXp
  2914. });
  2915. if (animationQueue[skill].length === 1)
  2916. {
  2917. nextAnimation(skill);
  2918. }
  2919. }
  2920.  
  2921. function nextAnimation(skill)
  2922. {
  2923. var entry = animationQueue[skill][0];
  2924. if (!entry || !settings.get(settings.KEY.newXpAnimation))
  2925. {
  2926. return;
  2927. }
  2928. var cell = entry.cell
  2929. , color = entry.color
  2930. , xpAmount = entry.xpAmount
  2931. , extraXp = entry.extraXp;
  2932. var rect = cell.getBoundingClientRect();
  2933. var extraXpStr = extraXp > 0 ? " (+" + extraXp + ")" : '';
  2934. 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>")
  2935. .appendTo('body');
  2936. // ensure the existence of $el, so the complete-function can be called instantly if the window is hidden
  2937. $el
  2938. .animate(
  2939. {
  2940. top: '-=15px'
  2941. }
  2942. , {
  2943. duration: 1500
  2944. , easing: 'easeOutQuad'
  2945. , complete: function ()
  2946. {
  2947. animationQueue[skill].shift();
  2948. nextAnimation(skill);
  2949. }
  2950. })
  2951. .fadeOut(
  2952. {
  2953. duration: 2500
  2954. , queue: false
  2955. , complete: function ()
  2956. {
  2957. return $el.remove();
  2958. }
  2959. });
  2960. }
  2961.  
  2962. function processXpGain(data)
  2963. {
  2964. var match = data.match(XP_GAIN_REGEX);
  2965. if (!match)
  2966. {
  2967. return false;
  2968. }
  2969. var icon = match[1];
  2970. var skill = IMAGE2SKILL[icon] || '';
  2971. var color = match[2];
  2972. var xpAmount = Number(match[3]);
  2973. var extra = match[4];
  2974. var cell = document.getElementById('top-bar-level-td-' + skill);
  2975. if (!cell)
  2976. {
  2977. console.debug('match (no cell found):', match);
  2978. return false;
  2979. }
  2980. var entry = {
  2981. time: now()
  2982. , amount: xpAmount
  2983. };
  2984. if (match[4])
  2985. {
  2986. entry.extra = match[4];
  2987. }
  2988. if (skill == 'fishing')
  2989. {
  2990. log.processFishingXpChange(xpAmount);
  2991. }
  2992. var extraXp = 0;
  2993. if (extra && settings.get(settings.KEY.newXpAnimation))
  2994. {
  2995. var extraMatch = extra.match(/^\s*\(<img[^>]+src=(['"])images\/([^']+)\.png\1[^>]+>\s*(.+)\)$/);
  2996. var extraXpMatch = extra.match(/^\s*\(\+(\d+)\s*xp\)\s*$/);
  2997. if (extraMatch)
  2998. {
  2999. var icon_1 = extraMatch[2];
  3000. var text = extraMatch[3];
  3001. if (icon_1 == 'brewingKit')
  3002. {
  3003. text = '+' + text;
  3004. }
  3005. win.scrollText(icon_1, color, text);
  3006. }
  3007. else if (extraXpMatch)
  3008. {
  3009. extraXp = Number(extraXpMatch[1]);
  3010. }
  3011. else
  3012. {
  3013. win.scrollText('none', color, extra);
  3014. }
  3015. }
  3016. // save the xp event
  3017. var list = xpGainHistory[skill] || [];
  3018. list.push(entry);
  3019. xpGainHistory[skill] = list.slice(-MAX_XP_GAIN_HISTORY_LENGTH);
  3020. store.set(XP_GAIN_KEY, xpGainHistory);
  3021. if (settings.get(settings.KEY.newXpAnimation))
  3022. {
  3023. queueXpAnimation(skill, cell, color, xpAmount, extraXp);
  3024. }
  3025. return true;
  3026. }
  3027.  
  3028. function processLevelUp(data)
  3029. {
  3030. if (!data.startsWith('LVL_UP='))
  3031. {
  3032. return false;
  3033. }
  3034. var skill = data.substr('LVL_UP='.length);
  3035. var xp = getGameValue(skill + 'Xp');
  3036. var oldLvl = win.getLevel(xp);
  3037. log.add(
  3038. {
  3039. type: 'lvlup'
  3040. , skill: skill
  3041. , newLevel: oldLvl + 1
  3042. });
  3043. return true;
  3044. }
  3045.  
  3046. function processCombat(data)
  3047. {
  3048. var match = data.match(/^STHS=([^~]+)~([^~]+)~([^~]+)~img-(.+)~(melee|heal)$/);
  3049. if (!match)
  3050. {
  3051. return false;
  3052. }
  3053. // keep track of different battles and add the data to the current battle
  3054. var number = match[3];
  3055. if (!/\D/.test(number))
  3056. {
  3057. number = Number(number);
  3058. }
  3059. log.add(
  3060. {
  3061. type: 'combat'
  3062. , what: match[5]
  3063. , who: match[4]
  3064. , text: number
  3065. });
  3066. return true;
  3067. }
  3068.  
  3069. function processEnergy(data)
  3070. {
  3071. var match = data.match(/^ST=steak\.png~orange~\+([\d',]+)$/);
  3072. if (!match)
  3073. {
  3074. return false;
  3075. }
  3076. log.add(
  3077. {
  3078. type: 'energy'
  3079. , energy: Number(match[1].replace(/\D/g, ''))
  3080. });
  3081. return true;
  3082. }
  3083.  
  3084. function processHeat(data)
  3085. {
  3086. var match = data.match(/^ST=icons\/fire\.png~red~\+([\d',]+)$/);
  3087. if (!match)
  3088. {
  3089. return false;
  3090. }
  3091. log.add(
  3092. {
  3093. type: 'heat'
  3094. , heat: Number(match[1].replace(/\D/g, ''))
  3095. });
  3096. return true;
  3097. }
  3098.  
  3099. function processMarket(data)
  3100. {
  3101. if (data === 'ST=icons/shop.png~orange~Item Purchased')
  3102. {
  3103. log.add(
  3104. {
  3105. type: 'market'
  3106. });
  3107. return true;
  3108. }
  3109. var match = data.match(/^ST=coins\.png~yellow~\+([\d',]+)$/);
  3110. if (!match)
  3111. {
  3112. return false;
  3113. }
  3114. var coins = Number(match[1].replace(/\D/g, ''));
  3115. log.add(
  3116. {
  3117. type: 'market'
  3118. , coins: coins
  3119. });
  3120. return true;
  3121. }
  3122.  
  3123. function processBonemeal(data)
  3124. {
  3125. var match = data.match(/^ST=filledBonemealBin\.png~white~\+([\d',]+)$/);
  3126. if (!match)
  3127. {
  3128. return false;
  3129. }
  3130. var bonemeal = Number(match[1].replace(/\D/g, ''));
  3131. log.add(
  3132. {
  3133. type: 'bonemeal'
  3134. , bonemeal: bonemeal
  3135. });
  3136. return true;
  3137. }
  3138.  
  3139. function processCrafting(data)
  3140. {
  3141. if (data === 'ST=none~#806600~Item Crafted')
  3142. {
  3143. log.add(
  3144. {
  3145. type: 'crafting'
  3146. });
  3147. return true;
  3148. }
  3149. return false;
  3150. }
  3151.  
  3152. function processStardust(data)
  3153. {
  3154. var match = data.match(/^ST=(?:icons\/)?stardust\.png~yellow~\+([\d',]+)$/);
  3155. if (!match)
  3156. {
  3157. return false;
  3158. }
  3159. var stardust = Number(match[1].replace(/\D/g, ''));
  3160. log.add(
  3161. {
  3162. type: 'stardust'
  3163. , stardust: stardust
  3164. });
  3165. return true;
  3166. }
  3167. var RUNNING_ACCOUNT_STR = 'Your account has been running for:';
  3168.  
  3169. function formatData(data)
  3170. {
  3171. if (data.startsWith('STHS=')
  3172. || data.startsWith('STE=')
  3173. || data.startsWith('SM=')
  3174. || data.startsWith('ST=')
  3175. || data.startsWith('SHOW_LOOT_DIAG='))
  3176. {
  3177. if (data.indexOf(RUNNING_ACCOUNT_STR) != -1)
  3178. {
  3179. data = minutes2String(data);
  3180. }
  3181. data = format.numbersInText(data);
  3182. }
  3183. return data;
  3184. }
  3185. commands.formatData = formatData;
  3186.  
  3187. function process(data)
  3188. {
  3189. // prepare for logging events in an activity log
  3190. if (processLoot(data))
  3191. {
  3192. return;
  3193. }
  3194. else if (processXpGain(data))
  3195. {
  3196. // return undefined to let the original function be called
  3197. return settings.get(settings.KEY.newXpAnimation) ? null : void 0;
  3198. }
  3199. else if (processLevelUp(data)
  3200. || processCombat(data)
  3201. || processEnergy(data)
  3202. || processHeat(data)
  3203. || processMarket(data)
  3204. || processBonemeal(data)
  3205. || processCrafting(data)
  3206. || processStardust(data))
  3207. {
  3208. return;
  3209. }
  3210. else if (data.startsWith('SM='))
  3211. {
  3212. log.add(
  3213. {
  3214. data: minutes2String(data.replace(/^[^=]+=/, ''))
  3215. });
  3216. }
  3217. else if (data.startsWith('STHS=') || data.startsWith('STE=') || data.startsWith('ST='))
  3218. {}
  3219. // notifications for this kind of message: "SM=An update has been scheduled for today."
  3220. if (data.startsWith('SM='))
  3221. {
  3222. if (settings.getSub(settings.KEY.showNotifications, 'serverMsg'))
  3223. {
  3224. var msg = data.substr(3)
  3225. .replace(/<br\s*\/?>/g, '\n')
  3226. .replace(/<img src='images\/(.+?)\.png'.+?\/?> (\d+)/g, function (wholeMatch, key, amount)
  3227. {
  3228. return format.number(amount) + ' ' + split2Words(key) + ', ';
  3229. })
  3230. .replace(/<.+?>/g, '')
  3231. .replace(/(\s)\1+/g, '$1')
  3232. .replace(/, $/, '');
  3233. notifications.event('Message from server'
  3234. , {
  3235. body: minutes2String(msg)
  3236. });
  3237. }
  3238. }
  3239. return;
  3240. }
  3241. commands.process = process;
  3242. })(commands || (commands = {}));
  3243.  
  3244. /**
  3245. * log activities and stuff
  3246. */
  3247. var log;
  3248. (function (log)
  3249. {
  3250. log.name = 'log';
  3251. var LOG_KEY = 'activityLog';
  3252. var MAX_LOG_SIZE = 100;
  3253. var logList = store.has(LOG_KEY) ? store.get(LOG_KEY) : [];
  3254. var currentCombat = null;
  3255. var currentCombatEl = null;
  3256. var LOG_FILTER = {
  3257. 'combat':
  3258. {
  3259. title: 'Combat'
  3260. , img: 'images/icons/combat.png'
  3261. }
  3262. , 'loot':
  3263. {
  3264. title: 'Loot'
  3265. , img: 'images/npcLoot0.png'
  3266. }
  3267. , 'fish':
  3268. {
  3269. title: 'Caught fish'
  3270. , img: 'images/tuna.png'
  3271. }
  3272. , 'skill':
  3273. {
  3274. title: 'Skill advance'
  3275. , img: 'images/icons/skills.png'
  3276. }
  3277. , 'other':
  3278. {
  3279. title: 'All other'
  3280. , label: 'Other'
  3281. }
  3282. };
  3283. var logEl;
  3284.  
  3285. function isFightStarted()
  3286. {
  3287. return win.fightMonsterId !== 0;
  3288. }
  3289.  
  3290. function saveLog()
  3291. {
  3292. store.set(LOG_KEY, logList);
  3293. }
  3294.  
  3295. function createLi(entry)
  3296. {
  3297. var entryEl = document.createElement('li');
  3298. entryEl.dataset.time = (new Date(entry.time || 0)).toLocaleString();
  3299. entryEl.dataset.type = entry.type;
  3300. return entryEl;
  3301. }
  3302.  
  3303. function appendLi(entryEl)
  3304. {
  3305. var filterEl = logEl.firstElementChild;
  3306. var next = filterEl && filterEl.nextElementSibling;
  3307. if (next)
  3308. {
  3309. logEl.insertBefore(entryEl, next);
  3310. }
  3311. else
  3312. {
  3313. logEl.appendChild(entryEl);
  3314. }
  3315. logEl.classList.remove('empty');
  3316. }
  3317.  
  3318. function setGenericEntry(entry, init)
  3319. {
  3320. var el = createLi(entry);;
  3321. el.innerHTML = typeof entry.data === 'string' ? format.numbersInText(entry.data) : JSON.stringify(entry.data);
  3322. appendLi(el);
  3323. }
  3324.  
  3325. function setLootEntry(entry, init)
  3326. {
  3327. var el = createLi(entry);
  3328. var header = document.createElement('h1');
  3329. header.className = 'container-title';
  3330. header.textContent = entry.title;
  3331. el.appendChild(header);
  3332. var itemContainer = document.createElement('span');
  3333. if (entry.itemList.length === 0)
  3334. {
  3335. itemContainer.innerHTML = "<span class=\"dialogue-loot\">" + entry.emptyText + "</span>";
  3336. }
  3337. else
  3338. {
  3339. var update = false;
  3340. for (var _i = 0, _a = entry.itemList; _i < _a.length; _i++)
  3341. {
  3342. var item = _a[_i];
  3343. if (item.hasOwnProperty('key'))
  3344. {
  3345. item.icon = item.key;
  3346. delete item.key;
  3347. update = true;
  3348. }
  3349. if (item.hasOwnProperty('amount'))
  3350. {
  3351. item.text = (item.amount || Number.NaN).toString();
  3352. delete item.amount;
  3353. update = true;
  3354. }
  3355. var itemEl = document.createElement('span');
  3356. itemEl.className = 'dialogue-loot';
  3357. itemEl.innerHTML = "<img src=\"" + item.icon + "\" class=\"image-icon-50\"> " + format.numbersInText(item.text);
  3358. itemContainer.appendChild(itemEl);
  3359. itemContainer.appendChild(document.createTextNode(' '));
  3360. }
  3361. if (update)
  3362. {
  3363. saveLog();
  3364. }
  3365. }
  3366. el.appendChild(itemContainer);
  3367. var valueContainer = document.createElement('div');
  3368. valueContainer.className = 'total-value';
  3369. valueContainer.appendChild(document.createTextNode('Total value: '));
  3370. var totalValue = document.createElement('span');
  3371. totalValue.style.cursor = 'pointer';
  3372. totalValue.textContent = 'Click to calculate';
  3373. valueContainer.appendChild(totalValue);
  3374. totalValue.addEventListener('click', function ()
  3375. {
  3376. var items = {};
  3377. for (var _i = 0, _a = entry.itemList; _i < _a.length; _i++)
  3378. {
  3379. var item = _a[_i];
  3380. if (item.text.indexOf('xp') === -1)
  3381. {
  3382. var key = item.icon.replace(/^.+\/([^\/]+)\.png$/, '$1');
  3383. var num = Number(item.text.replace(/\D/g, ''));
  3384. items[key] = (items[key] || 0) + num;
  3385. }
  3386. }
  3387. market.calcMarketValue(items)
  3388. .then(function (sum)
  3389. {
  3390. 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]);
  3391. });
  3392. });
  3393. el.appendChild(valueContainer);
  3394. appendLi(el);
  3395. }
  3396.  
  3397. function setFishEntry(entry, init)
  3398. {
  3399. var el = createLi(entry);
  3400. el.innerHTML = "You caught a " + key2Name(entry.fish, true) + ".";
  3401. appendLi(el);
  3402. }
  3403.  
  3404. function setEnergyEntry(entry, init)
  3405. {
  3406. var el = createLi(entry);
  3407. el.innerHTML = "Your hero gained " + format.number(entry.energy) + " energy.";
  3408. appendLi(el);
  3409. }
  3410.  
  3411. function setHeatEntry(entry, init)
  3412. {
  3413. var el = createLi(entry);
  3414. el.innerHTML = "You added " + format.number(entry.heat) + " heat to your oven.";
  3415. appendLi(el);
  3416. }
  3417.  
  3418. function setLevelUpEntry(entry, init)
  3419. {
  3420. var el = createLi(entry);
  3421. el.innerHTML = "You advanced your " + entry.skill + " skill to level " + entry.newLevel + ".";
  3422. appendLi(el);
  3423. }
  3424.  
  3425. function getCombatInfo(data, initHp, scaleX, width)
  3426. {
  3427. var points = [];
  3428. var startHp = -1;
  3429. var hp = initHp;
  3430. for (var tick in data)
  3431. {
  3432. hp = data[tick];
  3433. if (startHp === -1)
  3434. {
  3435. startHp = hp;
  3436. }
  3437. points.push((scaleX * Number(tick)) + ' ' + hp);
  3438. }
  3439. if (points.length === 0)
  3440. {
  3441. points.push('0 ' + initHp);
  3442. }
  3443. points.push(width + ' ' + hp, width + ' 0', '0 0');
  3444. return {
  3445. points: points
  3446. , startHp: startHp === -1 ? initHp : startHp
  3447. , endHp: hp
  3448. };
  3449. }
  3450.  
  3451. function getHTMLFromCombatInfo(info, name)
  3452. {
  3453. 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>";
  3454. }
  3455.  
  3456. function setCombatEntry(entry, init)
  3457. {
  3458. var created = init || currentCombatEl == null;
  3459. if (init || currentCombatEl == null)
  3460. {
  3461. currentCombatEl = createLi(entry);
  3462. }
  3463. var HTML = '';
  3464. // support old log format
  3465. if (!entry.hasOwnProperty('ticks'))
  3466. {
  3467. var info = {
  3468. hero:
  3469. {
  3470. heal: 0
  3471. , melee: 0
  3472. }
  3473. , monster:
  3474. {
  3475. heal: 0
  3476. , melee: 0
  3477. }
  3478. };
  3479. for (var i = 0; i < entry.parts.length; i++)
  3480. {
  3481. var part = entry.parts[i];
  3482. info[part.who][part.type] += part.number;
  3483. }
  3484. 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>";
  3485. }
  3486. else
  3487. {
  3488. var currentTick = Math.max(entry.ticks, 0);
  3489. var width = logEl.scrollWidth - 4 * 12.8 - 2;
  3490. var scaleX = currentTick === 0 ? 0 : width / currentTick;
  3491. var hero = getCombatInfo(entry.hero, win.heroHp, scaleX, width);
  3492. var monster = getCombatInfo(entry.monster, win.fightMonsterHp, scaleX, width);
  3493. // TODO: who won?
  3494. 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";
  3495. }
  3496. // map monster name and area name from monster id (the ids are starting at 1)
  3497. var isShiny = entry.monsterId > 1e3;
  3498. var mId = entry.monsterId - (isShiny ? 1001 : 1);
  3499. var monsterName = (isShiny ? 'Shiny ' : '') + (getMonsterName(mId) || '(' + (mId % 3 + 1) + ')');
  3500. var areaId = (mId == 105 || mId == 106) ? 34 : Math.floor(mId / 3);
  3501. var areaName = getAreaName(areaId) || '(' + (areaId + 1) + ')';
  3502. currentCombatEl.innerHTML = "<h2>Combat against " + monsterName + " in " + areaName + "</h2>\n\t\t" + HTML;
  3503. if (created)
  3504. {
  3505. appendLi(currentCombatEl);
  3506. }
  3507. if (!isFightStarted())
  3508. {
  3509. currentCombatEl = null;
  3510. }
  3511. }
  3512.  
  3513. function setMarketEntry(entry, init)
  3514. {
  3515. var el = createLi(entry);
  3516. if (entry.coins)
  3517. {
  3518. el.innerHTML = "You collected " + format.number(entry.coins) + " from market.";
  3519. }
  3520. else
  3521. {
  3522. el.innerHTML = "You purchased an item on market.";
  3523. }
  3524. appendLi(el);
  3525. }
  3526.  
  3527. function setBonemealEntry(entry, init)
  3528. {
  3529. var el = createLi(entry);
  3530. el.innerHTML = "You added " + format.number(entry.bonemeal) + " bonemeal to your bonemeal bin.";
  3531. appendLi(el);
  3532. }
  3533.  
  3534. function setCraftingEntry(entry, init)
  3535. {
  3536. var el = createLi(entry);
  3537. el.innerHTML = "You crafted an item.";
  3538. appendLi(el);
  3539. }
  3540.  
  3541. function setStardustEntry(entry, init)
  3542. {
  3543. var el = createLi(entry);
  3544. el.innerHTML = "You got " + format.number(entry.stardust) + " stardust.";
  3545. appendLi(el);
  3546. }
  3547. var entryType2Fn = {
  3548. 'loot': setLootEntry
  3549. , 'fish': setFishEntry
  3550. , 'energy': setEnergyEntry
  3551. , 'heat': setHeatEntry
  3552. , 'lvlup': setLevelUpEntry
  3553. , 'combat': setCombatEntry
  3554. , 'market': setMarketEntry
  3555. , 'bonemeal': setBonemealEntry
  3556. , 'crafting': setCraftingEntry
  3557. , 'stardust': setStardustEntry
  3558. };
  3559.  
  3560. function updateLog(entry, init)
  3561. {
  3562. if (init === void 0)
  3563. {
  3564. init = false;
  3565. }
  3566. if (!logEl)
  3567. {
  3568. return;
  3569. }
  3570. if (entry.type && entryType2Fn.hasOwnProperty(entry.type))
  3571. {
  3572. entryType2Fn[entry.type](entry, init);
  3573. }
  3574. else
  3575. {
  3576. setGenericEntry(entry, init);
  3577. }
  3578. }
  3579.  
  3580. function add2Log(entry)
  3581. {
  3582. logList.push(entry);
  3583. logList = logList.slice(-MAX_LOG_SIZE);
  3584. saveLog();
  3585. }
  3586. // 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
  3587. function findCurrentCombat()
  3588. {
  3589. for (var i = logList.length - 1; i >= 0; i--)
  3590. {
  3591. if (logList[i].type == 'combat')
  3592. {
  3593. var entry = logList[i];
  3594. if (entry.monsterId == win.fightMonsterId
  3595. && entry.hero[entry.ticks] !== 0
  3596. && entry.hero[entry.ticks] !== 0)
  3597. {
  3598. return entry;
  3599. }
  3600. break;
  3601. }
  3602. }
  3603. return null;
  3604. }
  3605.  
  3606. function add(entry)
  3607. {
  3608. if (!entry.time)
  3609. {
  3610. entry.time = now();
  3611. }
  3612. if (entry.type == 'combat')
  3613. {
  3614. currentCombat = currentCombat || findCurrentCombat();
  3615. if (!currentCombat)
  3616. {
  3617. return;
  3618. }
  3619. // skip entries without further information
  3620. if (typeof entry.text !== 'number' || entry.text === 0)
  3621. {
  3622. return;
  3623. }
  3624. var hp = entry.who == 'hero' ? win.heroHp : win.fightMonsterHp;
  3625. // the hp values are updated after this event, so I have to calculate the new value by myself
  3626. hp += (entry.what == 'heal' ? 1 : -1) * entry.text;
  3627. currentCombat[entry.who][currentCombat.ticks] = hp;
  3628. saveLog();
  3629. updateLog(currentCombat);
  3630. }
  3631. else
  3632. {
  3633. add2Log(entry);
  3634. updateLog(entry);
  3635. }
  3636. }
  3637. log.add = add;
  3638.  
  3639. function addLogEl()
  3640. {
  3641. 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");
  3642. // add new tab "Activity Log"
  3643. var checkboxId = 'show-activity-log';
  3644. var activityLogLabel = document.createElement('label');
  3645. activityLogLabel.id = 'activity-log-label';
  3646. activityLogLabel.htmlFor = checkboxId;
  3647. activityLogLabel.textContent = 'Activity Log';
  3648. newTopbar.addTabEntry(activityLogLabel);
  3649. var checkbox = document.createElement('input');
  3650. checkbox.id = checkboxId;
  3651. checkbox.type = 'checkbox';
  3652. checkbox.style.display = 'none';
  3653. document.body.insertBefore(checkbox, document.body.firstChild);
  3654. var label = document.createElement('label');
  3655. label.id = 'activity-log-overlay';
  3656. label.htmlFor = checkboxId;
  3657. document.body.appendChild(label);
  3658. logEl = document.createElement('ul');
  3659. logEl.id = 'activity-log';
  3660. var classList = [];
  3661. var html = '';
  3662. for (var key in LOG_FILTER)
  3663. {
  3664. // TODO: load saved filter
  3665. var checked = true;
  3666. classList.push(key);
  3667. 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' : '') + ">";
  3668. }
  3669. logEl.className = 'empty ' + classList.join(' ');
  3670. logEl.innerHTML = "<li class=\"filter\">\n\t\t\t" + html + "\n\t\t</li>";
  3671. document.body.appendChild(logEl);
  3672. var $checkboxes = win.$('li.filter > input[id^="log-filter-"]');
  3673. $checkboxes.checkboxradio(
  3674. {
  3675. icon: false
  3676. });
  3677. $checkboxes.change(function (event)
  3678. {
  3679. var id = event.target.id;
  3680. var key = id.replace('log-filter-', '');
  3681. var checked = document.getElementById(id).checked;
  3682. logEl.classList[checked ? 'add' : 'remove'](key);
  3683. // TODO: save current state
  3684. });
  3685. // add all stored elements
  3686. logList.forEach(function (e)
  3687. {
  3688. return updateLog(e, true);
  3689. });
  3690. }
  3691.  
  3692. function observeCombat()
  3693. {
  3694. observer.add('fightMonsterId', function (key, oldValue, newValue)
  3695. {
  3696. if (isFightStarted())
  3697. {
  3698. currentCombat = {
  3699. type: 'combat'
  3700. , time: now()
  3701. , monsterId: newValue
  3702. , ticks: -5
  3703. , hero:
  3704. {}
  3705. , monster:
  3706. {}
  3707. };
  3708. add2Log(currentCombat);
  3709. updateLog(currentCombat);
  3710. }
  3711. else
  3712. {
  3713. if (currentCombat)
  3714. {
  3715. currentCombat.ticks--;
  3716. saveLog();
  3717. }
  3718. currentCombat = null;
  3719. currentCombatEl = null;
  3720. }
  3721. });
  3722. observer.addTick(function ()
  3723. {
  3724. if (currentCombat !== null)
  3725. {
  3726. currentCombat.ticks++;
  3727. if (currentCombat.ticks === 0)
  3728. {
  3729. currentCombat.hero[0] = win.heroHp;
  3730. currentCombat.monster[0] = win.fightMonsterHp;
  3731. }
  3732. updateLog(currentCombat);
  3733. }
  3734. });
  3735. }
  3736. var possiblyCaughtFish;
  3737. var lastFishingXpChange = 0;
  3738.  
  3739. function fishObserver(key, oldValue, newValue)
  3740. {
  3741. if (oldValue < newValue && lastFishingXpChange >= now() - 5e3)
  3742. {
  3743. var idx = possiblyCaughtFish.indexOf(key);
  3744. if (idx !== -1)
  3745. {
  3746. add(
  3747. {
  3748. type: 'fish'
  3749. , fish: key
  3750. });
  3751. possiblyCaughtFish = [];
  3752. lastFishingXpChange = 0;
  3753. }
  3754. }
  3755. }
  3756.  
  3757. function processFishingXpChange(xp)
  3758. {
  3759. lastFishingXpChange = now();
  3760. possiblyCaughtFish = [];
  3761. for (var fish in FISH_XP)
  3762. {
  3763. if (FISH_XP[fish] == xp)
  3764. {
  3765. possiblyCaughtFish.push(fish);
  3766. }
  3767. }
  3768. }
  3769. log.processFishingXpChange = processFishingXpChange;
  3770.  
  3771. function observeFishing()
  3772. {
  3773. for (var fish in FISH_XP)
  3774. {
  3775. observer.add(fish, fishObserver);
  3776. }
  3777. }
  3778.  
  3779. function init()
  3780. {
  3781. addLogEl();
  3782. observeCombat();
  3783. observeFishing();
  3784. }
  3785. log.init = init;
  3786. })(log || (log = {}));
  3787.  
  3788. /**
  3789. * game events
  3790. */
  3791. var gameEvents;
  3792. (function (gameEvents)
  3793. {
  3794. gameEvents.name = 'gameEvents';
  3795. // min time difference between two notifications with the same title (10 seconds)
  3796. var MIN_TIME_DIFFERENCE = 10;
  3797. gameEvents.enabled = {
  3798. smelting: true
  3799. , chopping: true
  3800. , harvest: true
  3801. , boat: true
  3802. , battle: true
  3803. , brewing: true
  3804. , market: true
  3805. , map: true
  3806. //, essence: true
  3807. , rocket: true
  3808. , wind: true
  3809. , perk: true
  3810. };
  3811. var lastTimestamp = new Map();
  3812.  
  3813. function notifyTabClickable(title, body, icon, tabKey, whenActive)
  3814. {
  3815. if (whenActive === void 0)
  3816. {
  3817. whenActive = false;
  3818. }
  3819. var now = (new Date).getTime();
  3820. var timeDiff = now - (lastTimestamp.get(title) || 0);
  3821. if (timeDiff < MIN_TIME_DIFFERENCE * 1e3)
  3822. {
  3823. return;
  3824. }
  3825. var promise = notifications.event(title
  3826. , {
  3827. body: body
  3828. , icon: 'images/' + icon
  3829. , whenActive: whenActive
  3830. , onclick: function ()
  3831. {
  3832. var tabNames = tabKey.split('.');
  3833. win.openTab(tabNames[0]);
  3834. if (tabNames.length > 1)
  3835. {
  3836. win.openSubTab(tabNames[1]);
  3837. }
  3838. }
  3839. });
  3840. if (promise)
  3841. {
  3842. lastTimestamp.set(title, now);
  3843. }
  3844. }
  3845.  
  3846. function observeTimer(k, fn)
  3847. {
  3848. observer.add(k, function (key, oldValue, newValue)
  3849. {
  3850. if (oldValue > 0 && newValue == 0)
  3851. {
  3852. fn(key, oldValue, newValue);
  3853. }
  3854. });
  3855. }
  3856.  
  3857. function smelting()
  3858. {
  3859. observeTimer('smeltingPercD', function (key, oldValue, newValue)
  3860. {
  3861. if (!gameEvents.enabled.smelting || !settings.getSub(settings.KEY.showNotifications, 'smelting'))
  3862. {
  3863. return;
  3864. }
  3865. notifyTabClickable('Hot topic', 'Your smelting has finished.', getFurnaceLevelName() + 'Furnace.png', 'crafting');
  3866. });
  3867. }
  3868.  
  3869. function chopping()
  3870. {
  3871. observer.add([
  3872. 'treeStage1'
  3873. , 'treeStage2'
  3874. , 'treeStage3'
  3875. , 'treeStage4'
  3876. , 'treeStage5'
  3877. , 'treeStage6'
  3878. ], function (key, oldValue, newValue)
  3879. {
  3880. if (!gameEvents.enabled.chopping || !settings.getSub(settings.KEY.showNotifications, 'chopping'))
  3881. {
  3882. return;
  3883. }
  3884. if (newValue == 4)
  3885. {
  3886. notifyTabClickable('Wood you be mine?', 'One or more of your trees are fully grown and can be chopped.', 'icons/woodcutting.png', 'woodcutting');
  3887. }
  3888. });
  3889. }
  3890.  
  3891. function harvest()
  3892. {
  3893. observer.add([
  3894. 'farmingPatchStage1'
  3895. , 'farmingPatchStage2'
  3896. , 'farmingPatchStage3'
  3897. , 'farmingPatchStage4'
  3898. , 'farmingPatchStage5'
  3899. , 'farmingPatchStage6'
  3900. ], function (key, oldValue, newValue)
  3901. {
  3902. if (!gameEvents.enabled.harvest || !settings.getSub(settings.KEY.showNotifications, 'harvest'))
  3903. {
  3904. return;
  3905. }
  3906. if (newValue == 4)
  3907. {
  3908. notifyTabClickable('Green thumb', 'One or more of your crops is ready for harvest.', 'icons/watering-can.png', 'farming');
  3909. }
  3910. else if (newValue > 4)
  3911. {
  3912. notifyTabClickable('I didn\'t plant this', 'One or more of your crops died.', 'icons/watering-can.png', 'farming');
  3913. }
  3914. });
  3915. }
  3916.  
  3917. function boat()
  3918. {
  3919. var timerKeys = BOAT_LIST.map(function (boatKey)
  3920. {
  3921. return boatKey + 'Timer';
  3922. });
  3923. observeTimer(timerKeys, function (key, oldValue, newValue)
  3924. {
  3925. if (!gameEvents.enabled.boat || !settings.getSub(settings.KEY.showNotifications, 'boatReturned'))
  3926. {
  3927. return;
  3928. }
  3929. var boatKey = key.replace(/Timer$/, '');
  3930. notifyTabClickable('Fishy business', 'Your ' + split2Words(boatKey).toLowerCase() + ' returned from its trip.', boatKey + '.png', 'combat');
  3931. });
  3932. }
  3933.  
  3934. function battle()
  3935. {
  3936. observeTimer('combatGlobalCooldown', function (key, oldValue, newValue)
  3937. {
  3938. if (!gameEvents.enabled.battle || !settings.getSub(settings.KEY.showNotifications, 'heroReady'))
  3939. {
  3940. return;
  3941. }
  3942. notifyTabClickable('Ready to work', 'Your hero is eager to fight.', 'icons/combat.png', 'combat');
  3943. });
  3944. }
  3945.  
  3946. function brewing()
  3947. {
  3948. observeTimer([
  3949. 'barPotionTimer'
  3950. , 'seedPotionTimer'
  3951. , 'stardustPotionTimer'
  3952. , 'superStardustPotionTimer'
  3953. ], function (key, oldValue, newValue)
  3954. {
  3955. if (!gameEvents.enabled.brewing || !settings.getSub(settings.KEY.showNotifications, 'potionEffect'))
  3956. {
  3957. return;
  3958. }
  3959. var potionKey = key.replace(/Timer$/, '');
  3960. if (getGameValue(potionKey) > 0)
  3961. {
  3962. notifyTabClickable('Cheers!', 'You can drink another ' + split2Words(potionKey) + '.', key.replace(/Timer$/, '') + '.png', 'brewing');
  3963. }
  3964. });
  3965. }
  3966.  
  3967. function market()
  3968. {
  3969. var _refreshMarketSlot = win.refreshMarketSlot;
  3970. var lastCollectText = 0;
  3971. win.refreshMarketSlot = function (offerId, itemKey, amount, price, collectText, slotId, timeLeft)
  3972. {
  3973. var diff = collectText - lastCollectText;
  3974. lastCollectText = collectText;
  3975. if (gameEvents.enabled.market && settings.getSub(settings.KEY.showNotifications, 'itemsSold') && collectText > 0)
  3976. {
  3977. var soldAmount = diff / price;
  3978. var amountText = ['one (1)', 'two (2)', 'three (3)'][soldAmount - 1] || format.number(soldAmount);
  3979. var itemName = split2Words(itemKey).toLowerCase();
  3980. if (soldAmount > 1)
  3981. {
  3982. itemName = pluralize(itemName);
  3983. }
  3984. var textTemplate = function (itemText)
  3985. {
  3986. return "You've sold " + itemText + " to the market.";
  3987. };
  3988. if (amount > 0)
  3989. {
  3990. notifyTabClickable('Ka-ching', textTemplate(amountText + ' ' + itemName), 'icons/shop.png', 'playermarket');
  3991. }
  3992. else
  3993. {
  3994. notifyTabClickable('Sold out', textTemplate((soldAmount === 1 ? 'your' : 'all') + ' ' + amountText + ' ' + itemName), 'icons/shop.png', 'playermarket');
  3995. }
  3996. }
  3997. _refreshMarketSlot(offerId, itemKey, amount, price, collectText, slotId, timeLeft);
  3998. };
  3999. }
  4000.  
  4001. function gameValues()
  4002. {
  4003. observer.add('treasureMap', function (key, oldValue, newValue)
  4004. {
  4005. if (gameEvents.enabled.map && settings.getSub(settings.KEY.showNotifications, 'pirate') && oldValue < newValue)
  4006. {
  4007. notifyTabClickable('Arrrr!', 'Your pirate found a treasure map.', 'treasureMap.png', 'items');
  4008. }
  4009. });
  4010. observer.add('rocketMoonId', function (key, oldValue, newValue)
  4011. {
  4012. if (gameEvents.enabled.rocket && settings.getSub(settings.KEY.showNotifications, 'rocket'))
  4013. {
  4014. if (newValue > 0)
  4015. {
  4016. notifyTabClickable('One small step for a man...', 'Your rocket landed on the moon.', 'rocket.png', 'mining');
  4017. }
  4018. else if (oldValue < 0 && newValue === 0)
  4019. {
  4020. notifyTabClickable('Back home', 'Your rocket returned to earth.', 'rocket.png', 'mining');
  4021. }
  4022. }
  4023. });
  4024. var WIND_DESCRIPTION = [
  4025. 'The sea is sleeping like a baby'
  4026. , 'There is a slight breeze'
  4027. , 'A normal day on the sea'
  4028. , 'There is a storm coming'
  4029. , 'The sea is raging'
  4030. ];
  4031. var WIND_CATEGORY = ['none', 'low', 'medium', 'high', 'very high'];
  4032. var _setSailBoatWind = win.setSailBoatWind;
  4033. var oldValue = -1;
  4034. win.setSailBoatWind = function (windLevel)
  4035. {
  4036. _setSailBoatWind(windLevel);
  4037. var newValue = win.sailBoatWindGlobal;
  4038. if (oldValue !== -1
  4039. && oldValue !== newValue
  4040. && win.boundSailBoat > 0
  4041. && gameEvents.enabled.wind
  4042. && settings.getSub(settings.KEY.showNotifications, 'wind'))
  4043. {
  4044. var windText = (WIND_DESCRIPTION[win.sailBoatWindGlobal] || 'The wind is turning')
  4045. + ' (' + (WIND_CATEGORY[win.sailBoatWindGlobal] || 'level ' + win.sailBoatWindGlobal) + ' wind).';
  4046. notifyTabClickable('Wind of change', windText, 'sailBoat.png', 'combat');
  4047. }
  4048. oldValue = newValue;
  4049. };
  4050. // trigger getting the wind level once at page load
  4051. // so the script can distinguish between getting the wind initially and an actual wind change
  4052. win.processTab('combat');
  4053. // achievements (e.g. achBrewingEasyCompleted)
  4054. var achRegex = /^ach([A-Z][a-z]+)([A-Z][a-z]+)Completed$/;
  4055.  
  4056. function checkAchievement(key, oldValue, newValue)
  4057. {
  4058. if (gameEvents.enabled.perk && settings.getSub(settings.KEY.showNotifications, 'perk') && oldValue < newValue)
  4059. {
  4060. var match = key.match(/^ach([A-Z][a-z]+)([A-Z][a-z]+)Completed$/);
  4061. var skillName = match[1].toLowerCase();
  4062. var difficulty = match[2].toLowerCase();
  4063. notifyTabClickable('New perk unlocked', 'You completed the ' + difficulty + ' ' + skillName + ' achievement set.', 'achievementBook.png', 'achievements');
  4064. }
  4065. }
  4066. for (var _i = 0, _a = win.jsItemArray; _i < _a.length; _i++)
  4067. {
  4068. var key = _a[_i];
  4069. if (achRegex.test(key))
  4070. {
  4071. observer.add(key, checkAchievement);
  4072. }
  4073. }
  4074. var stardustEl = document.querySelector('span[data-item-display="stardust"]');
  4075. var parent = stardustEl && stardustEl.parentElement;
  4076. if (stardustEl && parent)
  4077. {
  4078. 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");
  4079. var changeEl_1 = document.createElement('span');
  4080. changeEl_1.className = 'hide';
  4081. changeEl_1.id = 'stardust-change';
  4082. parent.appendChild(changeEl_1);
  4083. var HIDE_AFTER_TICKS_1 = 5;
  4084. var ticksSinceSdChange_1 = HIDE_AFTER_TICKS_1;
  4085. var sdDiff_1 = 0;
  4086. observer.add('stardust', function (key, oldValue, newValue)
  4087. {
  4088. sdDiff_1 = Math.max(newValue - oldValue, 0);
  4089. if (sdDiff_1 > 0)
  4090. {
  4091. ticksSinceSdChange_1 = 0;
  4092. }
  4093. });
  4094. observer.addTick(function ()
  4095. {
  4096. var show = settings.get(settings.KEY.showSdChange) && ticksSinceSdChange_1 < HIDE_AFTER_TICKS_1;
  4097. changeEl_1.classList[show ? 'remove' : 'add']('hide');
  4098. ticksSinceSdChange_1++;
  4099. var diff = ticksSinceSdChange_1 > 1 ? 0 : sdDiff_1;
  4100. var sign = diff > 0 ? '+' : PLUS_MINUS_SIGN;
  4101. changeEl_1.textContent = '(' + sign + format.number(diff) + ')';
  4102. });
  4103. }
  4104. }
  4105.  
  4106. function init()
  4107. {
  4108. smelting();
  4109. chopping();
  4110. harvest();
  4111. boat();
  4112. battle();
  4113. brewing();
  4114. market();
  4115. gameValues();
  4116. }
  4117. gameEvents.init = init;
  4118. })(gameEvents || (gameEvents = {}));
  4119.  
  4120. /**
  4121. * hide crafting recipes of lower tiers or of maxed machines
  4122. */
  4123. var crafting;
  4124. (function (crafting)
  4125. {
  4126. crafting.name = 'crafting';
  4127. /**
  4128. * hide crafted recipes
  4129. */
  4130. function setRecipeVisibility(key, visible)
  4131. {
  4132. var recipeRow = document.getElementById('crafting-' + key);
  4133. if (recipeRow)
  4134. {
  4135. recipeRow.style.display = (!settings.get(settings.KEY.hideCraftingRecipes) || visible) ? '' : 'none';
  4136. }
  4137. }
  4138.  
  4139. function hideLeveledRecipes(max, getKey, init)
  4140. {
  4141. if (init === void 0)
  4142. {
  4143. init = false;
  4144. }
  4145. var keys2Observe = [];
  4146. var maxLevel = 0;
  4147. for (var i = max - 1; i >= 0; i--)
  4148. {
  4149. var level = i + 1;
  4150. var key = getKey(i);
  4151. var boundKey = getBoundKey(key);
  4152. keys2Observe.push(key);
  4153. keys2Observe.push(boundKey);
  4154. if (getGameValue(key) > 0 || getGameValue(boundKey) > 0)
  4155. {
  4156. maxLevel = Math.max(maxLevel, level);
  4157. }
  4158. setRecipeVisibility(key, level > maxLevel);
  4159. }
  4160. if (init)
  4161. {
  4162. observer.add(keys2Observe, function ()
  4163. {
  4164. return hideLeveledRecipes(max, getKey, false);
  4165. });
  4166. }
  4167. }
  4168.  
  4169. function hideToolRecipe(key, init)
  4170. {
  4171. if (init === void 0)
  4172. {
  4173. init = false;
  4174. }
  4175. var emptyKey = getTierKey(key, 0);
  4176. var keys2Observe = [emptyKey];
  4177. var hasTool = getGameValue(emptyKey) > 0;
  4178. for (var i = 0; i < TIER_LEVELS.length; i++)
  4179. {
  4180. var boundKey = getBoundKey(getTierKey(key, i));
  4181. hasTool = hasTool || getGameValue(boundKey) > 0;
  4182. keys2Observe.push(boundKey);
  4183. }
  4184. setRecipeVisibility(emptyKey, !hasTool);
  4185. if (init)
  4186. {
  4187. observer.add(keys2Observe, function ()
  4188. {
  4189. return hideToolRecipe(key, false);
  4190. });
  4191. }
  4192. }
  4193.  
  4194. function hideRecipe(key, init)
  4195. {
  4196. if (init === void 0)
  4197. {
  4198. init = false;
  4199. }
  4200. var info = RECIPE_MAX.crafting[key];
  4201. var maxValue = typeof info.max === 'function' ? info.max() : info.max;
  4202. var boundKey = getBoundKey(key);
  4203. var unbound = getGameValue(key);
  4204. var bound = getGameValue(boundKey);
  4205. var extra = (info.extraKeys || []).map(function (k)
  4206. {
  4207. return getGameValue(k);
  4208. }).reduce(function (p, c)
  4209. {
  4210. return p + c;
  4211. }, 0);
  4212. setRecipeVisibility(key, maxValue - (bound + unbound + extra) > 0);
  4213. if (init)
  4214. {
  4215. observer.add([key, boundKey], function ()
  4216. {
  4217. return hideRecipe(key, false);
  4218. });
  4219. }
  4220. }
  4221. /**
  4222. * hide useless items
  4223. */
  4224. function setItemVisibility(key, visible)
  4225. {
  4226. var itemBox = document.getElementById('item-box-' + key);
  4227. if (itemBox)
  4228. {
  4229. itemBox.style.display = getGameValue(key) > 0 && (!settings.get(settings.KEY.hideUselessItems) || visible) ? '' : 'none';
  4230. }
  4231. }
  4232.  
  4233. function hideLeveledItems(max, getKey, init)
  4234. {
  4235. if (init === void 0)
  4236. {
  4237. init = false;
  4238. }
  4239. var keys2Observe = [];
  4240. var maxLevel = 0;
  4241. for (var i = max - 1; i >= 0; i--)
  4242. {
  4243. var level = i + 1;
  4244. var key = getKey(i);
  4245. var boundKey = getBoundKey(key);
  4246. keys2Observe.push(key);
  4247. keys2Observe.push(boundKey);
  4248. if (getGameValue(boundKey) > 0)
  4249. {
  4250. maxLevel = Math.max(maxLevel, level);
  4251. }
  4252. setItemVisibility(key, level > maxLevel);
  4253. }
  4254. if (init)
  4255. {
  4256. observer.add(keys2Observe, function ()
  4257. {
  4258. return hideLeveledItems(max, getKey, false);
  4259. });
  4260. }
  4261. }
  4262.  
  4263. function hideItem(key, hideInfo, init)
  4264. {
  4265. if (init === void 0)
  4266. {
  4267. init = false;
  4268. }
  4269. var maxValue = typeof hideInfo.max === 'function' ? hideInfo.max() : hideInfo.max;
  4270. var boundKey = getBoundKey(key);
  4271. var bound = getGameValue(boundKey);
  4272. var extra = (hideInfo.extraKeys || []).map(function (k)
  4273. {
  4274. return getGameValue(k);
  4275. }).reduce(function (p, c)
  4276. {
  4277. return p + c;
  4278. }, 0);
  4279. setItemVisibility(key, (bound + extra) < maxValue);
  4280. if (init)
  4281. {
  4282. observer.add([key, boundKey], function ()
  4283. {
  4284. return hideItem(key, hideInfo, false);
  4285. });
  4286. }
  4287. }
  4288.  
  4289. function init()
  4290. {
  4291. function processRecipes(init)
  4292. {
  4293. if (init === void 0)
  4294. {
  4295. init = false;
  4296. }
  4297. // furnace
  4298. hideLeveledRecipes(FURNACE_LEVELS.length, function (i)
  4299. {
  4300. return FURNACE_LEVELS[i] + 'Furnace';
  4301. }, init);
  4302. // oil storage
  4303. hideLeveledRecipes(OIL_STORAGE_SIZES.length, function (i)
  4304. {
  4305. return 'oilStorage' + (i + 1);
  4306. }, init);
  4307. // oven recipes
  4308. hideLeveledRecipes(OVEN_LEVELS.length, function (i)
  4309. {
  4310. return OVEN_LEVELS[i] + 'Oven';
  4311. }, init);
  4312. // tools
  4313. for (var _i = 0, TIER_ITEMS_1 = TIER_ITEMS; _i < TIER_ITEMS_1.length; _i++)
  4314. {
  4315. var tool = TIER_ITEMS_1[_i];
  4316. hideToolRecipe(tool, init);
  4317. }
  4318. // other stuff
  4319. for (var key in RECIPE_MAX.crafting)
  4320. {
  4321. hideRecipe(key, init);
  4322. }
  4323. if (init)
  4324. {
  4325. settings.observe(settings.KEY.hideCraftingRecipes, function ()
  4326. {
  4327. return processRecipes(false);
  4328. });
  4329. }
  4330. }
  4331. processRecipes(true);
  4332. var _processCraftingTab = win.processCraftingTab;
  4333. win.processCraftingTab = function ()
  4334. {
  4335. var reinit = !!win.refreshLoadCraftingTable;
  4336. _processCraftingTab();
  4337. if (reinit)
  4338. {
  4339. processRecipes(false);
  4340. }
  4341. };
  4342.  
  4343. function processItems(init)
  4344. {
  4345. if (init === void 0)
  4346. {
  4347. init = false;
  4348. }
  4349. // furnace
  4350. hideLeveledItems(FURNACE_LEVELS.length, function (i)
  4351. {
  4352. return FURNACE_LEVELS[i] + 'Furnace';
  4353. }, init);
  4354. // oil storage
  4355. hideLeveledItems(OIL_STORAGE_SIZES.length, function (i)
  4356. {
  4357. return 'oilStorage' + (i + 1);
  4358. }, init);
  4359. // oven recipes
  4360. hideLeveledItems(OVEN_LEVELS.length, function (i)
  4361. {
  4362. return OVEN_LEVELS[i] + 'Oven';
  4363. }, init);
  4364. // other stuff
  4365. for (var key in RECIPE_MAX.crafting)
  4366. {
  4367. hideItem(key, RECIPE_MAX.crafting[key], init);
  4368. }
  4369. if (init)
  4370. {
  4371. settings.observe(settings.KEY.hideUselessItems, function ()
  4372. {
  4373. return processItems(false);
  4374. });
  4375. }
  4376. }
  4377. processItems(true);
  4378. }
  4379. crafting.init = init;
  4380. })(crafting || (crafting = {}));
  4381.  
  4382. /**
  4383. * improve item boxes
  4384. */
  4385. var itemBoxes;
  4386. (function (itemBoxes)
  4387. {
  4388. itemBoxes.name = 'itemBoxes';
  4389.  
  4390. function hideNumberInItemBox(key, setVisibility)
  4391. {
  4392. if (setVisibility === void 0)
  4393. {
  4394. setVisibility = false;
  4395. }
  4396. var itemBox = document.getElementById('item-box-' + key);
  4397. if (!itemBox)
  4398. {
  4399. return;
  4400. }
  4401. var numberElement = itemBox.querySelector('span[data-item-display]');
  4402. if (!numberElement)
  4403. {
  4404. return;
  4405. }
  4406. numberElement.classList.add('number-caption');
  4407. if (setVisibility)
  4408. {
  4409. numberElement.classList.remove('hide');
  4410. numberElement.classList.add('hidden');
  4411. }
  4412. else
  4413. {
  4414. numberElement.classList.remove('hidden');
  4415. numberElement.classList.add('hide');
  4416. }
  4417. }
  4418.  
  4419. function addSpan2ItemBox(key, replace, setVisibility)
  4420. {
  4421. if (replace === void 0)
  4422. {
  4423. replace = true;
  4424. }
  4425. if (setVisibility === void 0)
  4426. {
  4427. setVisibility = false;
  4428. }
  4429. if (replace)
  4430. {
  4431. hideNumberInItemBox(key, setVisibility);
  4432. }
  4433. var itemBox = document.getElementById('item-box-' + key);
  4434. if (!itemBox)
  4435. {
  4436. return;
  4437. }
  4438. var span = document.createElement('span');
  4439. span.className = 'caption';
  4440. itemBox.appendChild(span);
  4441. return span;
  4442. }
  4443.  
  4444. function addCaptionStyle()
  4445. {
  4446. var CLASS_NAME = 'show-captions';
  4447. 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");
  4448.  
  4449. function updateBodyClass()
  4450. {
  4451. var show = settings.get(settings.KEY.showCaptions);
  4452. document.body.classList[show ? 'add' : 'remove'](CLASS_NAME);
  4453. }
  4454. updateBodyClass();
  4455. settings.observe(settings.KEY.showCaptions, function ()
  4456. {
  4457. return updateBodyClass();
  4458. });
  4459. }
  4460.  
  4461. function setOilPerSecond(span, oil)
  4462. {
  4463. span.innerHTML = "+ " + format.number(oil) + " L/s <img src=\"images/oil.png\" class=\"image-icon-20\">";
  4464. }
  4465. // show capacity of furnace
  4466. function addFurnaceCaption()
  4467. {
  4468. for (var i = 0; i < FURNACE_LEVELS.length; i++)
  4469. {
  4470. var key = FURNACE_LEVELS[i] + 'Furnace';
  4471. var boundKey = getBoundKey(key);
  4472. var capacitySpan = addSpan2ItemBox(boundKey);
  4473. if (capacitySpan)
  4474. {
  4475. capacitySpan.classList.add('capacity');
  4476. capacitySpan.textContent = 'Capacity: ' + format.number(win.getFurnaceCapacity(boundKey), true);
  4477. }
  4478. }
  4479. // charcoal foundry
  4480. var foundryCapacitySpan = addSpan2ItemBox('charcoalFoundry');
  4481. if (foundryCapacitySpan)
  4482. {
  4483. foundryCapacitySpan.classList.add('capacity');
  4484. foundryCapacitySpan.textContent = 'Capacity: 100';
  4485. }
  4486. }
  4487. // show oil cap of oil storage
  4488. function addOilStorageCaption()
  4489. {
  4490. for (var i = 0; i < OIL_STORAGE_SIZES.length; i++)
  4491. {
  4492. var key = 'oilStorage' + (i + 1);
  4493. var capSpan = addSpan2ItemBox(getBoundKey(key));
  4494. if (capSpan)
  4495. {
  4496. capSpan.classList.add('oil-cap');
  4497. capSpan.textContent = 'Oil cap: ' + format.number(OIL_STORAGE_SIZES[i], true);
  4498. }
  4499. }
  4500. }
  4501. var oilPipeOrbKey = 'boundBlueOilPipeOrb';
  4502.  
  4503. function setOilPipeCaption(span)
  4504. {
  4505. setOilPerSecond(span, 50 + win.achMiningEasyCompleted * 50 + getGameValue(oilPipeOrbKey) * 100);
  4506. }
  4507. function setTombKeys(span, key)
  4508. {
  4509. span.style = 'color: #470058';
  4510. span.innerHTML = format.number(key);
  4511. }
  4512. function addTombKeyCaption()
  4513. {
  4514. 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");
  4515. var tpl = document.createElement('templateWrapper');
  4516. 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";
  4517. var shadowDrop = tpl.firstElementChild;
  4518. document.body.appendChild(shadowDrop);
  4519. var crystalChargedSpan = addSpan2ItemBox('faradoxsCrystalCharged');
  4520. if (crystalChargedSpan)
  4521. {
  4522. crystalChargedSpan.classList.add('tombKey');
  4523. var totalKeys = win.tombKeyTotal;
  4524. setTombKeys(crystalChargedSpan, totalKeys);
  4525. observer.add(crystalChargedSpan, function ()
  4526. {
  4527. return setTombKeys(crystalChargedSpan, totalKeys);
  4528. });
  4529. }
  4530. var darkCrystalChargedSpan = addSpan2ItemBox('darkFaradoxsCrystalCharged');
  4531. if (darkCrystalChargedSpan)
  4532. {
  4533. darkCrystalChargedSpan.classList.add('tombKey');
  4534. var totalKeys = win.darkTombKeyTotal;
  4535. setTombKeys(darkCrystalChargedSpan, totalKeys);
  4536. observer.add(darkCrystalChargedSpan, function ()
  4537. {
  4538. return setTombKeys(darkCrystalChargedSpan, totalKeys);
  4539. });
  4540. }
  4541. }
  4542. // show oil per second
  4543. function addOilCaption()
  4544. {
  4545. 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");
  4546. var tpl = document.createElement('templateWrapper');
  4547. 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";
  4548. var shadowDrop = tpl.firstElementChild;
  4549. document.body.appendChild(shadowDrop);
  4550. var handheldOilSpan = addSpan2ItemBox('handheldOilPump', true, true);
  4551. if (handheldOilSpan)
  4552. {
  4553. handheldOilSpan.classList.add('oil');
  4554. setOilPerSecond(handheldOilSpan, 1 * win.miner);
  4555. observer.add('miner', function ()
  4556. {
  4557. return setOilPerSecond(handheldOilSpan, 1 * win.miner);
  4558. });
  4559. }
  4560. var oilPipeSpan = addSpan2ItemBox('boundOilPipe', true, true);
  4561. if (oilPipeSpan)
  4562. {
  4563. oilPipeSpan.classList.add('oil');
  4564. setOilPipeCaption(oilPipeSpan);
  4565. observer.add(oilPipeOrbKey, function ()
  4566. {
  4567. return setOilPipeCaption(oilPipeSpan);
  4568. });
  4569. }
  4570. var charcoalFactorySpan = addSpan2ItemBox('boundCharcoalFactory');
  4571. var charcoalFactoryOilGain = (boundRedCharcoalFactoryOrb) ? 600 : 300;
  4572. if (charcoalFactorySpan)
  4573. {
  4574. charcoalFactorySpan.classList.add('oil');
  4575. setOilPerSecond(charcoalFactorySpan, charcoalFactoryOilGain);
  4576. observer.add(charcoalFactorySpan, function ()
  4577. {
  4578. return setOilPerSecond(charcoalFactorySpan, charcoalFactoryOilGain);
  4579. });
  4580. }
  4581. // add pump jack oil display
  4582. var pumpjackSpan = addSpan2ItemBox('boundPumpjacks', false);
  4583. var totalOilPumpjacks = win.boundPumpjacks * 10;
  4584. var pumpjackOilGain = (achMiningHardCompleted) ? (totalOilPumpjacks * 2) : totalOilPumpjacks;
  4585. if (pumpjackSpan)
  4586. {
  4587. pumpjackSpan.classList.add('oil');
  4588. var setCaption_1 = function ()
  4589. {
  4590. return setOilPerSecond(pumpjackSpan, pumpjackOilGain);
  4591. };
  4592. setCaption_1();
  4593. observer.add('boundPumpjacks', function ()
  4594. {
  4595. return setCaption_1();
  4596. });
  4597. }
  4598. // add number of workers as caption to oil factory
  4599. var workerSpan = addSpan2ItemBox('boundOilFactory');
  4600. if (workerSpan)
  4601. {
  4602. var setCaption_2 = function ()
  4603. {
  4604. return workerSpan.textContent = 'Workers: ' + format.number(win.oilFactoryCheapWorkers, true);
  4605. };
  4606. setCaption_2();
  4607. observer.add('oilFactoryCheapWorkers', function ()
  4608. {
  4609. return setCaption_2();
  4610. });
  4611. }
  4612. var factoryOilSpan = addSpan2ItemBox('boundOilFactory');
  4613. var factoryOilGain = (boundGreenOilFactoryOrb) ? win.oilFactoryCheapWorkers * 2 :win.oilFactoryCheapWorkers;
  4614. if (factoryOilSpan)
  4615. {
  4616. factoryOilSpan.classList.add('oil');
  4617. var setCaption_3 = function ()
  4618. {
  4619. return setOilPerSecond(factoryOilSpan, factoryOilGain);
  4620. };
  4621. setCaption_3();
  4622. observer.add('oilFactoryCheapWorkers', function ()
  4623. {
  4624. return setCaption_3();
  4625. });
  4626. }
  4627. }
  4628.  
  4629. function addWandCaption()
  4630. {
  4631. for (var i = 0; i < WAND_LEVELS.length; i++)
  4632. {
  4633. var level = WAND_LEVELS[i];
  4634. var key = level + 'Wand';
  4635. var wandSpan = addSpan2ItemBox(key);
  4636. if (wandSpan)
  4637. {
  4638. wandSpan.textContent = capitalize(level) + ' Wand';
  4639. }
  4640. }
  4641. }
  4642.  
  4643. function addVariousCaptions()
  4644. {
  4645. var key2Name = {
  4646. 'achievementBook': 'Achievements'
  4647. , 'emptyAnvil': 'Anvil'
  4648. , 'tap': 'Tree Tap'
  4649. , 'farmer': 'Farmer'
  4650. , 'spellScroll1': 'Spell Scroll 1'
  4651. , 'boundRuniteSpyglass': 'Spyglass'
  4652. , 'bobsUncle': "Bob's Uncle"
  4653. , 'boundBoatingDock': 'Boating Dock'
  4654. , 'lumberjack': 'Lumberjack'
  4655. , 'handheldOilPump': 'Oil Pump'
  4656. , 'boundCharcoalFactory': 'Ch.coal Factory'
  4657. , 'boundNeedle': 'Needle'
  4658. , 'vendor': 'Vendor'
  4659. , 'boundOilStorage1': 'Oil Storage 1'
  4660. , 'boundOilStorage2': 'Oil Storage 2'
  4661. , 'boundOilStorage3': 'Oil Storage 3'
  4662. , 'boundOilStorage4': 'Oil Storage 4'
  4663. , 'boundOilStorage5': 'Oil Storage 5'
  4664. , 'boundOilStorage6': 'Oil Storage 6'
  4665. , 'boundOilStorage7': 'Oil Storage 7'
  4666. , 'boundOilPipe': 'Oil Pipe'
  4667. , 'meditate1': 'Meditate level 1'
  4668. , 'meditate2': 'Meditate level 2'
  4669. , 'meditate3': 'Meditate level 3'
  4670. , 'meditate4': 'Meditate level 4'
  4671. , 'meditate5': 'Meditate level 5'
  4672. , 'meditate6': 'Meditate level 6'
  4673. , 'meditate7': 'Meditate level 7'
  4674. , 'meditate8': 'Meditate level 8'
  4675. , 'meditate9': 'Meditate level 9'
  4676. , 'gardener': 'Gardener'
  4677. , 'planter': 'Planter'
  4678. , 'boundBrewingKit': 'Brewing Kit'
  4679. , 'cooksBook': 'Cooks Book'
  4680. , 'cooksPage': 'Cooks Page'
  4681. , 'combatDropTable': 'Loot Table'
  4682. , 'magicBook': 'Spell Book'
  4683. , 'magicShop': 'Magic Shop'
  4684. , 'crackedSpinningWheel': 'Cracked Wheel'
  4685. , 'woodenSpinningWheel': 'Wooden Wheel'
  4686. , 'oakSpinningWheel': 'Oak Wheel'
  4687. , 'willowSpinningWheel': 'Willow Wheel'
  4688. , 'mapleSpinningWheel': 'Maple Wheel'
  4689. , 'stardustSpinningWheel': 'Stardust Wheel'
  4690. , 'strangeSpinningWheel': 'Strange Wheel'
  4691. , 'ancientSpinningWheel': 'Ancient Wheel'
  4692. };
  4693. for (var key in key2Name)
  4694. {
  4695. var span = addSpan2ItemBox(key);
  4696. if (span)
  4697. {
  4698. span.textContent = key2Name[key];
  4699. }
  4700. }
  4701. }
  4702. // show current tier
  4703. function addTierCaption()
  4704. {
  4705. 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");
  4706.  
  4707. function addOrbObserver(key, spanList)
  4708. {
  4709. var boundOrbKey = getBoundKey('Blue' + capitalize(key) + 'Orb');
  4710.  
  4711. function checkOrb()
  4712. {
  4713. var classAction = getGameValue(boundOrbKey) > 0 ? 'add' : 'remove';
  4714. for (var _i = 0, spanList_1 = spanList; _i < spanList_1.length; _i++)
  4715. {
  4716. var span = spanList_1[_i];
  4717. span.classList[classAction]('orb');
  4718. }
  4719. }
  4720. checkOrb();
  4721. observer.add(boundOrbKey, function ()
  4722. {
  4723. return checkOrb();
  4724. });
  4725. }
  4726. var remainingOrbItems = ORB_ITEMS;
  4727. for (var _i = 0, TIER_ITEMS_2 = TIER_ITEMS; _i < TIER_ITEMS_2.length; _i++)
  4728. {
  4729. var tierItem = TIER_ITEMS_2[_i];
  4730. var isBindable = TIER_ITEMS_NOT_BINDABLE.indexOf(tierItem) === -1;
  4731. var spanList = [];
  4732. for (var i = 0; i < TIER_LEVELS.length; i++)
  4733. {
  4734. var key = getTierKey(tierItem, i);
  4735. var toolKey = isBindable ? getBoundKey(key) : key;
  4736. var tierSpan = addSpan2ItemBox(toolKey);
  4737. if (tierSpan)
  4738. {
  4739. tierSpan.classList.add('tier');
  4740. tierSpan.textContent = TIER_NAMES[i];
  4741. spanList.push(tierSpan);
  4742. }
  4743. }
  4744. var orbIndex = remainingOrbItems.indexOf(tierItem);
  4745. if (orbIndex !== -1)
  4746. {
  4747. addOrbObserver(tierItem, spanList);
  4748. remainingOrbItems.splice(orbIndex, 1);
  4749. }
  4750. }
  4751. for (var _a = 0, remainingOrbItems_1 = remainingOrbItems; _a < remainingOrbItems_1.length; _a++)
  4752. {
  4753. var itemKey = remainingOrbItems_1[_a];
  4754. var captionSpan = document.querySelector('#item-box-' + getBoundKey(itemKey) + ' > span:last-of-type');
  4755. if (!captionSpan)
  4756. {
  4757. continue;
  4758. }
  4759. addOrbObserver(itemKey, [captionSpan]);
  4760. }
  4761. }
  4762. var boatTimerKeys = BOAT_LIST.map(function (boatKey)
  4763. {
  4764. return boatKey + 'Timer';
  4765. });
  4766.  
  4767. function checkBoat(span, timerKey, init)
  4768. {
  4769. if (init === void 0)
  4770. {
  4771. init = false;
  4772. }
  4773. var isInTransit = getGameValue(timerKey) > 0;
  4774. var otherInTransit = boatTimerKeys.some(function (k)
  4775. {
  4776. return k != timerKey && getGameValue(k) > 0 && !boundBoatingDock;
  4777. });
  4778. span.textContent = isInTransit ? 'In transit' : 'Ready';
  4779. span.style.visibility = otherInTransit ? 'hidden' : '';
  4780. var parent = span.parentElement;
  4781. parent.style.opacity = otherInTransit ? '.5' : '';
  4782. if (init)
  4783. {
  4784. observer.add(boatTimerKeys, function ()
  4785. {
  4786. return checkBoat(span, timerKey, false);
  4787. });
  4788. }
  4789. }
  4790. // show boat progress
  4791. function addBoatCaption()
  4792. {
  4793. addStyle("\n#item-box-boundSailBoat.item-box > span[data-item-display] + span + span\n{\n\tdisplay: none;\n}\n\t\t");
  4794. for (var i = 0; i < BOAT_LIST.length; i++)
  4795. {
  4796. var span = addSpan2ItemBox(getBoundKey(BOAT_LIST[i]));
  4797. if (span)
  4798. {
  4799. checkBoat(span, boatTimerKeys[i], true);
  4800. }
  4801. }
  4802. }
  4803. // show bonemeal
  4804. function addBonemealCaption()
  4805. {
  4806. var noBonemealSpan = addSpan2ItemBox('boundBonemealBin');
  4807. if (!noBonemealSpan)
  4808. {
  4809. return;
  4810. }
  4811. noBonemealSpan.textContent = 'Bonemeal: 0';
  4812. var bonemealSpan = addSpan2ItemBox('boundFilledBonemealBin');
  4813. if (!bonemealSpan)
  4814. {
  4815. return;
  4816. }
  4817. bonemealSpan.dataset.itemDisplay = 'bonemeal';
  4818. bonemealSpan.textContent = format.number(win.bonemeal);
  4819. var captionSpan = document.createElement('span');
  4820. captionSpan.className = 'caption';
  4821. captionSpan.textContent = 'Bonemeal: ';
  4822. bonemealSpan.parentElement.insertBefore(captionSpan, bonemealSpan);
  4823. }
  4824.  
  4825. function warningBeforeSellingGems()
  4826. {
  4827. var _sellNPCItemDialogue = win.sellNPCItemDialogue;
  4828. win.sellNPCItemDialogue = function (item, amount)
  4829. {
  4830. if (item == 'sapphire' || item == 'emerald' || item == 'ruby' || item == 'diamond' || item == 'bloodDiamond')
  4831. {
  4832. var itemName = key2Name(amount == 1 ? item : item.replace(/y$/, 'ie') + 's', true);
  4833. if (amount == 0
  4834. || !win.confirm('Gems are precious and rare. Please consider carefully:\nDo you really want to sell ' + amount + ' ' + itemName + '?'))
  4835. {
  4836. return;
  4837. }
  4838. }
  4839. else if (item == 'logs' || item == 'oakLogs' || item == 'willowLogs' || item == 'mapleLogs' || item == 'stardustLogs' || item == 'strangeLogs' || item == 'ancientLogs')
  4840. {
  4841. var itemName = key2Name(amount == 1 ? item.replace(/s$/, '') : item, true);
  4842. if (amount == 0
  4843. || !win.confirm('Logs are time consuming to collect. Please consider carefully:\nDo you really want to sell ' + amount + ' ' + itemName + '?'))
  4844. {
  4845. return;
  4846. }
  4847. }
  4848. _sellNPCItemDialogue(item, amount);
  4849. };
  4850. }
  4851.  
  4852. function addWikiaLinks()
  4853. {
  4854. var WIKIA_CLASS = 'wikia-links';
  4855. 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");
  4856.  
  4857. function setWikiaLinksVisibility(init)
  4858. {
  4859. if (init === void 0)
  4860. {
  4861. init = false;
  4862. }
  4863. var show = settings.get(settings.KEY.wikiaLinks);
  4864. document.body.classList[show ? 'add' : 'remove'](WIKIA_CLASS);
  4865. if (init)
  4866. {
  4867. settings.observe(settings.KEY.wikiaLinks, function ()
  4868. {
  4869. return setWikiaLinksVisibility();
  4870. });
  4871. }
  4872. }
  4873. setWikiaLinksVisibility(true);
  4874. var boxes = document.getElementsByClassName('item-box');
  4875.  
  4876. function disableClickPropagation(el)
  4877. {
  4878. el.addEventListener('click', function (event)
  4879. {
  4880. event.stopPropagation();
  4881. });
  4882. }
  4883. for (var i = 0; i < boxes.length; i++)
  4884. {
  4885. var box = boxes.item(i);
  4886. var key = box.id.replace(/^item-box-/, '');
  4887. var linkArea = document.createElement('a');
  4888. linkArea.className = 'wikia-link';
  4889. linkArea.href = getWikiaLink(key);
  4890. linkArea.target = '_blank';
  4891. disableClickPropagation(linkArea);
  4892. box.appendChild(linkArea);
  4893. var tooltipEl = ensureTooltip('wikiLink', linkArea);
  4894. if (tooltipEl.innerHTML === '')
  4895. {
  4896. tooltipEl.innerHTML = "Click to open the wikia page about this item.";
  4897. }
  4898. }
  4899. }
  4900.  
  4901. function init()
  4902. {
  4903. addCaptionStyle();
  4904. addFurnaceCaption();
  4905. addOilStorageCaption();
  4906. addOilCaption();
  4907. addTombKeyCaption();
  4908. addWandCaption();
  4909. addVariousCaptions();
  4910. addTierCaption();
  4911. addBoatCaption();
  4912. addBonemealCaption();
  4913. warningBeforeSellingGems();
  4914. addWikiaLinks();
  4915. }
  4916. itemBoxes.init = init;
  4917. })(itemBoxes || (itemBoxes = {}));
  4918.  
  4919. /**
  4920. * add new chat
  4921. */
  4922. var chat;
  4923. (function (chat)
  4924. {
  4925. chat.name = 'chat';
  4926. // min time difference between repeated messages to not be considered as spam
  4927. var MIN_DIFF_REPEATED_MSG = 5e3;
  4928. var KEYWORD_LIST_KEY = 'keywordList';
  4929. chat.keywordList = store.has(KEYWORD_LIST_KEY) ? store.get(KEYWORD_LIST_KEY) : [];
  4930. var CHAT_HISTORY_KEY = 'chatHistory';
  4931. var MAX_CHAT_HISTORY_LENGTH = 100;
  4932. var PM_HISTORY_KEY = 'pmHistory';
  4933. var MAX_PM_HISTORY_LENGTH = 50;
  4934. var Type;
  4935. (function (Type)
  4936. {
  4937. Type[Type["reload"] = -1] = "reload";
  4938. Type[Type["normal"] = 0] = "normal";
  4939. Type[Type["pmReceived"] = 1] = "pmReceived";
  4940. Type[Type["pmSent"] = 2] = "pmSent";
  4941. Type[Type["serverMsg"] = 3] = "serverMsg";
  4942. })(Type || (Type = {}));;
  4943. var Tag;
  4944. (function (Tag)
  4945. {
  4946. Tag[Tag["none"] = 0] = "none";
  4947. Tag[Tag["donor"] = 1] = "donor";
  4948. Tag[Tag["contributor"] = 2] = "contributor";
  4949. Tag[Tag["mod"] = 3] = "mod";
  4950. Tag[Tag["dev"] = 4] = "dev";
  4951. Tag[Tag["server"] = 5] = "server";
  4952. })(Tag || (Tag = {}));;
  4953. /**
  4954. * The chunk hiding starts with at least 10 chunks.
  4955. * So there are at least
  4956. * (chunkHidingMinChunks-1) * msgChunkSize + 1 = 9 * 100 + 1 = 901
  4957. * messages before the chunk hiding mechanism starts.
  4958. */
  4959. var CHUNK_HIDING_MIN_CHUNKS = 10;
  4960. var MSG_CHUNK_SIZE = 100;
  4961. var RELOADED_CHAT_DATA = {
  4962. timestamp: 0
  4963. , username: ''
  4964. , userlevel: 0
  4965. , icon: 0
  4966. , tag: 0
  4967. , type: Type.reload
  4968. , msg: '[...]'
  4969. };
  4970. var CHAT_BOX_ID = 'div-chat';
  4971. var DEFAULT_CHAT_DIV_ID = 'div-chat-area';
  4972. var GENERAL_CHAT_DIV_ID = 'div-chat-general';
  4973. var PM_CHAT_TAB_PREFIX = 'tab-chat-pm-';
  4974. var PM_CHAT_DIV_PREFIX = 'div-chat-pm-';
  4975. var CHAT_TABS_ID = 'chat-tabs';
  4976. var CHAT_INPUT_ID = 'chat-input-text';
  4977. var CHAT_CLASS = 'div-chat-area';
  4978. var COLORIZE_CLASS = 'colorize';
  4979. var SpecialTab;
  4980. (function (SpecialTab)
  4981. {
  4982. SpecialTab[SpecialTab["default"] = 0] = "default";
  4983. SpecialTab[SpecialTab["general"] = 1] = "general";
  4984. SpecialTab[SpecialTab["filler"] = 2] = "filler";
  4985. })(SpecialTab || (SpecialTab = {}));;
  4986. var CHAT_SPECIAL_TAB_ID = (_a = {}
  4987. , _a[SpecialTab.default] = 'tab-chat-default'
  4988. , _a[SpecialTab.general] = 'tab-chat-general'
  4989. , _a[SpecialTab.filler] = 'tab-chat-filler'
  4990. , _a);
  4991. var CONTEXTMENU_ID = 'player-contextmenu';
  4992. var CHAT_ICONS = [
  4993. {
  4994. key: ''
  4995. , title: ''
  4996. }
  4997. , {
  4998. key: 'halloween2015'
  4999. , title: 'Halloween Gamer (2015)'
  5000. }
  5001. , {
  5002. key: 'christmas2015'
  5003. , title: 'Chirstmas Gamer (2015)'
  5004. }
  5005. , {
  5006. key: 'easter2016'
  5007. , title: 'Easter Gamer (2016)'
  5008. }
  5009. , {
  5010. key: 'halloween2016'
  5011. , title: 'Halloween Gamer (2016)'
  5012. }
  5013. , {
  5014. key: 'christmas2016'
  5015. , title: 'Chirstmas Gamer (2016)'
  5016. }
  5017. , {
  5018. key: 'dh1Max'
  5019. , title: 'DH1 Pro'
  5020. }
  5021. , {
  5022. key: 'hardcore'
  5023. , title: 'Hardcore Player'
  5024. }
  5025. , {
  5026. key: 'quest'
  5027. , title: 'Questmaster'
  5028. }
  5029. , {
  5030. key: 'maxMining'
  5031. , title: 'Mastery in mining'
  5032. }
  5033. , {
  5034. key: 'maxCrafting'
  5035. , title: 'Mastery in crafting'
  5036. }
  5037. , {
  5038. key: 'maxWC'
  5039. , title: 'Mastery in woodcutting'
  5040. }
  5041. , {
  5042. key: 'maxFarming'
  5043. , title: 'Mastery in farming'
  5044. }
  5045. , {
  5046. key: 'maxBrewing'
  5047. , title: 'Mastery in brewing'
  5048. }
  5049. , {
  5050. key: 'maxCombat'
  5051. , title: 'Mastery in combat'
  5052. }
  5053. , {
  5054. key: 'maxMagic'
  5055. , title: 'Mastery in magic'
  5056. }
  5057. , {
  5058. key: 'maxFishing'
  5059. , title: 'Mastery in fishing'
  5060. }
  5061. , {
  5062. key: 'maxCooking'
  5063. , title: 'Mastery in cooking'
  5064. }
  5065. , {
  5066. key: 'maxLevel'
  5067. , title: 'Mastery of all skills'
  5068. }
  5069. , {
  5070. key: 'birdcage'
  5071. , title: 'Stole a birdcage'
  5072. }
  5073. , {
  5074. key: 'achievement'
  5075. , title: 'Achievement Hunter'
  5076. }
  5077. , {
  5078. key: 'pinkPartyHat'
  5079. , title: 'Pink Party Hat'
  5080. }
  5081. , {
  5082. key: 'redPartyHat'
  5083. , title: 'Red Party Hat'
  5084. }
  5085. , {
  5086. key: 'greenPartyHat'
  5087. , title: 'Green Party Hat'
  5088. }
  5089. , {
  5090. key: 'yellowPartyHat'
  5091. , title: 'Yellow Party Hat'
  5092. }
  5093. , {
  5094. key: 'whitePartyHat'
  5095. , title: 'White Party Hat'
  5096. }
  5097. , {
  5098. key: 'bluePartyHat'
  5099. , title: 'Blue Party Hat'
  5100. }];
  5101. var getUnknownChatIcon = function (icon)
  5102. {
  5103. return {
  5104. key: 'unknown'
  5105. , title: ''
  5106. , img: '<img src="images/chat-icons/' + icon + '.png" class="image-icon-20" />'
  5107. };
  5108. };
  5109. var CHAT_TAGS = [
  5110. null
  5111. , {
  5112. key: 'donor'
  5113. , name: ''
  5114. }
  5115. , {
  5116. key: 'contributor'
  5117. , name: 'Contributor'
  5118. }
  5119. , {
  5120. key: 'mod'
  5121. , name: 'Moderator'
  5122. }
  5123. , {
  5124. key: 'dev'
  5125. , name: 'Dev'
  5126. }
  5127. , {
  5128. key: 'yell'
  5129. , name: 'Server Message'
  5130. }
  5131. ];
  5132. var LOCALE = 'en-US';
  5133. var LOCALE_OPTIONS = {
  5134. hour12: false
  5135. , year: 'numeric'
  5136. , month: 'long'
  5137. , day: 'numeric'
  5138. , hour: '2-digit'
  5139. , minute: '2-digit'
  5140. , second: '2-digit'
  5141. };
  5142. // game commands
  5143. var COMMANDS = [
  5144. 'pm'
  5145. , 'mute'
  5146. , 'clear'
  5147. , 'ipmute'
  5148. ];
  5149. var CLEAR_CMD = 'clear';
  5150. var TUTORIAL_CMD = 'tutorial';
  5151. // load chat history
  5152. var chatHistory = store.get(CHAT_HISTORY_KEY) || [];
  5153. var pmHistory = store.get(PM_HISTORY_KEY) || [];
  5154. // store chat colors for each user
  5155. var user2Color;
  5156. var usedColors;
  5157. // reserve color for special messages (e.g. server messages): white
  5158. var reservedColors = ['#ffffff'];
  5159. // message chunks
  5160. var msgChunkMap = new Map();
  5161. // for adding elements at startup
  5162. var chatboxFragments = new Map();
  5163. var chatInitialized = false;
  5164. // find index of last message which is not a pm
  5165. var isLastMsgNotReload = false;
  5166. for (var i = chatHistory.length - 1; i >= 0; i--)
  5167. {
  5168. if (!isDataPM(chatHistory[i]))
  5169. {
  5170. isLastMsgNotReload = chatHistory[i].type != Type.reload;
  5171. break;
  5172. }
  5173. }
  5174. // insert a placeholder for a reloaded chat
  5175. if (isLastMsgNotReload)
  5176. {
  5177. RELOADED_CHAT_DATA.timestamp = (new Date()).getTime();
  5178. chatHistory.push(RELOADED_CHAT_DATA);
  5179. }
  5180.  
  5181. function isMuted(user)
  5182. {
  5183. return user !== win.username
  5184. && win.mutedPeople.some(function (name)
  5185. {
  5186. return user.indexOf(name) > -1;
  5187. });
  5188. }
  5189.  
  5190. function isSpam(data)
  5191. {
  5192. // allow all own messages, messages from contributors, mods, devs and all server messages
  5193. if (data.username === win.username || data.tag != Tag.none)
  5194. {
  5195. return false;
  5196. }
  5197. /**
  5198. * get last message of current user
  5199. */
  5200. var historyIndex = chatHistory.indexOf(data);
  5201. if (historyIndex == -1)
  5202. {
  5203. historyIndex = chatHistory.length;
  5204. }
  5205. var lastData = null;
  5206. for (var i = historyIndex - 1; i >= 0 && (lastData === null); i--)
  5207. {
  5208. var dataBefore = chatHistory[i];
  5209. if (dataBefore.username === data.username)
  5210. {
  5211. lastData = dataBefore;
  5212. }
  5213. }
  5214. /**
  5215. * compare message and don't allow the same message twice
  5216. */
  5217. if (lastData
  5218. && lastData.msg === data.msg
  5219. && (data.timestamp - lastData.timestamp) < MIN_DIFF_REPEATED_MSG)
  5220. {
  5221. return true;
  5222. }
  5223. return false;
  5224. }
  5225.  
  5226. function saveKeywordList()
  5227. {
  5228. store.set(KEYWORD_LIST_KEY, chat.keywordList);
  5229. }
  5230.  
  5231. function addKeyword(keyword)
  5232. {
  5233. if (keyword !== '' && chat.keywordList.indexOf(keyword) === -1)
  5234. {
  5235. chat.keywordList.push(keyword);
  5236. saveKeywordList();
  5237. return true;
  5238. }
  5239. return false;
  5240. }
  5241. chat.addKeyword = addKeyword;
  5242.  
  5243. function removeKeyword(keyword)
  5244. {
  5245. var index = chat.keywordList.indexOf(keyword);
  5246. if (index !== -1)
  5247. {
  5248. chat.keywordList.splice(index, 1);
  5249. saveKeywordList();
  5250. return true;
  5251. }
  5252. return false;
  5253. }
  5254. chat.removeKeyword = removeKeyword;
  5255.  
  5256. function handleScrolling(chatbox)
  5257. {
  5258. if (win.isAutoScrolling)
  5259. {
  5260. setTimeout(function ()
  5261. {
  5262. return chatbox.scrollTop = chatbox.scrollHeight;
  5263. });
  5264. }
  5265. }
  5266. // for chat messages which arrive before DOMContentLoaded and can not be displayed since the DOM isn't ready
  5267. function processChatData(username, iconString, tagString, msg, isPM)
  5268. {
  5269. var tag = parseInt(tagString, 10);
  5270. var userlevel = 0;
  5271. var type = Type.normal;
  5272. if (isPM == 1)
  5273. {
  5274. var match = msg.match(/^\s*\[(PM from|Sent to) ([A-Za-z0-9_ ]+)\]: (.+?)\s*$/) || ['', '', username, msg];
  5275. type = match[1] == 'Sent to' ? Type.pmSent : Type.pmReceived;
  5276. username = match[2];
  5277. if (username !== 'sexy_squid')
  5278. {
  5279. username = username.replace(/_/g, ' ');
  5280. }
  5281. msg = match[3];
  5282. }
  5283. else if (tag == Tag.server)
  5284. {
  5285. type = Type.serverMsg;
  5286. }
  5287. else
  5288. {
  5289. var match = msg.match(/^\s*\((\d+)\): (.+?)\s*$/);
  5290. if (match)
  5291. {
  5292. userlevel = parseInt(match[1], 10);
  5293. msg = match[2];
  5294. }
  5295. else
  5296. {
  5297. userlevel = win.getGlobalLevel();
  5298. }
  5299. }
  5300. // unlinkify when using DH2QoL to store the plain message
  5301. if (win.addToChatBox.toString().includes('linkify(arguments[3])'))
  5302. {
  5303. msg = msg.replace(/<a href='([^']+)' target='_blank'>\1<\/a>/ig, '$1');
  5304. }
  5305. if (type == Type.pmSent)
  5306. {
  5307. // turn some critical characters into HTML entities
  5308. msg = msg.replace(/[<>]/g, function (char)
  5309. {
  5310. return '&#' + char.charCodeAt(0) + ';';
  5311. });
  5312. }
  5313. return {
  5314. timestamp: now()
  5315. , username: username
  5316. , userlevel: userlevel
  5317. , icon: parseInt(iconString, 10)
  5318. , tag: tag
  5319. , type: type
  5320. , msg: msg
  5321. };
  5322. }
  5323.  
  5324. function saveChatHistory()
  5325. {
  5326. store.set(CHAT_HISTORY_KEY, chatHistory);
  5327. }
  5328.  
  5329. function savePmHistory()
  5330. {
  5331. store.set(PM_HISTORY_KEY, pmHistory);
  5332. }
  5333.  
  5334. function add2ChatHistory(data)
  5335. {
  5336. if (data.type === Type.pmReceived
  5337. || data.type === Type.pmSent)
  5338. {
  5339. pmHistory.push(data);
  5340. pmHistory = pmHistory.slice(-MAX_PM_HISTORY_LENGTH);
  5341. savePmHistory();
  5342. }
  5343. else
  5344. {
  5345. chatHistory.push(data);
  5346. chatHistory = chatHistory.slice(-MAX_CHAT_HISTORY_LENGTH);
  5347. saveChatHistory();
  5348. }
  5349. }
  5350.  
  5351. function username2Id(username)
  5352. {
  5353. return username.replace(/ /g, '_');
  5354. }
  5355.  
  5356. function setNewCounter(tab, num, force)
  5357. {
  5358. if (force === void 0)
  5359. {
  5360. force = false;
  5361. }
  5362. var panel = getChatPanel(tab.dataset.username || '');
  5363. if (force
  5364. || !tab.classList.contains('selected')
  5365. || !win.isAutoScrolling && panel.scrollHeight > panel.scrollTop + panel.offsetHeight)
  5366. {
  5367. tab.dataset.new = num.toString();
  5368. }
  5369. }
  5370.  
  5371. function incrementNewCounter(tab)
  5372. {
  5373. setNewCounter(tab, parseInt(tab.dataset.new || '0', 10) + 1);
  5374. }
  5375.  
  5376. function getChatTab(username, specialTab)
  5377. {
  5378. var id = (specialTab != null)
  5379. ? CHAT_SPECIAL_TAB_ID[specialTab]
  5380. : PM_CHAT_TAB_PREFIX + username2Id(username);
  5381. var tab = document.getElementById(id);
  5382. if (!tab)
  5383. {
  5384. tab = document.createElement('div');
  5385. tab.className = 'chat-tab';
  5386. if (specialTab != null)
  5387. {
  5388. tab.classList.add(SpecialTab[specialTab]);
  5389. }
  5390. tab.id = id;
  5391. tab.dataset.username = username;
  5392. setNewCounter(tab, 0, true);
  5393. if (username.length > 0)
  5394. {
  5395. tab.textContent = username;
  5396. // thanks /u/Spino-Prime for pointing out this was missing
  5397. var closeSpan = document.createElement('span');
  5398. closeSpan.className = 'close';
  5399. tab.appendChild(closeSpan);
  5400. }
  5401. var chatTabs = document.getElementById(CHAT_TABS_ID);
  5402. var filler = chatTabs.querySelector('.filler');
  5403. if (filler)
  5404. {
  5405. chatTabs.insertBefore(tab, filler);
  5406. }
  5407. else
  5408. {
  5409. chatTabs.appendChild(tab);
  5410. }
  5411. }
  5412. return tab;
  5413. }
  5414.  
  5415. function getChatPanel(username)
  5416. {
  5417. var id = username == '' ? GENERAL_CHAT_DIV_ID : PM_CHAT_DIV_PREFIX + username2Id(username);
  5418. var panel = document.getElementById(id);
  5419. if (!panel)
  5420. {
  5421. panel = document.createElement('div');
  5422. panel.setAttribute('disabled', 'disabled');
  5423. panel.id = id;
  5424. panel.className = CHAT_CLASS;
  5425. var defaultChat = document.getElementById(DEFAULT_CHAT_DIV_ID);
  5426. var height = defaultChat.style.height;
  5427. panel.style.height = height;
  5428. var chatDiv = defaultChat.parentElement;
  5429. chatDiv.insertBefore(panel, defaultChat);
  5430. }
  5431. return panel;
  5432. }
  5433.  
  5434. function changeChatTab(oldTab, newTab)
  5435. {
  5436. if (oldTab)
  5437. {
  5438. oldTab.classList.remove('selected');
  5439. var oldChatPanel = void 0;
  5440. if (oldTab.classList.contains('default'))
  5441. {
  5442. oldChatPanel = document.getElementById(DEFAULT_CHAT_DIV_ID);
  5443. }
  5444. else
  5445. {
  5446. oldChatPanel = getChatPanel(oldTab.dataset.username || '');
  5447. }
  5448. oldChatPanel.classList.remove('selected');
  5449. }
  5450. newTab.classList.add('selected');
  5451. setNewCounter(newTab, 0, true);
  5452. var newChatPanel;
  5453. if (newTab.classList.contains('default'))
  5454. {
  5455. newChatPanel = document.getElementById(DEFAULT_CHAT_DIV_ID);
  5456. }
  5457. else
  5458. {
  5459. newChatPanel = getChatPanel(newTab.dataset.username || '');
  5460. }
  5461. newChatPanel.classList.add('selected');
  5462. var toUsername = newTab.dataset.username;
  5463. var newTextPlaceholder = toUsername == '' ? win.username + ':' : 'PM to ' + toUsername + ':';
  5464. document.getElementById(CHAT_INPUT_ID).placeholder = newTextPlaceholder;
  5465. handleScrolling(newChatPanel);
  5466. }
  5467.  
  5468. function clearChat(username)
  5469. {
  5470. if (username === '')
  5471. {
  5472. // clean server chat
  5473. chatHistory = [];
  5474. saveChatHistory();
  5475. }
  5476. else
  5477. {
  5478. // delete pms stored for that user
  5479. for (var i = 0; i < pmHistory.length; i++)
  5480. {
  5481. var data = pmHistory[i];
  5482. if (data.username == username)
  5483. {
  5484. pmHistory.splice(i, 1);
  5485. i--;
  5486. }
  5487. }
  5488. savePmHistory();
  5489. }
  5490. // clear pm-chat panel
  5491. var panel = getChatPanel(username);
  5492. while (panel.children.length > 0)
  5493. {
  5494. panel.removeChild(panel.children[0]);
  5495. }
  5496. msgChunkMap.delete(username);
  5497. return panel;
  5498. }
  5499.  
  5500. function closeChatTab(username)
  5501. {
  5502. // clear pm-chat panel and remove message-history
  5503. clearChat(username);
  5504. // remove pm-tab (and change tab if necessary)
  5505. var selectedTab = getSelectedTab();
  5506. var tab2Close = getChatTab(username, null);
  5507. if (selectedTab.dataset.username == username)
  5508. {
  5509. var generalTab = getChatTab('', SpecialTab.general);
  5510. changeChatTab(tab2Close, generalTab);
  5511. }
  5512. var tabContainer = tab2Close.parentElement;
  5513. tabContainer.removeChild(tab2Close);
  5514. }
  5515.  
  5516. function isDataPM(data)
  5517. {
  5518. return data.type === Type.pmSent || data.type === Type.pmReceived;
  5519. }
  5520.  
  5521. function colorizeMsg(username)
  5522. {
  5523. if (username == '')
  5524. {
  5525. return null;
  5526. }
  5527. if (!user2Color.has(username))
  5528. {
  5529. var color = void 0;
  5530. do {
  5531. var colorizer = settings.getSub(settings.KEY.colorizeChat, 'colorizer');
  5532. if (colorizer == 1)
  5533. {
  5534. color = colorGenerator.getRandom(
  5535. {
  5536. luminosity: 'light'
  5537. });
  5538. }
  5539. else if (colorizer == 2)
  5540. {
  5541. color = colorGenerator.getRandom(
  5542. {
  5543. luminosity: 'dark'
  5544. });
  5545. }
  5546. else
  5547. {
  5548. color = colorGenerator.getEquallyDistributed();
  5549. }
  5550. } while (usedColors.has(color));
  5551. user2Color.set(username, color);
  5552. usedColors.add(color);
  5553. addStyle("\n#" + CHAT_BOX_ID + "." + COLORIZE_CLASS + " .chat-msg[data-username=\"" + username + "\"]\n{\n\tbackground-color: " + color + ";\n}\n\t\t\t", 'name-color');
  5554. }
  5555. return user2Color.get(username);
  5556. }
  5557.  
  5558. function createMessageSegment(data)
  5559. {
  5560. var isThisPm = isDataPM(data);
  5561. var msgUsername = data.type === Type.pmSent ? win.username : data.username;
  5562. var history = isThisPm ? pmHistory : chatHistory;
  5563. var historyIndex = history.indexOf(data);
  5564. var isSameUser = null;
  5565. var isSameTime = null;
  5566. for (var i = historyIndex - 1; i >= 0 && (isSameUser === null || isSameTime === null); i--)
  5567. {
  5568. var dataBefore = history[i];
  5569. if (isThisPm === isDataPM(dataBefore))
  5570. {
  5571. if (isSameUser === null)
  5572. {
  5573. var beforeUsername = dataBefore.type == Type.pmSent ? win.username : dataBefore.username;
  5574. isSameUser = beforeUsername === msgUsername;
  5575. }
  5576. if (dataBefore.type != Type.reload)
  5577. {
  5578. isSameTime = Math.floor(data.timestamp / 1000 / 60) - Math.floor(dataBefore.timestamp / 1000 / 60) === 0;
  5579. }
  5580. }
  5581. }
  5582. var d = new Date(data.timestamp);
  5583. var hour = (d.getHours() < 10 ? '0' : '') + d.getHours();
  5584. var minute = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes();
  5585. var icon = CHAT_ICONS[data.icon] || getUnknownChatIcon(data.icon);
  5586. var tag = CHAT_TAGS[data.tag] ||
  5587. {
  5588. key: ''
  5589. , name: ''
  5590. };
  5591. var formattedMsg = data.msg
  5592. .replace(/<a href='(.+?)' target='_blank'>\1<\/a>/g, '$1')
  5593. .replace(/(https?:\/\/[^\s"<>]+)/g, '<a target="_blank" href="$1">$1</a>');
  5594. colorizeMsg(msgUsername);
  5595. var msgTitle = data.type == Type.reload ? 'Chat loaded on ' + d.toLocaleString(LOCALE, LOCALE_OPTIONS) : '';
  5596. var user = data.type === Type.serverMsg ? 'Server Message' : msgUsername;
  5597. var levelAppendix = data.type == Type.normal ? ' (' + data.userlevel + ')' : '';
  5598. var userTitle = data.tag != Tag.server ? tag.name : '';
  5599. return "<span class=\"chat-msg\" data-type=\"" + data.type + "\" data-tag=\"" + tag.key + "\" data-username=\"" + msgUsername + "\">"
  5600. + ("<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>")
  5601. + ("<span class=\"user\" data-name=\"" + msgUsername + "\" data-same-user=\"" + isSameUser + "\">")
  5602. + ("<span class=\"icon " + icon.key + "\" title=\"" + icon.title + "\"></span>")
  5603. + ("<span class=\"name chat-tag-" + tag.key + "\" title=\"" + userTitle + "\">" + user + levelAppendix + ":</span>")
  5604. + "</span>"
  5605. + ("<span class=\"msg\" title=\"" + msgTitle + "\">" + formattedMsg + "</span>")
  5606. + "</span>";
  5607. }
  5608.  
  5609. function add2Chat(data)
  5610. {
  5611. if (!chatInitialized)
  5612. {
  5613. return;
  5614. }
  5615. var isThisPm = isDataPM(data);
  5616. // don't mute pms (you can just ignore pm-tab if you like)
  5617. if (!isThisPm && isMuted(data.username))
  5618. {
  5619. return;
  5620. }
  5621. var userKey = isThisPm ? data.username : '';
  5622. if (isThisPm)
  5623. {
  5624. win.lastPMUser = data.username;
  5625. }
  5626. // username is 3-12 characters long
  5627. var chatbox = getChatPanel(userKey);
  5628. var msgChunk = msgChunkMap.get(userKey);
  5629. if (!msgChunk || msgChunk.children.length >= MSG_CHUNK_SIZE)
  5630. {
  5631. msgChunk = document.createElement('div');
  5632. msgChunk.className = 'msg-chunk';
  5633. msgChunkMap.set(userKey, msgChunk);
  5634. if (chatboxFragments != null)
  5635. {
  5636. if (!chatboxFragments.has(userKey))
  5637. {
  5638. chatboxFragments.set(userKey, document.createDocumentFragment());
  5639. }
  5640. chatboxFragments.get(userKey).appendChild(msgChunk);
  5641. }
  5642. else
  5643. {
  5644. chatbox.appendChild(msgChunk);
  5645. }
  5646. }
  5647. var tmp = document.createElement('templateWrapper');
  5648. tmp.innerHTML = createMessageSegment(data);
  5649. msgChunk.appendChild(tmp.children[0]);
  5650. handleScrolling(chatbox);
  5651. // add delay because handleScrolling is will set scrollTop delayed
  5652. setTimeout(function ()
  5653. {
  5654. var chatTab = getChatTab(userKey, isThisPm ? null : SpecialTab.general);
  5655. incrementNewCounter(chatTab);
  5656. });
  5657. }
  5658.  
  5659. function applyChatStyle()
  5660. {
  5661. addStyle("\ndiv.div-chat-area\n{\n\tpadding-left: 0;\n}\nspan.chat-msg\n{\n\tdisplay: flex;\n\tmin-height: 21px;\n\tpadding: 1px 0;\n\tpadding-left: 5px;\n}\n#" + CHAT_BOX_ID + ":not(." + COLORIZE_CLASS + ") span.chat-msg:nth-child(2n)\n{\n\tbackground-color: hsla(0, 0%, 90%, 1);\n}\n.chat-msg[data-type=\"" + Type.reload + "\"]\n{\n\tfont-size: 0.8rem;\n\tline-height: 1.2rem;\n}\n.chat-msg .timestamp\n{\n\tdisplay: none;\n}\n#" + CHAT_BOX_ID + ".showTimestamps .chat-msg:not([data-type=\"" + Type.reload + "\"]) .timestamp\n{\n\tcolor: hsla(0, 0%, 50%, 1);\n\tdisplay: inline-block;\n\tfont-size: .9rem;\n\tmargin: 0;\n\tmargin-right: 5px;\n\tposition: relative;\n\twidth: 2.5rem;\n}\n.chat-msg .timestamp[data-same-time=\"true\"]\n{\n\tcolor: hsla(0, 0%, 50%, .1);\n}\n.chat-msg:not([data-type=\"" + Type.reload + "\"]) .timestamp:hover::after\n{\n\tbackground-color: hsla(0, 0%, 12%, 1);\n\tborder-radius: .2rem;\n\tcontent: attr(data-fulltime);\n\tcolor: hsla(0, 0%, 100%, 1);\n\tline-height: 1.35rem;\n\tpadding: .4rem .8rem;\n\tpointer-events: none;\n\tposition: absolute;\n\tleft: 2.5rem;\n\ttop: -0.4rem;\n\ttext-align: center;\n\twhite-space: nowrap;\n}\n\n#" + CHAT_BOX_ID + ".showTags .chat-msg[data-type=\"" + Type.pmReceived + "\"] { color: purple; }\n#" + CHAT_BOX_ID + ".showTags .chat-msg[data-type=\"" + Type.pmSent + "\"] { color: purple; }\n#" + CHAT_BOX_ID + ".showTags .chat-msg[data-type=\"" + Type.serverMsg + "\"] { color: blue; }\n#" + CHAT_BOX_ID + ".showTags .chat-msg[data-tag=\"contributor\"] { color: green; }\n#" + CHAT_BOX_ID + ".showTags .chat-msg[data-tag=\"mod\"] { color: #669999; }\n#" + CHAT_BOX_ID + ".showTags .chat-msg[data-tag=\"dev\"] { color: #666600; }\n.chat-msg:not([data-type=\"" + Type.reload + "\"]) .user\n{\n\tflex: 0 0 132px;\n\tmargin-right: 5px;\n\twhite-space: nowrap;\n}\n#" + GENERAL_CHAT_DIV_ID + " .chat-msg:not([data-type=\"" + Type.reload + "\"]) .user\n{\n\tflex-basis: 182px;\n}\n#" + CHAT_BOX_ID + ".showIcons #" + GENERAL_CHAT_DIV_ID + " .chat-msg:not([data-type=\"" + Type.reload + "\"]) .user\n{\n\tpadding-left: 22px;\n}\n.chat-msg .user[data-same-user=\"true\"]:not([data-name=\"\"])\n{\n\tcursor: default;\n\topacity: 0;\n}\n\n.chat-msg .user .icon\n{\n\tdisplay: none;\n}\n#" + CHAT_BOX_ID + ".showIcons .chat-msg .user .icon\n{\n\tdisplay: inline-block;\n\tmargin-left: -22px;\n}\n.chat-msg .user .icon.unknown > img,\n.chat-msg .user .icon:not(.unknown)::before\n{\n\tbackground-size: 20px 20px;\n\tcontent: '';\n\tdisplay: inline-block;\n\tmargin-right: 2px;\n\twidth: 20px;\n\theight: 20px;\n\tvertical-align: middle;\n}\n.chat-msg .user .icon.halloween2015::before\t{ background-image: url('images/chat-icons/1.png'); }\n.chat-msg .user .icon.christmas2015::before\t{ background-image: url('images/chat-icons/2.png'); }\n.chat-msg .user .icon.easter2016::before\t{ background-image: url('images/chat-icons/3.png'); }\n.chat-msg .user .icon.halloween2016::before\t{ background-image: url('images/chat-icons/4.png'); }\n.chat-msg .user .icon.christmas2016::before\t{ background-image: url('images/chat-icons/5.png'); }\n.chat-msg .user .icon.dh1Max::before\t\t{ background-image: url('images/chat-icons/6.png'); }\n.chat-msg .user .icon.hardcore::before\t\t{ background-image: url('images/chat-icons/7.png'); }\n.chat-msg .user .icon.quest::before\t\t\t{ background-image: url('images/chat-icons/8.png'); }\n.chat-msg .user .icon.maxMining::before\t\t{ background-image: url('images/chat-icons/9.png'); }\n.chat-msg .user .icon.maxCrafting::before\t{ background-image: url('images/chat-icons/10.png'); }\n.chat-msg .user .icon.maxWC::before\t\t\t{ background-image: url('images/chat-icons/11.png'); }\n.chat-msg .user .icon.maxFarming::before\t{ background-image: url('images/chat-icons/12.png'); }\n.chat-msg .user .icon.maxBrewing::before\t{ background-image: url('images/chat-icons/13.png'); }\n.chat-msg .user .icon.maxCombat::before\t\t{ background-image: url('images/chat-icons/14.png'); }\n.chat-msg .user .icon.maxMagic::before\t\t{ background-image: url('images/chat-icons/15.png'); }\n.chat-msg .user .icon.maxFishing::before\t{ background-image: url('images/chat-icons/16.png'); }\n.chat-msg .user .icon.maxCooking::before\t{ background-image: url('images/chat-icons/17.png'); }\n.chat-msg .user .icon.maxLevel::before\t\t{ background-image: url('images/chat-icons/18.png'); }\n.chat-msg .user .icon.birdcage::before\t\t{ background-image: url('images/chat-icons/19.png'); }\n.chat-msg .user .icon.achievement::before\t{ background-image: url('images/chat-icons/20.png'); }\n.chat-msg .user .icon.pinkPartyHat::before\t{ background-image: url('images/chat-icons/21.png'); }\n.chat-msg .user .icon.redPartyHat::before\t{ background-image: url('images/chat-icons/22.png'); }\n.chat-msg .user .icon.greenPartyHat::before\t{ background-image: url('images/chat-icons/23.png'); }\n.chat-msg .user .icon.yellowPartyHat::before\t{ background-image: url('images/chat-icons/24.png'); }\n.chat-msg .user .icon.whitePartyHat::before\t{ background-image: url('images/chat-icons/25.png'); }\n.chat-msg .user .icon.bluePartyHat::before\t{ background-image: url('images/chat-icons/26.png'); }\n\n.chat-msg .user:not([data-same-user=\"true\"]) .name\n{\n\tcolor: rgba(0, 0, 0, 0.7);\n\tcursor: pointer;\n}\n.chat-msg .user .name.chat-tag-donor::before\n{\n\tbackground-image: url('images/chat-icons/donor.png');\n\tbackground-size: 20px 20px;\n\tcontent: '';\n\tdisplay: inline-block;\n\theight: 20px;\n\twidth: 20px;\n\tvertical-align: middle;\n}\n.chat-msg .user .name.chat-tag-yell\n{\n\tcursor: default;\n}\n#" + CHAT_BOX_ID + ".showTags .chat-msg .user .name.chat-tag-contributor,\n#" + CHAT_BOX_ID + ".showTags .chat-msg .user .name.chat-tag-mod,\n#" + CHAT_BOX_ID + ".showTags .chat-msg .user .name.chat-tag-dev,\n#" + CHAT_BOX_ID + ".showTags .chat-msg .user .name.chat-tag-yell\n{\n\tcolor: white;\n\tdisplay: inline-block;\n\tfont-size: 10pt;\n\tmargin-bottom: -1px;\n\tmargin-top: -1px;\n\tpadding-bottom: 2px;\n\ttext-align: center;\n\t/* 2px border, 10 padding */\n\twidth: calc(100% - 2*1px - 2*5px);\n}\n#" + CHAT_BOX_ID + ":not(.showTags) .chat-msg .user .name.chat-tag-contributor,\n#" + CHAT_BOX_ID + ":not(.showTags) .chat-msg .user .name.chat-tag-mod,\n#" + CHAT_BOX_ID + ":not(.showTags) .chat-msg .user .name.chat-tag-dev,\n#" + CHAT_BOX_ID + ":not(.showTags) .chat-msg .user .name.chat-tag-yell\n{\n\tbackground: initial;\n\tborder: inherit;\n\tfont-family: inherit;\n\tfont-size: inherit;\n\tpadding: initial;\n}\n\n.chat-msg[data-type=\"" + Type.reload + "\"] .user > *,\n.chat-msg[data-type=\"" + Type.pmReceived + "\"] .user > .icon,\n.chat-msg[data-type=\"" + Type.pmSent + "\"] .user > .icon\n{\n\tdisplay: none;\n}\n\n.chat-msg .msg\n{\n\tmin-width: 0;\n\toverflow: hidden;\n\tword-wrap: break-word;\n}\n\n#" + CHAT_BOX_ID + " ." + CHAT_CLASS + "\n{\n\twidth: calc(100% - 5px);\n\theight: 130px;\n\tdisplay: none;\n}\n#" + CHAT_BOX_ID + " ." + CHAT_CLASS + ".selected\n{\n\tdisplay: block;\n}\n#" + CHAT_TABS_ID + "\n{\n\tdisplay: flex;\n\tmargin: 10px -5px -6px;\n\tflex-wrap: wrap;\n}\n#" + CHAT_TABS_ID + " .chat-tab\n{\n\tbackground-color: gray;\n\tborder-top: 1px solid black;\n\tborder-right: 1px solid black;\n\tcursor: pointer;\n\tdisplay: inline-block;\n\tfont-weight: normal;\n\tpadding: 0.3rem .6rem;\n\tposition: relative;\n}\n#" + CHAT_TABS_ID + " .chat-tab.selected\n{\n\tbackground-color: transparent;\n\tborder-top-color: transparent;\n}\n#" + CHAT_TABS_ID + " .chat-tab.default\n{\n\tdisplay: none;\n}\n#" + CHAT_TABS_ID + " .chat-tab.filler\n{\n\tbackground-color: hsla(0, 0%, 90%, 1);\n\tborder-right: 0;\n\tbox-shadow: inset 5px 5px 5px -5px rgba(0, 0, 0, 0.5);\n\tcolor: transparent;\n\tcursor: default;\n\tflex-grow: 1;\n}\n#" + CHAT_TABS_ID + " .chat-tab::after\n{\n\tcolor: white;\n\tcontent: '(' attr(data-new) ')';\n\tfont-size: .9rem;\n\tfont-weight: bold;\n\tmargin-left: .4rem;\n}\n#" + CHAT_TABS_ID + " .chat-tab.selected::after\n{\n\tcolor: gray;\n}\n#" + CHAT_TABS_ID + " .chat-tab[data-new=\"0\"]::after\n{\n\tcolor: inherit;\n\tfont-weight: normal;\n}\n#" + CHAT_TABS_ID + " .chat-tab:not(.general).selected::after,\n#" + CHAT_TABS_ID + " .chat-tab:not(.general):hover::after\n{\n\tvisibility: hidden;\n}\n#" + CHAT_TABS_ID + " .chat-tab:not(.general).selected .close::after,\n#" + CHAT_TABS_ID + " .chat-tab:not(.general):hover .close::after\n{\n\tcontent: '\u00D7';\n\tfont-size: 1.5rem;\n\tposition: absolute;\n\ttop: 0;\n\tright: .6rem;\n\tbottom: 0;\n}\n\n#" + CONTEXTMENU_ID + "\n{\n\tbox-shadow: rgba(0, 0, 0, 0.8) 4px 4px 4px -2px;\n\tposition: fixed;\n}\n#" + CONTEXTMENU_ID + " .ui-widget-header\n{\n\tcursor: default;\n\tpadding: .25rem;\n}\n\t\t");
  5662. }
  5663.  
  5664. function initColorizer(init)
  5665. {
  5666. if (init === void 0)
  5667. {
  5668. init = false;
  5669. }
  5670. var usernameList = user2Color && Array.from(user2Color.keys()) || [];
  5671. user2Color = new Map();
  5672. usedColors = new Set();
  5673. for (var _i = 0, reservedColors_1 = reservedColors; _i < reservedColors_1.length; _i++)
  5674. {
  5675. var color = reservedColors_1[_i];
  5676. usedColors.add(color);
  5677. }
  5678. var colorStyle = getStyle('name-color');
  5679. colorStyle.innerHTML = '';
  5680. for (var _a = 0, usernameList_1 = usernameList; _a < usernameList_1.length; _a++)
  5681. {
  5682. var username = usernameList_1[_a];
  5683. colorizeMsg(username);
  5684. }
  5685. if (init)
  5686. {
  5687. settings.observeSub(settings.KEY.colorizeChat, 'colorizer', function ()
  5688. {
  5689. return initColorizer();
  5690. });
  5691. }
  5692. }
  5693.  
  5694. function addIntelligentScrolling()
  5695. {
  5696. // add checkbox instead of button for toggling auto scrolling
  5697. var btn = document.querySelector('input[value="Toggle Autoscroll"]');
  5698. var btnParent = btn.parentElement;
  5699. var checkboxId = 'chat-toggle-autoscroll';
  5700. // create checkbox
  5701. var toggleCheckbox = document.createElement('input');
  5702. toggleCheckbox.type = 'checkbox';
  5703. toggleCheckbox.id = checkboxId;
  5704. toggleCheckbox.checked = true;
  5705. // create label
  5706. var toggleLabel = document.createElement('label');
  5707. toggleLabel.htmlFor = checkboxId;
  5708. toggleLabel.textContent = 'Autoscroll';
  5709. btnParent.insertBefore(toggleCheckbox, btn);
  5710. btnParent.insertBefore(toggleLabel, btn);
  5711. btn.style.display = 'none';
  5712. var chatArea = document.getElementById(GENERAL_CHAT_DIV_ID);
  5713. var showScrollTextTimeout = null;
  5714.  
  5715. function setAutoScrolling(value, full)
  5716. {
  5717. if (full === void 0)
  5718. {
  5719. full = false;
  5720. }
  5721. if (win.isAutoScrolling != value)
  5722. {
  5723. toggleCheckbox.checked = value;
  5724. win.isAutoScrolling = value;
  5725. var icon_2 = 'none';
  5726. var color_1 = value ? 'lime' : 'red';
  5727. var text_1 = (value ? 'En' : 'Dis') + 'abled' + (full ? ' Autoscroll' : '');
  5728. if (full)
  5729. {
  5730. if (showScrollTextTimeout)
  5731. {
  5732. win.clearTimeout(showScrollTextTimeout);
  5733. }
  5734. showScrollTextTimeout = win.setTimeout(function ()
  5735. {
  5736. return win.scrollText(icon_2, color_1, text_1);
  5737. }, 300);
  5738. }
  5739. else
  5740. {
  5741. win.scrollText(icon_2, color_1, text_1);
  5742. }
  5743. setNewCounter(getSelectedTab(), 0, true);
  5744. return true;
  5745. }
  5746. return false;
  5747. }
  5748. toggleCheckbox.addEventListener('change', function ()
  5749. {
  5750. setAutoScrolling(this.checked);
  5751. if (this.checked && settings.get(settings.KEY.intelligentScrolling))
  5752. {
  5753. chatArea.scrollTop = chatArea.scrollHeight - chatArea.clientHeight;
  5754. }
  5755. });
  5756. var placeholderTemplate = document.createElement('div');
  5757. placeholderTemplate.className = 'placeholder';
  5758. var childStore = new WeakMap();
  5759.  
  5760. function scrollHugeChat()
  5761. {
  5762. // # of children
  5763. var chunkNum = chatArea.children.length;
  5764. // start chunk hiding at a specific amount of chunks
  5765. if (chunkNum < CHUNK_HIDING_MIN_CHUNKS)
  5766. {
  5767. return;
  5768. }
  5769. var visibleTop = chatArea.scrollTop;
  5770. var visibleBottom = visibleTop + chatArea.clientHeight;
  5771. var referenceTop = visibleTop - win.innerHeight;
  5772. var referenceBottom = visibleBottom + win.innerHeight;
  5773. var top = 0;
  5774. // never hide the last element since its size may change at any time when a new message gets appended
  5775. for (var i = 0; i < chunkNum - 1; i++)
  5776. {
  5777. var child = chatArea.children[i];
  5778. var height = child.clientHeight;
  5779. var bottom = top + height;
  5780. var isVisible = top >= referenceTop && top <= referenceBottom
  5781. || bottom >= referenceTop && bottom <= referenceBottom
  5782. || top < referenceTop && bottom > referenceBottom;
  5783. var isPlaceholder = child.classList.contains('placeholder');
  5784. if (!isVisible && !isPlaceholder)
  5785. {
  5786. var newPlaceholder = placeholderTemplate.cloneNode(false);
  5787. newPlaceholder.style.height = height + 'px';
  5788. chatArea.replaceChild(newPlaceholder, child);
  5789. childStore.set(newPlaceholder, child);
  5790. }
  5791. else if (isVisible && isPlaceholder)
  5792. {
  5793. var oldChild = childStore.get(child);
  5794. chatArea.replaceChild(oldChild, child);
  5795. childStore.delete(child);
  5796. }
  5797. top = bottom;
  5798. }
  5799. }
  5800. var delayedScrollStart = null;
  5801. var delayedScrollTimeout = null;
  5802. // does not consider pm tabs; may be changed in a future version?
  5803. chatArea.addEventListener('scroll', function ()
  5804. {
  5805. if (settings.get(settings.KEY.intelligentScrolling))
  5806. {
  5807. var scrolled2Bottom = (chatArea.scrollTop + chatArea.clientHeight) >= chatArea.scrollHeight - 1;
  5808. setAutoScrolling(scrolled2Bottom, true);
  5809. }
  5810. var n = now();
  5811. if (delayedScrollStart == null)
  5812. {
  5813. delayedScrollStart = n;
  5814. }
  5815. if (delayedScrollStart + 300 > n)
  5816. {
  5817. if (delayedScrollTimeout)
  5818. {
  5819. win.clearTimeout(delayedScrollTimeout);
  5820. }
  5821. delayedScrollTimeout = win.setTimeout(function ()
  5822. {
  5823. delayedScrollStart = null;
  5824. delayedScrollTimeout = null;
  5825. scrollHugeChat();
  5826. }, 50);
  5827. }
  5828. });
  5829. }
  5830.  
  5831. function getSelectedTab()
  5832. {
  5833. return document.querySelector('#' + CHAT_TABS_ID + ' .chat-tab.selected');
  5834. }
  5835.  
  5836. function getSelectedTabUsername()
  5837. {
  5838. var selectedTab = getSelectedTab();
  5839. return selectedTab.dataset.username || '';
  5840. }
  5841.  
  5842. function clickChatTab(newTab)
  5843. {
  5844. var oldTab = getSelectedTab();
  5845. if (newTab == oldTab)
  5846. {
  5847. return;
  5848. }
  5849. changeChatTab(oldTab, newTab);
  5850. }
  5851.  
  5852. function clickCloseChatTab(tab)
  5853. {
  5854. var username = tab.dataset.username || '';
  5855. var chatPanel = getChatPanel(username);
  5856. if (chatPanel.children.length === 0
  5857. || confirm("Do you want to close the pm tab of \"" + username + "\"?"))
  5858. {
  5859. closeChatTab(username);
  5860. }
  5861. }
  5862.  
  5863. function checkSetting(init)
  5864. {
  5865. if (init === void 0)
  5866. {
  5867. init = false;
  5868. }
  5869. var enabled = settings.get(settings.KEY.useNewChat);
  5870. // dis-/enable chat tabs
  5871. var chatTabs = document.getElementById(CHAT_TABS_ID);
  5872. chatTabs.style.display = enabled ? '' : 'none';
  5873. // dis-/enable checkbox for intelligent scrolling
  5874. var intelScrollId = 'chat-toggle-intelligent-scroll';
  5875. var input = document.getElementById(intelScrollId);
  5876. if (input)
  5877. {
  5878. input.style.display = enabled ? '' : 'none';
  5879. }
  5880. var label = document.querySelector('label[for="' + intelScrollId + '"]');
  5881. if (label)
  5882. {
  5883. label.style.display = enabled ? '' : 'none';
  5884. }
  5885. // virtually click on a tab
  5886. var defaultTab = getChatTab('', SpecialTab.default);
  5887. var generalTab = getChatTab('', SpecialTab.general);
  5888. clickChatTab(enabled ? generalTab : defaultTab);
  5889. if (init)
  5890. {
  5891. settings.observe(settings.KEY.useNewChat, function ()
  5892. {
  5893. return checkSetting(false);
  5894. });
  5895. }
  5896. }
  5897.  
  5898. function addChatTabs()
  5899. {
  5900. var chatBoxArea = document.getElementById(CHAT_BOX_ID);
  5901. var chatTabs = document.createElement('div');
  5902. chatTabs.id = CHAT_TABS_ID;
  5903. chatTabs.addEventListener('click', function (event)
  5904. {
  5905. var newTab = event.target;
  5906. if (newTab.classList.contains('close'))
  5907. {
  5908. return clickCloseChatTab(newTab.parentElement);
  5909. }
  5910. if (!newTab.classList.contains('chat-tab') || newTab.classList.contains('filler'))
  5911. {
  5912. return;
  5913. }
  5914. clickChatTab(newTab);
  5915. });
  5916. chatBoxArea.appendChild(chatTabs);
  5917. // default tab (for disabled new chat)
  5918. getChatTab('', SpecialTab.default);
  5919. // general server chat
  5920. var generalTab = getChatTab('', SpecialTab.general);
  5921. generalTab.textContent = 'Server';
  5922. getChatPanel('');
  5923. getChatTab('', SpecialTab.filler);
  5924. var _sendChat = win.sendChat;
  5925. win.sendChat = function (inputEl)
  5926. {
  5927. var msg = inputEl.value;
  5928. var selectedTab = document.querySelector('.chat-tab.selected');
  5929. if (selectedTab.dataset.username != '' && msg[0] != '/')
  5930. {
  5931. inputEl.value = '/pm ' + (selectedTab.dataset.username || '').replace(/ /g, '_') + ' ' + msg;
  5932. }
  5933. _sendChat(inputEl);
  5934. };
  5935. }
  5936.  
  5937. function switch2PmTab(username)
  5938. {
  5939. if (settings.get(settings.KEY.useNewChat)){
  5940. var newTab = getChatTab(username, null);
  5941. clickChatTab(newTab);
  5942. }
  5943. }
  5944.  
  5945. function notifyPm(data)
  5946. {
  5947. notifications.event('Message from "' + data.username + '"'
  5948. , {
  5949. body: data.msg
  5950. , onclick: function ()
  5951. {
  5952. return switch2PmTab(data.username);
  5953. }
  5954. , whenActive: getSelectedTab().dataset.username != data.username
  5955. });
  5956. }
  5957.  
  5958. function checkMentionAndKeywords(data)
  5959. {
  5960. var lowerMsg = data.msg.toLowerCase();
  5961. var usernameRegex = new RegExp('\\b' + win.username + '\\b', 'i');
  5962. if (settings.getSub(settings.KEY.showNotifications, 'mention') && usernameRegex.test(lowerMsg))
  5963. // if (lowerMsg.indexOf(win.username) > -1)
  5964. {
  5965. notifications.event('You\'ve been mentioned'
  5966. , {
  5967. body: data.msg
  5968. });
  5969. }
  5970. var match = [];
  5971. for (var _i = 0, keywordList_1 = chat.keywordList; _i < keywordList_1.length; _i++)
  5972. {
  5973. var keyword = keywordList_1[_i];
  5974. var regex = new RegExp('\\b' + keyword + '\\b', 'i');
  5975. if (regex.test(lowerMsg))
  5976. // if (lowerMsg.indexOf(keyword) > -1)
  5977. {
  5978. match.push(keyword);
  5979. }
  5980. }
  5981. if (settings.getSub(settings.KEY.showNotifications, 'keyword') && match.length > 0)
  5982. {
  5983. notifications.event('Keyword: "' + match.join('", "') + '"'
  5984. , {
  5985. body: data.msg
  5986. });
  5987. }
  5988. }
  5989. var addToChatBox_ = null;
  5990.  
  5991. function newAddToChatBox(username, icon, tag, msg, isPM)
  5992. {
  5993. var data = processChatData(username, icon, tag, msg, isPM);
  5994. var isThisSpam = false;
  5995. if (isDataPM(data))
  5996. {
  5997. if (data.type == Type.pmSent)
  5998. {
  5999. switch2PmTab(data.username);
  6000. }
  6001. else
  6002. {
  6003. notifyPm(data);
  6004. }
  6005. }
  6006. else
  6007. {
  6008. isThisSpam = settings.get(settings.KEY.enableSpamDetection) && isSpam(data);
  6009. if (!isThisSpam && data.username != win.username)
  6010. {
  6011. // check mentioning and keywords only for non-pms and only for messages from other players
  6012. checkMentionAndKeywords(data);
  6013. }
  6014. }
  6015. if (isThisSpam)
  6016. {
  6017. console.info('detected spam:', data);
  6018. }
  6019. else
  6020. {
  6021. add2ChatHistory(data);
  6022. add2Chat(data);
  6023. }
  6024. var fn = addToChatBox_ == null ? win.addToChatBox : addToChatBox_;
  6025. fn(username, icon, tag, msg, isPM);
  6026. }
  6027. chat.newAddToChatBox = newAddToChatBox;
  6028.  
  6029. function openPmTab(username)
  6030. {
  6031. if (username == win.username || username == '')
  6032. {
  6033. return;
  6034. }
  6035. var userTab = getChatTab(username, null);
  6036. clickChatTab(userTab);
  6037. var input = document.getElementById(CHAT_INPUT_ID);
  6038. input.focus();
  6039. }
  6040.  
  6041. function newChat()
  6042. {
  6043. addChatTabs();
  6044. applyChatStyle();
  6045. initColorizer(true);
  6046. addToChatBox_ = win.addToChatBox;
  6047. win.addToChatBox = newAddToChatBox;
  6048. chatInitialized = true;
  6049. var chatbox = document.getElementById(CHAT_BOX_ID);
  6050. chatbox.addEventListener('click', function (event)
  6051. {
  6052. var target = event.target;
  6053. var userEl = target && target.parentElement;
  6054. if (!target || !userEl || !target.classList.contains('name') || !userEl.classList.contains('user'))
  6055. {
  6056. return;
  6057. }
  6058. if (userEl.dataset.sameUser != 'true')
  6059. {
  6060. openPmTab(userEl.dataset.name || '');
  6061. }
  6062. });
  6063. chatbox.addEventListener('mouseover', function (event)
  6064. {
  6065. var target = event.target;
  6066. if (!target.classList.contains('timestamp') || !target.dataset.timestamp)
  6067. {
  6068. return;
  6069. }
  6070. var timestamp = parseInt(target.dataset.timestamp || '0', 10);
  6071. target.dataset.fulltime = (new Date(timestamp)).toLocaleDateString(LOCALE, LOCALE_OPTIONS);
  6072. target.dataset.timestamp = '';
  6073. });
  6074. // add context menu
  6075. var contextmenu = document.createElement('ul');
  6076. contextmenu.id = CONTEXTMENU_ID;
  6077. contextmenu.style.display = 'none';
  6078. 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>";
  6079. document.body.appendChild(contextmenu);
  6080. win.$(contextmenu).menu(
  6081. {
  6082. items: '> :not(.ui-widget-header)'
  6083. });
  6084. var nameListEl = contextmenu.querySelector('.name');
  6085. var nameDivEl = nameListEl.firstElementChild;
  6086. var muteEl = contextmenu.querySelector('.mute');
  6087. var unmuteEl = contextmenu.querySelector('.unmute');
  6088. chatbox.addEventListener('contextmenu', function (event)
  6089. {
  6090. var target = event.target;
  6091. var userEl = target && target.parentElement;
  6092. if (!userEl || !userEl.classList.contains('user'))
  6093. {
  6094. return;
  6095. }
  6096. var username = userEl.dataset.name;
  6097. // ignore clicks on server messages or other special messages
  6098. if (!username || userEl.dataset.sameUser == 'true')
  6099. {
  6100. return;
  6101. }
  6102. contextmenu.style.left = event.clientX + 'px';
  6103. contextmenu.style.top = event.clientY + 'px';
  6104. contextmenu.style.display = '';
  6105. contextmenu.dataset.username = username;
  6106. nameDivEl.textContent = username;
  6107. var isMuted = win.mutedPeople.indexOf(username) !== -1;
  6108. muteEl.style.display = isMuted ? 'none' : '';
  6109. unmuteEl.style.display = isMuted ? '' : 'none';
  6110. event.stopPropagation();
  6111. event.preventDefault();
  6112. });
  6113. // add click listener for context menu and stop propagation
  6114. contextmenu.addEventListener('click', function (event)
  6115. {
  6116. var target = event.target;
  6117. event.stopPropagation();
  6118. while (target && target.id != CONTEXTMENU_ID && target.tagName != 'LI')
  6119. {
  6120. target = target.parentElement;
  6121. }
  6122. if (!target || target.id == CONTEXTMENU_ID)
  6123. {
  6124. return;
  6125. }
  6126. var username = contextmenu.dataset.username || '';
  6127. if (target.classList.contains('open-pm'))
  6128. {
  6129. openPmTab(username);
  6130. }
  6131. else if (target.classList.contains('stats'))
  6132. {
  6133. win.lookup(username);
  6134. }
  6135. else if (target.classList.contains('mute'))
  6136. {
  6137. if (username == '')
  6138. {
  6139. return;
  6140. }
  6141. win.mutedPeople.push(username);
  6142. win.scrollText('none', 'lime', '<em>' + username + '</em> muted');
  6143. }
  6144. else if (target.classList.contains('unmute'))
  6145. {
  6146. if (username == '')
  6147. {
  6148. return;
  6149. }
  6150. var index = win.mutedPeople.indexOf(username);
  6151. if (index !== -1)
  6152. {
  6153. win.mutedPeople.splice(index, 1);
  6154. }
  6155. win.scrollText('none', 'red', '<em>' + username + '</em> unmuted');
  6156. }
  6157. else
  6158. {
  6159. return;
  6160. }
  6161. contextmenu.style.display = 'none';
  6162. });
  6163. // add click listener to hide context menu
  6164. document.addEventListener('click', function (event)
  6165. {
  6166. if (contextmenu.style.display != 'none')
  6167. {
  6168. contextmenu.style.display = 'none';
  6169. }
  6170. });
  6171. win.addEventListener('contextmenu', function (event)
  6172. {
  6173. if (contextmenu.style.display != 'none')
  6174. {
  6175. contextmenu.style.display = 'none';
  6176. }
  6177. });
  6178. // handle settings
  6179. var showSettings = [settings.KEY.showTimestamps, settings.KEY.showIcons, settings.KEY.showTags];
  6180.  
  6181. function setShowSetting(key)
  6182. {
  6183. var enabled = settings.get(key);
  6184. chatbox.classList[enabled ? 'add' : 'remove'](settings.KEY[key]);
  6185. }
  6186. for (var _i = 0, showSettings_1 = showSettings; _i < showSettings_1.length; _i++)
  6187. {
  6188. var key = showSettings_1[_i];
  6189. setShowSetting(key);
  6190. settings.observe(key, function (k)
  6191. {
  6192. return setShowSetting(k);
  6193. });
  6194. }
  6195. }
  6196.  
  6197. function addCommandSuggester()
  6198. {
  6199. var input = document.getElementById(CHAT_INPUT_ID);
  6200. input.addEventListener('keyup', function (event)
  6201. {
  6202. if (event.key == 'Backspace' || event.key == 'Delete' || event.key == 'Enter' || event.key == 'Tab'
  6203. || input.selectionStart != input.selectionEnd
  6204. || input.selectionStart != input.value.length
  6205. || !input.value.startsWith('/'))
  6206. {
  6207. return;
  6208. }
  6209. var value = input.value.substr(1);
  6210. for (var _i = 0, COMMANDS_1 = COMMANDS; _i < COMMANDS_1.length; _i++)
  6211. {
  6212. var cmd = COMMANDS_1[_i];
  6213. if (cmd.startsWith(value))
  6214. {
  6215. input.value = '/' + cmd;
  6216. input.selectionStart = 1 + value.length;
  6217. input.selectionEnd = input.value.length;
  6218. break;
  6219. }
  6220. }
  6221. });
  6222. }
  6223.  
  6224. function addOwnCommands()
  6225. {
  6226. COMMANDS.push(TUTORIAL_CMD);
  6227.  
  6228. function processOwnCommands(value)
  6229. {
  6230. if (!value.startsWith('/'))
  6231. {
  6232. return value;
  6233. }
  6234. var msgPrefix = '/';
  6235. var msg = value.substr(1);
  6236. if (msg.startsWith('pm'))
  6237. {
  6238. var split = msg.split(' ');
  6239. msgPrefix = '/' + split.slice(0, 2).join(' ') + ' ';
  6240. msg = split.slice(2).join(' ');
  6241. }
  6242. if (msg.startsWith(CLEAR_CMD))
  6243. {
  6244. // clear current chat (pm chat, or general chat)
  6245. var username = getSelectedTabUsername();
  6246. clearChat(username);
  6247. }
  6248. else if (msg.startsWith(TUTORIAL_CMD))
  6249. {
  6250. // thanks aguyd (https://greasyfork.org/forum/profile/aguyd) for the idea
  6251. var name_2 = msg.substr(TUTORIAL_CMD.length).trim();
  6252. msgPrefix = '';
  6253. msg = 'https://www.reddit.com/r/DiamondHunt/comments/5vrufh/diamond_hunt_2_starter_faq/';
  6254. if (name_2.length != 0)
  6255. {
  6256. // maybe add '@' before the name?
  6257. msg = name_2 + ', ' + msg;
  6258. }
  6259. }
  6260. return msgPrefix + msg;
  6261. }
  6262. var _sendChat = win.sendChat;
  6263. win.sendChat = function (inputEl)
  6264. {
  6265. inputEl.value = processOwnCommands(inputEl.value);
  6266. _sendChat(inputEl);
  6267. };
  6268. }
  6269.  
  6270. function checkColorize(init)
  6271. {
  6272. if (init === void 0)
  6273. {
  6274. init = false;
  6275. }
  6276. var chatDiv = document.getElementById(CHAT_BOX_ID);
  6277. chatDiv.classList[settings.get(settings.KEY.colorizeChat) ? 'add' : 'remove'](COLORIZE_CLASS);
  6278. if (init)
  6279. {
  6280. settings.observe(settings.KEY.colorizeChat, function ()
  6281. {
  6282. return checkColorize(false);
  6283. });
  6284. }
  6285. }
  6286.  
  6287. function init()
  6288. {
  6289. newChat();
  6290. addIntelligentScrolling();
  6291. addCommandSuggester();
  6292. addOwnCommands();
  6293. checkColorize(true);
  6294. checkSetting(true);
  6295. var _enlargeChat = win.enlargeChat;
  6296. var chatBoxArea = document.getElementById(CHAT_BOX_ID);
  6297.  
  6298. function setChatBoxHeight(height)
  6299. {
  6300. var defaultChat = document.getElementById(DEFAULT_CHAT_DIV_ID);
  6301. defaultChat.style.height = height;
  6302. var generalChat = document.getElementById(GENERAL_CHAT_DIV_ID);
  6303. generalChat.style.height = height;
  6304. var chatDivs = chatBoxArea.querySelectorAll('div[id^="' + PM_CHAT_DIV_PREFIX + '"]');
  6305. for (var i = 0; i < chatDivs.length; i++)
  6306. {
  6307. chatDivs[i].style.height = height;
  6308. }
  6309. }
  6310. win.enlargeChat = function (enlargeB)
  6311. {
  6312. _enlargeChat(enlargeB);
  6313. var defaultChatDiv = document.getElementById(DEFAULT_CHAT_DIV_ID);
  6314. var height = defaultChatDiv.style.height;
  6315. store.set('chat.height', height);
  6316. setChatBoxHeight(height);
  6317. handleScrolling(defaultChatDiv);
  6318. };
  6319. setChatBoxHeight(store.get('chat.height'));
  6320. // add history to chat
  6321. // TEMP >>>
  6322. // move pm entries to pm history
  6323. var changed = false;
  6324. for (var i = 0; i < chatHistory.length; i++)
  6325. {
  6326. var data = chatHistory[i];
  6327. if (isDataPM(data))
  6328. {
  6329. chatHistory.splice(i, 1);
  6330. i--;
  6331. pmHistory.push(data);
  6332. changed = true;
  6333. }
  6334. }
  6335. if (changed)
  6336. {
  6337. saveChatHistory();
  6338. savePmHistory();
  6339. }
  6340. // TEMP <<<
  6341. chatHistory.forEach(function (d)
  6342. {
  6343. return add2Chat(d);
  6344. });
  6345. pmHistory.forEach(function (d)
  6346. {
  6347. return add2Chat(d);
  6348. });
  6349. if (chatboxFragments)
  6350. {
  6351. chatboxFragments.forEach(function (fragment, key)
  6352. {
  6353. var chatbox = getChatPanel(key);
  6354. chatbox.appendChild(fragment);
  6355. });
  6356. chatboxFragments = null;
  6357. }
  6358. // reset the new counter for all tabs
  6359. var tabs = document.querySelectorAll('.chat-tab');
  6360. for (var i = 0; i < tabs.length; i++)
  6361. {
  6362. setNewCounter(tabs[i], 0, true);
  6363. }
  6364. }
  6365. chat.init = init;
  6366. var _a;
  6367. })(chat || (chat = {}));
  6368.  
  6369. /**
  6370. * hopefully only temporary fixes
  6371. */
  6372. var temporaryFixes;
  6373. (function (temporaryFixes)
  6374. {
  6375. temporaryFixes.name = 'temporaryFixes';
  6376. function fixWrongURLs()
  6377. {
  6378. var image = document.querySelectorAll('.dialogue-loot .image-icon-50');
  6379. for (var i=0; i < image.length; i++){
  6380. var key = image[i];
  6381. var change = key.src = key.src.replace('/images/icons/darkTombKey.png','/images/darkTombKey.png');
  6382. }
  6383. }
  6384. // update spells being clickable in combat
  6385. function setSpellsClickable()
  6386. {
  6387. var spellbox = document.getElementById('fight-spellboox');
  6388. if (spellbox)
  6389. {
  6390. for (var i = 0; i < spellbox.children.length; i++)
  6391. {
  6392. var child = spellbox.children.item(i);
  6393. if (!win.isInCombat() && child.hasAttribute('onclick'))
  6394. {
  6395. child.dataset.onclick = child.getAttribute('onclick') || '';
  6396. child.removeAttribute('onclick');
  6397. }
  6398. else if (win.isInCombat() && !!child.dataset.onclick)
  6399. {
  6400. child.setAttribute('onclick', child.dataset.onclick || '');
  6401. child.dataset.onclick = '';
  6402. }
  6403. }
  6404. }
  6405. }
  6406. // warn before unloading/reloading the tab if combat is in progress
  6407. function combatWarnOnUnload()
  6408. {
  6409. if (!win.isInCombat())
  6410. {
  6411. win.onbeforeunload = null;
  6412. }
  6413. else
  6414. {
  6415. if (win.onbeforeunload == null)
  6416. {
  6417. win.onbeforeunload = function ()
  6418. {
  6419. return 'You are in a fight!';
  6420. };
  6421. }
  6422. }
  6423. }
  6424.  
  6425. function fixCombatCountdown()
  6426. {
  6427. var el = document.getElementById('combat-countdown');
  6428. if (!el)
  6429. {
  6430. return;
  6431. }
  6432. if (win.isInCombat())
  6433. {
  6434. el.style.display = '';
  6435. var visible = win.combatCommenceTimer != 0;
  6436. el.style.visibility = visible ? '' : 'hidden';
  6437. }
  6438. }
  6439. // fix exhaustion timer and updating brewing and cooking recipes
  6440. function fixExhaustionTimer()
  6441. {
  6442. if (document.getElementById('tab-container-combat').style.display != 'none')
  6443. {
  6444. win.combatNotFightingTick();
  6445. }
  6446. }
  6447.  
  6448. function fixClientGameLoop()
  6449. {
  6450. var _clientGameLoop = win.clientGameLoop;
  6451. win.clientGameLoop = function ()
  6452. {
  6453. _clientGameLoop();
  6454. //setSpellsClickable();
  6455. combatWarnOnUnload();
  6456. fixCombatCountdown();
  6457. fixExhaustionTimer();
  6458. };
  6459. }
  6460. // fix elements of scrollText (e.g. when joining the game and receiving xp at that moment)
  6461. function fixScroller()
  6462. {
  6463. var textEls = document.querySelectorAll('div.scroller');
  6464. for (var i = 0; i < textEls.length; i++)
  6465. {
  6466. var scroller = textEls[i];
  6467. if (scroller.style.position != 'absolute')
  6468. {
  6469. scroller.style.display = 'none';
  6470. }
  6471. }
  6472. }
  6473. // fix style of tooltips
  6474. function fixTooltipStyle()
  6475. {
  6476. addStyle("\nbody > div.tooltip > h2:first-child\n{\n\tmargin-top: 0;\n\tfont-size: 20pt;\n\tfont-weight: normal;\n}\n\t\t");
  6477. }
  6478. // fix buiulding magic table dynamically
  6479. function fixRefreshingMagicRecipes()
  6480. {
  6481. // define missing properties for checking the needed materials
  6482. win.enchantStargemPotionMagic = 0;
  6483. win.changeWeatherMagic = 0;
  6484. win.refreshLoadMagicTable = false;
  6485. var _processMagicTab = win.processMagicTab;
  6486. win.processMagicTab = function ()
  6487. {
  6488. var _refreshLoadCraftingTable = win.refreshLoadCraftingTable;
  6489. win.refreshLoadCraftingTable = win.refreshLoadMagicTable;
  6490. _processMagicTab();
  6491. win.refreshLoadCraftingTable = _refreshLoadCraftingTable;
  6492. if (win.magicPage3 == 1)
  6493. {
  6494. win.showMateriesNeededAndLevelLabelsMagic('enchantStargemPotion');
  6495. win.showMateriesNeededAndLevelLabelsMagic('beam');
  6496. win.showMateriesNeededAndLevelLabelsMagic('changeWeather');
  6497. }
  6498. };
  6499. }
  6500.  
  6501. function moveItemBox(itemKey, targetElId, color1, color2)
  6502. {
  6503. var itemBox = document.getElementById('item-box-' + itemKey);
  6504. var targetContainer = document.getElementById(targetElId);
  6505. targetContainer.appendChild(itemBox);
  6506. // remove event listeners before binding the tooltip to it
  6507. var $itemBox = win.$(itemBox);
  6508. $itemBox.off('mouseover').off('mouseleave');
  6509. itemBox.title = '';
  6510. // bind tooltip to item box
  6511. ensureTooltip('ingredient-secondary', itemBox);
  6512. // change color
  6513. itemBox.style.background = 'linear-gradient(' + color1 + ', ' + color2 + ')';
  6514. $itemBox
  6515. .mouseover(function ()
  6516. {
  6517. itemBox.style.background = 'none';
  6518. itemBox.style.backgroundColor = color2;
  6519. })
  6520. .mouseleave(function ()
  6521. {
  6522. itemBox.style.background = 'linear-gradient(' + color1 + ', ' + color2 + ')';
  6523. });
  6524. }
  6525. // move the strange leaf to brewing tab (thanks lasse_brus for this idea)
  6526. function moveStrangeLeafs()
  6527. {
  6528. //moveItemBox('strangeBlueLeaf', 'tab-sub-container-brewing', '#800080', '#990099');
  6529. //moveItemBox('strangePinkLeaf', 'tab-sub-container-brewing', '#800080', '#990099');
  6530. }
  6531. // fix height of map item
  6532. function fixTreasureMap()
  6533. {
  6534. var mapBox = document.getElementById('item-box-treasureMap');
  6535. var numSpan = mapBox.lastElementChild;
  6536. numSpan.style.display = '';
  6537. numSpan.style.visibility = 'hidden';
  6538. }
  6539. // fix wobbling tree places on hover (in wood cutting)
  6540. function fixWoodcutting()
  6541. {
  6542. addStyle("\nimg.woodcutting-tree-img\n{\n\tborder: 1px solid transparent;\n}\n\t\t");
  6543. }
  6544. // fix wobbling quest rows on hover (in quest book)
  6545. function fixQuestBook()
  6546. {
  6547. addStyle("\n#table-quest-list tr\n{\n\tborder: 1px solid transparent;\n}\n\t\t");
  6548. }
  6549.  
  6550. function fixScrollImages()
  6551. {
  6552. function fixIcon(icon)
  6553. {
  6554. return icon + (icon != 'none' && !/\..{3,4}$/.test(icon) ? '.png' : '');
  6555. }
  6556. var _scrollTextHitSplat = win.scrollTextHitSplat;
  6557. win.scrollTextHitSplat = function (icon, color, text, elId, cbType)
  6558. {
  6559. _scrollTextHitSplat(fixIcon(icon), color, text, elId, cbType);
  6560. };
  6561. var _scrollText = win.scrollText;
  6562. win.scrollText = function (icon, color, text)
  6563. {
  6564. _scrollText(fixIcon(icon), color, text);
  6565. };
  6566. }
  6567.  
  6568. function fixQuest8BraveryRecipe()
  6569. {
  6570. observer.add([
  6571. 'quest8'
  6572. , 'braveryPotion'
  6573. ], function ()
  6574. {
  6575. var show = win.quest8 > 0 && win.braveryPotion == 0;
  6576. var recipe = document.getElementById('brewing-braveryPotion');
  6577. if (recipe)
  6578. {
  6579. recipe.style.display = show ? '' : 'none';
  6580. }
  6581. });
  6582. }
  6583.  
  6584. function fixHitText()
  6585. {
  6586. win.scrollTextHitSplat = function (icon, color, text, elId, cbType)
  6587. {
  6588. var imgTag = icon != 'none' ? "<img src=\"images/" + icon + "\" class=\"image-icon-50\" />" : '';
  6589. var elementChosen = document.getElementById(elId);
  6590. if (!elementChosen)
  6591. {
  6592. return;
  6593. }
  6594. var rect = elementChosen.getBoundingClientRect();
  6595. var xCoord = (rect.left + rect.right) / 2;
  6596. var yCoord = (rect.bottom + rect.top) / 2;
  6597. var extraStyle = '';
  6598. if (cbType == 'melee')
  6599. {
  6600. extraStyle = 'border: 1px solid red; background-color: #4d0000;';
  6601. }
  6602. else if (cbType == 'heal')
  6603. {
  6604. extraStyle = 'border: 1px solid green; background-color: lime;';
  6605. }
  6606. var $elementToAppend = win.$("<div class=\"scroller\" style=\"" + extraStyle + " color: " + color + "; position: fixed;\">" + imgTag + text + "</div>").appendTo('body');
  6607. if (xCoord == 0 && yCoord == 0)
  6608. {
  6609. var tab = document.getElementById('tab-container-bar-combat');
  6610. var tabRect = tab.getBoundingClientRect();
  6611. var boxRect = $elementToAppend.get(0).getBoundingClientRect();
  6612. xCoord = elId == 'img-hero' ? (tabRect.left - boxRect.width) : tabRect.right;
  6613. yCoord = tabRect.top;
  6614. }
  6615. $elementToAppend
  6616. .css(
  6617. {
  6618. left: xCoord
  6619. , top: yCoord
  6620. })
  6621. .animate(
  6622. {
  6623. top: '-=50px'
  6624. }, function ()
  6625. {
  6626. return $elementToAppend.fadeOut(1000, function ()
  6627. {
  6628. return $elementToAppend.remove();
  6629. });
  6630. });
  6631. };
  6632. }
  6633.  
  6634. function fixBoatTooltips()
  6635. {
  6636. var boatBox = document.getElementById('item-box-boundRowBoat');
  6637. var boatTooltip = boatBox && document.getElementById(boatBox.dataset.tooltipId || '');
  6638. var tooltipParent = boatTooltip && boatTooltip.parentElement;
  6639. if (!boatBox || !boatTooltip || !tooltipParent)
  6640. {
  6641. return;
  6642. }
  6643.  
  6644. function setTripDuration(durationEl, boatKey)
  6645. {
  6646. var durationStr = TRIP_DURATION.hasOwnProperty(boatKey) ? TRIP_DURATION[boatKey].toString(10) : '?';
  6647. durationEl.innerHTML = "<strong>Trip duration:</strong> " + durationStr + " hours";
  6648. }
  6649. boatTooltip.id = boatBox.dataset.tooltipId = 'tooltip-boundRowBoat';
  6650. boatTooltip.appendChild(document.createElement('br'));
  6651. var boatDuration = document.createElement('span');
  6652. boatDuration.className = 'trip-duration';
  6653. setTripDuration(boatDuration, 'rowBoat');
  6654. boatTooltip.appendChild(boatDuration);
  6655. for (var _i = 0, BOAT_LIST_1 = BOAT_LIST; _i < BOAT_LIST_1.length; _i++)
  6656. {
  6657. var boatKey = BOAT_LIST_1[_i];
  6658. var boundKey = getBoundKey(boatKey);
  6659. var itemBox = document.getElementById('item-box-' + boundKey);
  6660. if (!itemBox)
  6661. {
  6662. continue;
  6663. }
  6664. var tooltip = document.getElementById('tooltip-' + boundKey);
  6665. if (!tooltip)
  6666. {
  6667. tooltip = boatTooltip.cloneNode(true);
  6668. tooltip.id = 'tooltip-' + boundKey;
  6669. var header = tooltip.firstElementChild;
  6670. header.textContent = capitalize(split2Words(boatKey));
  6671. tooltipParent.appendChild(tooltip);
  6672. itemBox.dataset.tooltipId = 'tooltip-' + boundKey;
  6673. }
  6674. var durationEl = tooltip.getElementsByClassName('trip-duration').item(0);
  6675. if (durationEl)
  6676. {
  6677. setTripDuration(durationEl, boatKey);
  6678. }
  6679. }
  6680. }
  6681.  
  6682. function fixAlignments()
  6683. {
  6684. 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");
  6685. }
  6686. function fixFontSize11Tabs()
  6687. {
  6688. var tabKey = ['items', 'skills', 'mining', 'crafting', 'woodcutting', 'farming', 'brewing', 'combat', 'magic', 'cooking', 'shop'];
  6689. for (var i = 0; i < tabKey.length; i++)
  6690. {
  6691. var tab = document.getElementById('tab-container-bar-'+ tabKey[i] +'-label');
  6692. tab.style.fontSize = "15px";
  6693. }
  6694. }
  6695. function addSpellTooltips()
  6696. {
  6697. var heal = document.querySelector('[data-spell-name="heal"]');
  6698. heal.title = 'Mana: 2';
  6699. win.$(heal).tooltip();
  6700. var pound = document.querySelector('[data-spell-name="pound"]');
  6701. pound.title = 'Mana: 2';
  6702. win.$(pound).tooltip();
  6703. var teleport = document.querySelector('[data-spell-name="teleport"]');
  6704. teleport.title = 'Mana: 10';
  6705. win.$(teleport).tooltip();
  6706. var gust = document.querySelector('[data-spell-name="gust"]');
  6707. gust.title = 'Mana: 3';
  6708. win.$(gust).tooltip();
  6709. var bubble = document.querySelector('[data-spell-name="bubble"]');
  6710. bubble.title = 'Mana: 10';
  6711. win.$(bubble).tooltip();
  6712. var sandstorm = document.querySelector('[data-spell-name="sandstorm"]');
  6713. sandstorm.title = 'Mana: 20';
  6714. win.$(sandstorm).tooltip();
  6715. var ghostScan = document.querySelector('[data-spell-name="ghostScan"]');
  6716. ghostScan.title = 'Mana: 20';
  6717. win.$(ghostScan).tooltip();
  6718. var beam = document.querySelector('[data-spell-name="beam"]');
  6719. beam.title = 'Mana: 15';
  6720. win.$(beam).tooltip();
  6721. var reflect = document.querySelector('[data-spell-name="reflect"]');
  6722. reflect.title = 'Mana: 20';
  6723. win.$(reflect).tooltip();
  6724. var superHeal = document.querySelector('[data-spell-name="superHeal"]');
  6725. superHeal.title = 'Mana: 8';
  6726. win.$(superHeal).tooltip();
  6727. var barrier = document.querySelector('[data-spell-name="barrier"]');
  6728. barrier.title = 'Mana: 25';
  6729. win.$(barrier).tooltip();
  6730. var healSteal = document.querySelector('[data-spell-name="healSteal"]');
  6731. healSteal.title = 'Mana: 25';
  6732. win.$(healSteal).tooltip();
  6733. var poison = document.querySelector('[data-spell-name="poison"]');
  6734. poison.title = 'Mana: 30';
  6735. win.$(poison).tooltip();
  6736. }
  6737. function modifySpellImages()
  6738. {
  6739. var spell = document.querySelectorAll('.fight-spell');
  6740. for (var i = 0; i < 15; i++){
  6741. spell[i].style.width = '43px';
  6742. spell[i].style.height = '43px';
  6743. }
  6744. var img= [];
  6745. for (var i = 0; i < 15; i++){
  6746. img[i] = spell[i].getElementsByTagName('img')[0];
  6747. img[i].style.width = '43px';
  6748. }
  6749. }
  6750. function addHeroStatTooltips()
  6751. {
  6752. var table = document.querySelector('#hero-area table.table-hero-stats');
  6753. if (!table)
  6754. {
  6755. return;
  6756. }
  6757. var statRow = table.rows.item(0);
  6758. var attackCell = statRow.cells.item(0);
  6759. attackCell.title = 'Attack Damage';
  6760. win.$(attackCell).tooltip();
  6761. var accuracyCell = statRow.cells.item(1);
  6762. accuracyCell.title = 'Attack Accuracy';
  6763. win.$(accuracyCell).tooltip();
  6764. var speedCell = statRow.cells.item(2);
  6765. speedCell.title = 'Attack Speed';
  6766. win.$(speedCell).tooltip();
  6767. var defenseCell = statRow.cells.item(3);
  6768. defenseCell.title = 'Defense';
  6769. win.$(defenseCell).tooltip();
  6770. var magicCell = statRow.cells.item(4);
  6771. magicCell.title = 'Magic Bonus';
  6772. win.$(magicCell).tooltip();
  6773. // energy, cooldown, HP and mana
  6774. var energyRow = table.rows.item(1);
  6775. var energy = energyRow.cells.item(0);
  6776. energy.title = 'Energy';
  6777. var cdRow = table.rows.item(2);
  6778. var cd = cdRow.cells.item(0);
  6779. cd.title = 'Combat Cooldown';
  6780. var getHPbar = document.querySelectorAll('.inner-hp-bar-label');
  6781. getHPbar[0].title = 'Health Points';
  6782. var getManabar = document.querySelectorAll('.inner-mana-bar-label');
  6783. getManabar[0].title = 'Mana Points';
  6784. }
  6785.  
  6786. function unifyTooltips()
  6787. {
  6788. function getLastNonEmptyChild(parent)
  6789. {
  6790. for (var i = parent.childNodes.length - 1; i >= 0; i--)
  6791. {
  6792. var child = parent.childNodes.item(i);
  6793. if (child.nodeType === Node.TEXT_NODE
  6794. && (child.textContent || '').trim() !== '')
  6795. {
  6796. return null;
  6797. }
  6798. else if (child.nodeType === Node.ELEMENT_NODE)
  6799. {
  6800. return child;
  6801. }
  6802. }
  6803. return null;
  6804. }
  6805. // clean unnecessary br-tags in tooltips
  6806. var tooltips = document.querySelectorAll('#tooltip-list > div[id^="tooltip-"]');
  6807. for (var i = 0; i < tooltips.length; i++)
  6808. {
  6809. var tooltip = tooltips[i];
  6810. var lneChild = void 0;
  6811. while ((lneChild = getLastNonEmptyChild(tooltip)) && lneChild.tagName == 'BR')
  6812. {
  6813. tooltip.removeChild(lneChild);
  6814. }
  6815. }
  6816.  
  6817. function getTooltip(item)
  6818. {
  6819. return document.getElementById('tooltip-' + item);
  6820. }
  6821. var boldify = [
  6822. 'oilBarrel'
  6823. , 'boundEmptyPickaxe'
  6824. , 'boundEmptyShovel'
  6825. , 'boundRocket'
  6826. , 'ashes'
  6827. , 'iceBones'
  6828. ];
  6829. var lastDotRegex = /\.\s*$/;
  6830. for (var _i = 0, boldify_1 = boldify; _i < boldify_1.length; _i++)
  6831. {
  6832. var item = boldify_1[_i];
  6833. var tooltip = getTooltip(item);
  6834. if (!tooltip)
  6835. {
  6836. continue;
  6837. }
  6838. var textNode = tooltip.lastChild;
  6839. while (textNode && (textNode.nodeType != Node.TEXT_NODE || (textNode.textContent || '').trim() === ''))
  6840. {
  6841. if (textNode.nodeName === 'SPAN')
  6842. {
  6843. textNode = textNode.lastChild;
  6844. }
  6845. else
  6846. {
  6847. textNode = textNode.previousSibling;
  6848. }
  6849. }
  6850. if (!textNode)
  6851. {
  6852. continue;
  6853. }
  6854. var text = textNode.textContent || '';
  6855. var split = text.split(/\.(?=\s*\S+)/);
  6856. var clickText = split[split.length - 1];
  6857. textNode.textContent = text.replace(clickText, '');
  6858. if (split.length > 1)
  6859. {
  6860. tooltip.appendChild(document.createElement('br'));
  6861. tooltip.appendChild(document.createElement('br'));
  6862. }
  6863. var boldText = document.createElement('b');
  6864. boldText.textContent = clickText;
  6865. tooltip.appendChild(boldText);
  6866. }
  6867.  
  6868. function prepareTooltip(item, editText, createOnMissing)
  6869. {
  6870. if (createOnMissing === void 0)
  6871. {
  6872. createOnMissing = false;
  6873. }
  6874. var tooltip = getTooltip(item);
  6875. if (!tooltip)
  6876. {
  6877. return;
  6878. }
  6879. // try to find the b-node:
  6880. var bNode = getLastNonEmptyChild(tooltip);
  6881. if (bNode && bNode.tagName === 'SPAN')
  6882. {
  6883. bNode = getLastNonEmptyChild(bNode);
  6884. }
  6885. if (!bNode || bNode.tagName !== 'B')
  6886. {
  6887. if (!createOnMissing)
  6888. {
  6889. bNode = null;
  6890. }
  6891. else
  6892. {
  6893. tooltip.appendChild(document.createElement('br'));
  6894. tooltip.appendChild(document.createElement('br'));
  6895. bNode = document.createElement('b');
  6896. tooltip.appendChild(bNode);
  6897. }
  6898. }
  6899. if (bNode)
  6900. {
  6901. bNode.textContent = editText(bNode);
  6902. }
  6903. }
  6904. // remove dots
  6905. for (var i = 0; i < tooltips.length; i++)
  6906. {
  6907. var item = tooltips.item(i).id.replace(/^tooltip-/, '');
  6908. prepareTooltip(item, function (bNode)
  6909. {
  6910. var text = bNode.textContent || '';
  6911. if (/Click to /.test(text))
  6912. {
  6913. return text.replace(lastDotRegex, '');
  6914. }
  6915. return text;
  6916. });
  6917. }
  6918. // add click texts
  6919. function setText(item, text)
  6920. {
  6921. prepareTooltip(item, function ()
  6922. {
  6923. return text;
  6924. }, true);
  6925. }
  6926. for (var _a = 0, FURNACE_LEVELS_1 = FURNACE_LEVELS; _a < FURNACE_LEVELS_1.length; _a++)
  6927. {
  6928. var furnaceLevel = FURNACE_LEVELS_1[_a];
  6929. var furnaceItem = getBoundKey(furnaceLevel + 'Furnace');
  6930. setText(furnaceItem, 'Click to operate');
  6931. var ovenItem = getBoundKey(furnaceLevel + 'Oven');
  6932. setText(ovenItem, 'Click to operate');
  6933. }
  6934. // fix tooltip of quests-book
  6935. var questBookTooltip = getTooltip('quests-book');
  6936. if (questBookTooltip)
  6937. {
  6938. var childNodes = questBookTooltip.childNodes;
  6939. for (var i = 0; i < childNodes.length; i++)
  6940. {
  6941. var node = childNodes[i];
  6942. if (node.nodeType === Node.TEXT_NODE
  6943. && (node.textContent || '').indexOf('Click to see a list of quests.') > -1)
  6944. {
  6945. var next = node.nextSibling;
  6946. if (next)
  6947. {
  6948. questBookTooltip.removeChild(next);
  6949. }
  6950. questBookTooltip.removeChild(node);
  6951. }
  6952. }
  6953. }
  6954. // fix tooltip of axe
  6955. var axeTooltip = getTooltip('boundEmptyAxe');
  6956. if (axeTooltip)
  6957. {
  6958. axeTooltip.insertBefore(document.createElement('br'), axeTooltip.lastElementChild);
  6959. }
  6960. var texts = {
  6961. 'quests-book': 'Click to see the list of quests'
  6962. , 'achievementBook': 'Click to see the list of achievements'
  6963. , 'boundEmptyChisel': 'Click to use'
  6964. , 'rake': 'Click to upgrade your rake'
  6965. , 'boundBoat': 'Click to send boat'
  6966. };
  6967. for (var item in texts)
  6968. {
  6969. setText(item, texts[item]);
  6970. }
  6971. for (var _b = 0, BOAT_LIST_2 = BOAT_LIST; _b < BOAT_LIST_2.length; _b++)
  6972. {
  6973. var boatKey = BOAT_LIST_2[_b];
  6974. setText(getBoundKey(boatKey), 'Click to send boat');
  6975. }
  6976. }
  6977. var cached = {
  6978. scrollWidth: 0
  6979. , scrollHeight: 0
  6980. };
  6981.  
  6982. function changeTooltipPosition(event)
  6983. {
  6984. var tooltipX = event.pageX - 8;
  6985. var tooltipY = event.pageY + 8;
  6986. var el = document.querySelector('body > div.tooltip');
  6987. if (!el)
  6988. {
  6989. return;
  6990. }
  6991. if (!this)
  6992. {
  6993. // init
  6994. cached.scrollWidth = document.body.scrollWidth;
  6995. cached.scrollHeight = document.body.scrollHeight;
  6996. }
  6997. var rect = el.getBoundingClientRect();
  6998. var css = {
  6999. left: tooltipX
  7000. , top: tooltipY
  7001. , width: ''
  7002. , height: ''
  7003. , maxWidth: cached.scrollWidth
  7004. , maxHeight: cached.scrollHeight
  7005. };
  7006. var diffX = cached.scrollWidth - 20 - tooltipX - rect.width;
  7007. if (diffX < 0)
  7008. {
  7009. css.left += diffX;
  7010. css.width = rect.width - 42;
  7011. }
  7012. var diffY = cached.scrollHeight - 20 - tooltipY - rect.height;
  7013. if (diffY < 0)
  7014. {
  7015. css.top += diffY;
  7016. css.height = rect.height - 22;
  7017. }
  7018. win.$(el).css(css);
  7019. }
  7020.  
  7021. function fixTooltipPositioning()
  7022. {
  7023. win.changeTooltipPosition = changeTooltipPosition;
  7024. win.loadTooltips();
  7025. }
  7026.  
  7027. function fixCombatNavigation()
  7028. {
  7029. var backBtns = document.querySelectorAll('span.medium-button[onclick*="openTab(\'combat\')"]');
  7030. for (var i = 0; i < backBtns.length; i++)
  7031. {
  7032. var btn = backBtns.item(i);
  7033. var img = btn.firstElementChild;
  7034. var textNode = btn.lastChild;
  7035. if (!img || img.tagName != 'IMG' || !textNode)
  7036. {
  7037. continue;
  7038. }
  7039. img.className = img.className.replace(/(-\d+)-b/, '$1');
  7040. textNode.textContent = ' back';
  7041. }
  7042. }
  7043.  
  7044. function fixPromethiumSmeltingTime()
  7045. {
  7046. var _getTimerPerBar = win.getTimerPerBar;
  7047. win.getTimerPerBar = function (bar)
  7048. {
  7049. if (bar == 'promethiumBar')
  7050. {
  7051. return 80;
  7052. }
  7053. return _getTimerPerBar(bar);
  7054. };
  7055. }
  7056.  
  7057. function fixImage()
  7058. {
  7059. var oxygenEl = document.querySelector('img[src="images/oxygenPotion"]');
  7060. if (oxygenEl)
  7061. {
  7062. oxygenEl.src += '.png';
  7063. }
  7064. }
  7065.  
  7066. function init()
  7067. {
  7068. fixWrongURLs();
  7069. fixClientGameLoop();
  7070. fixScroller();
  7071. fixTooltipStyle();
  7072. //fixRefreshingMagicRecipes();
  7073. moveStrangeLeafs();
  7074. fixTreasureMap();
  7075. fixWoodcutting();
  7076. fixQuestBook();
  7077. // apply fix for scroll images later to fix images in this code too
  7078. fixHitText();
  7079. fixScrollImages();
  7080. fixQuest8BraveryRecipe();
  7081. fixBoatTooltips();
  7082. fixAlignments();
  7083. addHeroStatTooltips();
  7084. fixFontSize11Tabs();
  7085. //addSpellTooltips();
  7086. modifySpellImages();
  7087. unifyTooltips();
  7088. fixTooltipPositioning();
  7089. fixCombatNavigation();
  7090. fixPromethiumSmeltingTime();
  7091. fixImage();
  7092. }
  7093. temporaryFixes.init = init;
  7094. })(temporaryFixes || (temporaryFixes = {}));
  7095.  
  7096. /**
  7097. * improve timer
  7098. */
  7099. var timer;
  7100. (function (timer)
  7101. {
  7102. timer.name = 'timer';
  7103. var IMPROVED_CLASS = 'improved';
  7104. var NOTIFICATION_AREA_ID = 'notifaction-area';
  7105. var PERCENT_CLASS = 'percent';
  7106. var REMAINING_CLASS = 'remaining';
  7107. var TIMER_CLASS = 'timer';
  7108.  
  7109. function bindNewFormatter()
  7110. {
  7111. function doBind()
  7112. {
  7113. win.formatTime = win.formatTimeShort = win.formatTimeShort2 = function (seconds)
  7114. {
  7115. return format.timer(seconds);
  7116. };
  7117. }
  7118. win.addEventListener('load', function ()
  7119. {
  7120. return setTimeout(function ()
  7121. {
  7122. return doBind();
  7123. }, 100);
  7124. });
  7125. doBind();
  7126. setTimeout(function ()
  7127. {
  7128. return doBind();
  7129. }, 100);
  7130. }
  7131.  
  7132. function applyStyle()
  7133. {
  7134. 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");
  7135. }
  7136.  
  7137. function improveSmeltingTimer()
  7138. {
  7139. var el = document.getElementById('notif-smelting');
  7140. if (!el)
  7141. {
  7142. return;
  7143. }
  7144. var smeltingNotifBox = el;
  7145. smeltingNotifBox.classList.add(IMPROVED_CLASS);
  7146. var smeltingTimerEl = document.createElement('span');
  7147. smeltingTimerEl.className = TIMER_CLASS;
  7148. smeltingNotifBox.appendChild(smeltingTimerEl);
  7149. var remainingBarsEl = document.createElement('span');
  7150. remainingBarsEl.className = REMAINING_CLASS;
  7151. smeltingNotifBox.appendChild(remainingBarsEl);
  7152. var delta = 0;
  7153.  
  7154. function updatePercValues(init)
  7155. {
  7156. if (init === void 0)
  7157. {
  7158. init = false;
  7159. }
  7160. updateSmeltingTimer(delta = 0);
  7161. if (init)
  7162. {
  7163. observer.add('smeltingPercD', function ()
  7164. {
  7165. return updatePercValues();
  7166. });
  7167. observer.add('smeltingPerc', function ()
  7168. {
  7169. return updatePercValues();
  7170. });
  7171. }
  7172. }
  7173.  
  7174. function updateSmeltingTimer(delta)
  7175. {
  7176. if (delta === void 0)
  7177. {
  7178. delta = 0;
  7179. }
  7180. var totalTime = win.smeltingPercD;
  7181. // thanks at /u/marcus898 for your bug report
  7182. var elapsedTime = Math.round(win.smeltingPerc * totalTime / 100) + delta;
  7183. smeltingTimerEl.textContent = format.timer(Math.max(totalTime - elapsedTime, 0));
  7184. remainingBarsEl.textContent = (win.smeltingTotalAmount - win.smeltingAmount).toString();
  7185. }
  7186. observer.addTick(function ()
  7187. {
  7188. return updateSmeltingTimer(delta++);
  7189. });
  7190. updatePercValues(true);
  7191. }
  7192.  
  7193. function improveTimer(cssRulePrefix, textColor, timerColor, infoIdPrefx, containerPrefix, updateFn)
  7194. {
  7195. 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");
  7196. let iteration = cssRulePrefix == '.woodcutting-tree' ? 6 : 7;
  7197. for (var i = 0; i < iteration; i++)
  7198. {
  7199. var num = i + 1;
  7200. var infoId = infoIdPrefx + num;
  7201. var container = document.getElementById(containerPrefix + num);
  7202. container.style.position = 'relative';
  7203. var infoEl = document.createElement('div');
  7204. infoEl.className = 'info';
  7205. infoEl.id = infoId;
  7206. infoEl.innerHTML = "<div class=\"name\"></div><div class=\"timer\"></div>";
  7207. container.appendChild(infoEl);
  7208. updateFn(num, infoId, true);
  7209. }
  7210. }
  7211.  
  7212. function updateTreeInfo(placeId, infoElId, init)
  7213. {
  7214. if (init === void 0)
  7215. {
  7216. init = false;
  7217. }
  7218. var infoEl = document.getElementById(infoElId);
  7219. var nameEl = infoEl.firstElementChild;
  7220. var timerEl = infoEl.lastElementChild;
  7221. var idKey = 'treeId' + placeId;
  7222. var growTimerKey = 'treeGrowTimer' + placeId;
  7223. var lockedKey = 'treeUnlocked' + placeId;
  7224. var treeId = getGameValue(idKey);
  7225. if (treeId == 0)
  7226. {
  7227. var isLocked = (placeId == 5 || placeId == 6) && win.donorWoodcuttingPatch < win.currentTimeMillis;
  7228. nameEl.textContent = isLocked ? 'Locked' : 'Empty';
  7229. timerEl.textContent = '';
  7230. }
  7231. else
  7232. {
  7233. nameEl.textContent = key2Name(win.getTreeName(treeId)) || 'Unknown Tree';
  7234. var remainingTime = win.TREE_GROW_TIME[treeId - 1] - getGameValue(growTimerKey);
  7235. timerEl.textContent = remainingTime > 0 ? '(' + format.timer(remainingTime) + ')' : 'Fully grown';
  7236. }
  7237. if (init)
  7238. {
  7239. observer.add([idKey, growTimerKey, lockedKey], function ()
  7240. {
  7241. return updateTreeInfo(placeId, infoElId, false);
  7242. });
  7243. }
  7244. }
  7245. // add tree grow timer
  7246. function improveTreeGrowTimer()
  7247. {
  7248. improveTimer('.woodcutting-tree', 'white', 'yellow', 'wc-tree-info-', 'wc-div-tree-', updateTreeInfo);
  7249. }
  7250.  
  7251. function updatePatchInfo(patchId, infoElId, init)
  7252. {
  7253. if (init === void 0)
  7254. {
  7255. init = false;
  7256. }
  7257. var infoEl = document.getElementById(infoElId);
  7258. var nameEl = infoEl.querySelector('.name');
  7259. var timerEl = infoEl.querySelector('.timer');
  7260. var idKey = 'farmingPatchSeed' + patchId;
  7261. var growTimeKey = 'farmingPatchGrowTime' + patchId;
  7262. var timerKey = 'farmingPatchTimer' + patchId;
  7263. var stageKey = 'farmingPatchStage' + patchId;
  7264. var stage = getGameValue(stageKey);
  7265. var seedName = PLANT_NAME[getGameValue(idKey)] || 'Unkown Plant';
  7266. if (stage == 0)
  7267. {
  7268. var isLocked = (patchId == 5 || patchId == 6) && win.donorFarmingPatch < win.currentTimeMillis;
  7269. nameEl.textContent = isLocked ? 'Locked' : 'Click to grow';
  7270. timerEl.textContent = '';
  7271. }
  7272. else if (stage >= 4)
  7273. {
  7274. nameEl.textContent = stage > 4 ? 'Dead Plant' : seedName;
  7275. timerEl.textContent = stage > 4 ? 'Click to remove' : 'Click to harvest';
  7276. }
  7277. else
  7278. {
  7279. nameEl.textContent = seedName;
  7280. var remainingTime = getGameValue(growTimeKey) - getGameValue(timerKey);
  7281. timerEl.textContent = '(' + format.timer(remainingTime) + ')';
  7282. }
  7283. if (init)
  7284. {
  7285. observer.add([idKey, timerKey, stageKey, 'donorFarmingPatch'], function ()
  7286. {
  7287. return updatePatchInfo(patchId, infoElId, false);
  7288. });
  7289. }
  7290. }
  7291. // add seed name and change color of timer
  7292. function getSoonestTreeTimer()
  7293. {
  7294. if (win.treeStage1 == 4
  7295. || win.treeStage2 == 4
  7296. || win.treeStage3 == 4
  7297. || win.treeStage4 == 4
  7298. || win.treeStage5 == 4
  7299. || win.treeStage6 == 4)
  7300. {
  7301. return -1;
  7302. }
  7303. var minTimer = null;
  7304. for (var i = 1; i <= 6; i++)
  7305. {
  7306. var treeId = getGameValue('treeId' + i);
  7307. var unlocked = getGameValue('treeUnlocked' + i) == 1;
  7308. var timerValue = getGameValue('treeGrowTimer' + i);
  7309. if (unlocked && treeId !== 0 && timerValue > 0)
  7310. {
  7311. var remainingTime = win.TREE_GROW_TIME[treeId - 1] - timerValue;
  7312. minTimer = minTimer === null ? remainingTime : Math.min(minTimer, remainingTime);
  7313. }
  7314. }
  7315. return minTimer || 0;
  7316. }
  7317.  
  7318. function getSoonestFarmingTimer()
  7319. {
  7320. if (win.farmingPatchStage1 == 0 || win.farmingPatchStage1 == 4
  7321. || win.farmingPatchStage2 == 0 || win.farmingPatchStage2 == 4
  7322. || win.farmingPatchStage3 == 0 || win.farmingPatchStage3 == 4
  7323. || win.farmingPatchStage4 == 0 || win.farmingPatchStage4 == 4
  7324. || win.donorFarmingPatch > win.currentTimeMillis && (win.farmingPatchStage5 == 0 || win.farmingPatchStage5 == 4
  7325. || win.farmingPatchStage6 == 0 || win.farmingPatchStage6 == 4))
  7326. {
  7327. return -1;
  7328. }
  7329. var minTimer = null;
  7330. for (var i = 1; i <= ((win.donorFarmingPatch > win.currentTimeMillis) ? 6 : 4); i++)
  7331. {
  7332. var remainingTimer = getGameValue('farmingPatchGrowTime' + i) - getGameValue('farmingPatchTimer' + i);
  7333. minTimer = minTimer === null ? remainingTimer : Math.min(minTimer, remainingTimer);
  7334. }
  7335. return minTimer || 0;
  7336. }
  7337.  
  7338. function improveSeedGrowTimer()
  7339. {
  7340. improveTimer('div[id^="farming-patch-area"]', 'black', 'blue', 'farming-patch-info-', 'farming-patch-area-', updatePatchInfo);
  7341. }
  7342.  
  7343. function addTabTimer()
  7344. {
  7345. var TAB_TIMER_KEY = 'tabTimer';
  7346. 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");
  7347.  
  7348. function getTabEl(key)
  7349. {
  7350. return document.getElementById('tab-container-bar-' + key);
  7351. }
  7352.  
  7353. function addInfoDiv(key)
  7354. {
  7355. var infoDiv = document.createElement('div');
  7356. infoDiv.className = 'info';
  7357. var tab = getTabEl(key);
  7358. if (tab)
  7359. {
  7360. tab.appendChild(infoDiv);
  7361. }
  7362. return infoDiv;
  7363. }
  7364.  
  7365. function createTabTimer(key, timerFn)
  7366. {
  7367. var tab = getTabEl(key);
  7368. var timerDiv = addInfoDiv(key);
  7369. if (!tab || !timerDiv)
  7370. {
  7371. return;
  7372. }
  7373. timerDiv.classList.add('timer');
  7374.  
  7375. function updateTimer()
  7376. {
  7377. var minTimer = timerFn();
  7378. if (tab)
  7379. {
  7380. tab.classList[minTimer == -1 ? 'add' : 'remove']('ready');
  7381. }
  7382. timerDiv.textContent = minTimer <= 0 ? '' : format.timer(minTimer);
  7383. }
  7384. updateTimer();
  7385. observer.addTick(function ()
  7386. {
  7387. return updateTimer();
  7388. });
  7389. }
  7390. createTabTimer('woodcutting', getSoonestTreeTimer);
  7391. createTabTimer('farming', getSoonestFarmingTimer);
  7392. createTabTimer('combat', function ()
  7393. {
  7394. return win.combatGlobalCooldown;
  7395. });
  7396. var energyDiv = addInfoDiv('combat');
  7397. energyDiv.classList.add('extra');
  7398.  
  7399. function updateEnergy()
  7400. {
  7401. energyDiv.innerHTML = '<img src="images/steak.png" class="image-icon-15"> ' + format.number(win.energy);
  7402. }
  7403. updateEnergy();
  7404. observer.add('energy', function ()
  7405. {
  7406. return updateEnergy();
  7407. });
  7408. // add highlight for stardust potions
  7409. var potionDiv = addInfoDiv('brewing');
  7410. potionDiv.classList.add('extra');
  7411. var potionList = ['stardustPotion', 'superStardustPotion'];
  7412. var potionImageList = [];
  7413.  
  7414. function updatePotion(key, img, init)
  7415. {
  7416. if (init === void 0)
  7417. {
  7418. init = false;
  7419. }
  7420. var timerKey = key + 'Timer';
  7421. var show = getGameValue(key) > 0 && getGameValue(timerKey) === 0;
  7422. img.style.display = show ? '' : 'none';
  7423. if (init)
  7424. {
  7425. observer.add(key, function ()
  7426. {
  7427. return updatePotion(key, img);
  7428. });
  7429. observer.add(timerKey, function ()
  7430. {
  7431. return updatePotion(key, img);
  7432. });
  7433. }
  7434. }
  7435. for (var i = 0; i < potionList.length; i++)
  7436. {
  7437. var key = potionList[i];
  7438. var img = document.createElement('img');
  7439. img.src = 'images/' + key + '.png';
  7440. img.className = 'image-icon-15';
  7441. potionImageList[i] = img;
  7442. potionDiv.appendChild(img);
  7443. updatePotion(key, img, true);
  7444. }
  7445.  
  7446. function updateVisibility()
  7447. {
  7448. document.body.classList[settings.get(settings.KEY.showTabTimer) ? 'add' : 'remove'](TAB_TIMER_KEY);
  7449. }
  7450. updateVisibility();
  7451. settings.observe(settings.KEY.showTabTimer, function ()
  7452. {
  7453. return updateVisibility();
  7454. });
  7455. observer.add('profileShortTabs', function ()
  7456. {
  7457. var short = !!win.profileShortTabs;
  7458. document.body.classList[short ? 'add' : 'remove']('short-tabs');
  7459. });
  7460. }
  7461.  
  7462. function addOilInfo()
  7463. {
  7464. var NULL_TYPE = 'null';
  7465. var PLUS_TYPE = 'plus';
  7466. var MINUS_TYPE = 'minus';
  7467. 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");
  7468. var oilFlow = document.getElementById('oil-flow-values');
  7469. var parent = oilFlow && oilFlow.parentElement;
  7470. if (!oilFlow || !parent)
  7471. {
  7472. return;
  7473. }
  7474. var container = document.createElement('div');
  7475. container.id = 'oil-filling-level';
  7476. var fillingLevel = document.createElement('div');
  7477. container.appendChild(fillingLevel);
  7478. var first = parent.firstElementChild;
  7479. if (first)
  7480. {
  7481. parent.insertBefore(container, first);
  7482. }
  7483. else
  7484. {
  7485. parent.appendChild(container);
  7486. }
  7487. parent.style.position = 'relative';
  7488. var netFlow = document.createElement('span');
  7489. netFlow.id = 'oil-flow-net';
  7490. parent.insertBefore(netFlow, oilFlow);
  7491. var next = oilFlow.nextElementSibling;
  7492. var netTimer = document.createElement('span');
  7493. netTimer.id = 'oil-flow-net-timer';
  7494. if (next)
  7495. {
  7496. parent.insertBefore(netTimer, next);
  7497. }
  7498. else
  7499. {
  7500. parent.appendChild(netTimer);
  7501. }
  7502. var oilNet;
  7503. var oilNetType;
  7504.  
  7505. function updateNetFlow(init)
  7506. {
  7507. if (init === void 0)
  7508. {
  7509. init = false;
  7510. }
  7511. oilNet = win.oilIn - win.oilOut;
  7512. oilNetType = oilNet === 0 ? NULL_TYPE : (oilNet > 0 ? PLUS_TYPE : MINUS_TYPE);
  7513. netFlow.dataset.type = oilNetType;
  7514. var sign = oilNet === 0 ? PLUS_MINUS_SIGN : (oilNet > 0 ? '+' : '');
  7515. netFlow.textContent = sign + oilNet;
  7516. if (init)
  7517. {
  7518. observer.add('oilIn', function ()
  7519. {
  7520. return updateNetFlow();
  7521. });
  7522. observer.add('oilOut', function ()
  7523. {
  7524. return updateNetFlow();
  7525. });
  7526. }
  7527. updateFullTimer(init);
  7528. }
  7529. var hour2Color = (_a = {}
  7530. , // 30min
  7531. _a[.5 * 60 * 60] = 'rgb(255, 0, 0)'
  7532. , _a[5 * 60 * 60] = 'rgb(255, 255, 0)'
  7533. , _a[8 * 60 * 60] = 'rgb(255, 255, 255)'
  7534. , _a);
  7535.  
  7536. function updateFullTimer(init)
  7537. {
  7538. if (init === void 0)
  7539. {
  7540. init = false;
  7541. }
  7542. netTimer.dataset.type = oilNetType;
  7543. var time = 0;
  7544. if (oilNet > 0)
  7545. {
  7546. netTimer.title = 'full in...';
  7547. var diff = win.maxOil - win.oil;
  7548. time = diff / oilNet;
  7549. }
  7550. else if (oilNet < 0)
  7551. {
  7552. netTimer.title = 'empty in...';
  7553. time = win.oil / Math.abs(oilNet);
  7554. }
  7555. netTimer.textContent = '(' + format.timer(Math.ceil(time)) + ')';
  7556. var filledPercent = win.oil / win.maxOil * 100;
  7557. fillingLevel.style.height = (100 - filledPercent) + '%';
  7558. /**
  7559. * colorize filling level according to the time it needs to be full/empty:
  7560. * - red iff oil storage full/empty in 30min
  7561. * - yellow iff oil storage full/empty in 5h
  7562. * - white iff oil storage full/empty in 8h or more
  7563. */
  7564. var color = oilNet === 0 ? '#ffffff' : colorGenerator.getColorTransition(time, hour2Color);
  7565. container.style.borderColor = color;
  7566. if (init)
  7567. {
  7568. observer.add('maxOil', function ()
  7569. {
  7570. return updateFullTimer();
  7571. });
  7572. observer.add('oil', function ()
  7573. {
  7574. return updateFullTimer();
  7575. });
  7576. observer.addTick(function ()
  7577. {
  7578. return updateFullTimer();
  7579. });
  7580. }
  7581. }
  7582. updateNetFlow(true);
  7583. var _a;
  7584. }
  7585.  
  7586. function addRocketTimer()
  7587. {
  7588. var notifArea = document.getElementById(NOTIFICATION_AREA_ID);
  7589. if (!notifArea)
  7590. {
  7591. return;
  7592. }
  7593. var notifBox = document.createElement('span');
  7594. notifBox.className = 'notif-box ' + IMPROVED_CLASS;
  7595. notifBox.id = 'notif-rocket';
  7596. notifBox.style.display = 'none';
  7597. 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>";
  7598. var AVG_KM_PER_SEC = rocketDestination == 1 ? 15 : 392;
  7599. notifBox.title = 'This value is only an estimation based on an average speed of '+AVG_KM_PER_SEC+'km per second.';
  7600. notifArea.appendChild(notifBox);
  7601. var img = notifBox.getElementsByTagName('img').item(0);
  7602. var timerEl = notifBox.getElementsByClassName(TIMER_CLASS).item(0);
  7603. var percentEl = notifBox.getElementsByClassName(PERCENT_CLASS).item(0);
  7604. var smoothedTime = 0;
  7605.  
  7606. function updateRocketKm()
  7607. {
  7608. if(AVG_KM_PER_SEC != (rocketDestination == 1 ? 15 : 392))
  7609. {
  7610. AVG_KM_PER_SEC = rocketDestination == 1 ? 15 : 392;
  7611. notifBox.title = 'This value is only an estimation based on an average speed of '+AVG_KM_PER_SEC+'km per second.';
  7612. }
  7613. var hideStatic = win.rocketKm < (rocketDestination == 1 ? MAX_ROCKET_MOON_KM : MAX_ROCKET_MARS_KM);
  7614. var hideTimer = win.rocketKm <= 0 || !hideStatic;
  7615. notifBox.style.display = hideTimer ? 'none' : '';
  7616. var percent = win.rocketKm / (rocketDestination == 1 ? MAX_ROCKET_MOON_KM : MAX_ROCKET_MARS_KM);
  7617. var diff = (rocketDestination == 1 ? MAX_ROCKET_MOON_KM : MAX_ROCKET_MARS_KM) - win.rocketKm;
  7618. if (win.rocketMoonId < 0)
  7619. {
  7620. percent = 1 - percent;
  7621. diff = win.rocketKm;
  7622. }
  7623. var avgRemainingTime = Math.round(diff / AVG_KM_PER_SEC);
  7624. // be more accurate in the last few seconds (may be the last 2 up to 16 seconds)
  7625. var threshold = smoothedTime < 10 ? 1 : 8;
  7626. if (Math.abs(smoothedTime - avgRemainingTime) >= threshold)
  7627. {
  7628. smoothedTime = avgRemainingTime + 1;
  7629. }
  7630. percentEl.textContent = Math.floor(percent * 100).toString();
  7631. }
  7632.  
  7633. function tickRocketTimer()
  7634. {
  7635. if (smoothedTime > 0)
  7636. {
  7637. smoothedTime = Math.max(smoothedTime - 1, 0);
  7638. timerEl.textContent = format.timer(smoothedTime);
  7639. }
  7640. }
  7641. updateRocketKm();
  7642. observer.add('rocketKm', function (key, oldValue, newValue)
  7643. {
  7644. return updateRocketKm();
  7645. });
  7646. observer.addTick(function ()
  7647. {
  7648. return tickRocketTimer();
  7649. });
  7650.  
  7651. function updateRocketDirection()
  7652. {
  7653. // alternatively: `transform: rotateZ(180deg) rotateY(180deg)`
  7654. var transform = win.rocketMoonId >= 0 ? '' : 'rotate(90deg)';
  7655. img.style.transform = transform;
  7656. var itemBox = document.getElementById('default-item-img-tag-boundRocket');
  7657. if (itemBox)
  7658. {
  7659. itemBox.style.transform = transform;
  7660. }
  7661. }
  7662. updateRocketDirection();
  7663. observer.add('rocketMoonId', function ()
  7664. {
  7665. return updateRocketDirection();
  7666. });
  7667. }
  7668. function addVendorRefreshTimer()
  7669. {
  7670. var notifArea = document.getElementById(NOTIFICATION_AREA_ID);
  7671. if (!notifArea)
  7672. {
  7673. return;
  7674. }
  7675. var notifBox = document.createElement('span');
  7676. notifBox.className = 'notif-box ' + IMPROVED_CLASS;
  7677. notifBox.id = 'notif-vendorRefresh';
  7678. notifBox.style.display = 'none';
  7679. 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>";
  7680. notifArea.appendChild(notifBox);
  7681. var img = notifBox.getElementsByTagName('img').item(0);
  7682. var timerEl = notifBox.getElementsByClassName(TIMER_CLASS).item(0);
  7683.  
  7684. function updateVendorRefreshTimer()
  7685. {
  7686. var hideTimer = win.vendorNotification == 1;
  7687. notifBox.style.display = hideTimer ? 'none' : '';
  7688. var timeLeft = Math.floor( (12*60*60) - (Date.now()-vendorLastChanged)/1000 );
  7689. timerEl.textContent = format.timer(timeLeft);
  7690. }
  7691. updateVendorRefreshTimer();
  7692. observer.addTick(function ()
  7693. {
  7694. return updateVendorRefreshTimer();
  7695. });
  7696. }
  7697. function addBobsUncleTimer()
  7698. {
  7699. var notifArea = document.getElementById(NOTIFICATION_AREA_ID);
  7700. if (!notifArea)
  7701. {
  7702. return;
  7703. }
  7704. var notifBox = document.createElement('span');
  7705. notifBox.className = 'notif-box ' + IMPROVED_CLASS;
  7706. notifBox.id = 'notif-bobsUncle';
  7707. notifBox.style.display = 'none';
  7708. 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>";
  7709. notifArea.appendChild(notifBox);
  7710. var img = notifBox.getElementsByTagName('img').item(0);
  7711. var timerEl = notifBox.getElementsByClassName(TIMER_CLASS).item(0);
  7712.  
  7713. function updateBobsUncleTimer()
  7714. {
  7715. var hideTimer = win.farmingPatchStage7 == 0 || win.farmingPatchStage7 == 4;
  7716. notifBox.style.display = hideTimer ? 'none' : '';
  7717. var timeLeft = getGameValue('farmingPatchGrowTime7') - getGameValue('farmingPatchTimer7');
  7718. timerEl.textContent = format.timer(timeLeft);
  7719. }
  7720. updateBobsUncleTimer();
  7721. observer.addTick(function ()
  7722. {
  7723. return updateBobsUncleTimer();
  7724. });
  7725. }
  7726. function addCharcoalFactoryTimer()
  7727. {
  7728. var notifArea = document.getElementById(NOTIFICATION_AREA_ID);
  7729. if (!notifArea)
  7730. {
  7731. return;
  7732. }
  7733. var notifBox = document.createElement('span');
  7734. notifBox.className = 'notif-box ' + IMPROVED_CLASS;
  7735. notifBox.id = 'notif-charcoalFactory';
  7736. notifBox.style.display = 'none';
  7737. var consumeTime = (boundRedCharcoalFactoryOrb) ? 492: 112;
  7738. notifBox.title = 'This value is only an estimation based on an average consumption rate of one charcoal every '+consumeTime+' seconds.';
  7739. 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>";
  7740. notifArea.appendChild(notifBox);
  7741. var img = notifBox.getElementsByTagName('img').item(0);
  7742. var timerEl = notifBox.getElementsByClassName(TIMER_CLASS).item(0);
  7743. var now = Math.floor(Date.now()/1000);
  7744. function updateCharcoalFactoryTimer()
  7745. {
  7746. var hideTimer = win.boundCharcoalFactory == 0 || win.charcoalFactoryCharcoal == 0;
  7747. notifBox.style.display = hideTimer ? 'none' : '';
  7748. var averageTimeLeft = getGameValue('charcoalFactoryCharcoal') * consumeTime;
  7749. var smoothedTime = averageTimeLeft + now - Math.floor(Date.now()/1000);
  7750. timerEl.textContent = format.timer(smoothedTime);
  7751. }
  7752. updateCharcoalFactoryTimer();
  7753. observer.addTick(function ()
  7754. {
  7755. return updateCharcoalFactoryTimer();
  7756. });
  7757. }
  7758. function getLogTypeList()
  7759. {
  7760. var list = [];
  7761. var els = document.querySelectorAll('input[id^="input-charcoalFoundry-"]');
  7762. for (var i = 0; i < els.length; i++)
  7763. {
  7764. list.push(els[i].id.replace(/^input-charcoalFoundry-/i, ''));
  7765. }
  7766. return list;
  7767. }
  7768.  
  7769. function improveFoundryTimer()
  7770. {
  7771. var el = document.getElementById('notif-charcoalFoundry');
  7772. if (!el)
  7773. {
  7774. return;
  7775. }
  7776. var notifBox = el;
  7777. notifBox.classList.add(IMPROVED_CLASS);
  7778. var timerEl = document.createElement('span');
  7779. timerEl.className = TIMER_CLASS;
  7780. notifBox.appendChild(timerEl);
  7781. var remainingEl = document.createElement('span');
  7782. remainingEl.className = REMAINING_CLASS;
  7783. notifBox.appendChild(remainingEl);
  7784. var logTypeList = null;
  7785. observer.add('charcoalFoundryN', function (key, oldValue, newValue)
  7786. {
  7787. timerEl.textContent = format.timer(win.charcoalFoundryD - win.charcoalFoundryN);
  7788. // init log type list when needed
  7789. if (!logTypeList)
  7790. {
  7791. logTypeList = getLogTypeList();
  7792. }
  7793. var woodAmount = win.charcoalFoundryTotal - win.charcoalFoundryCurrent;
  7794. var coalPerLog = win.getCharcoalPerLog(logTypeList[win.charcoalFoundryLogId - 1]);
  7795. var remainingCoal = woodAmount * (isNaN(coalPerLog) ? 1 : coalPerLog);
  7796. remainingEl.textContent = remainingCoal.toString();
  7797. });
  7798. }
  7799. function improveCharcoalFactoryTimer()
  7800. {
  7801. var el = document.getElementById('notif-charcoalFactory');
  7802. if (!el)
  7803. {
  7804. return;
  7805. }
  7806. var notifBox = el;
  7807. notifBox.classList.add(IMPROVED_CLASS);
  7808. var remainingEl = document.createElement('span');
  7809. remainingEl.className = REMAINING_CLASS;
  7810. notifBox.appendChild(remainingEl);
  7811. observer.add('charcoalFactoryCharcoal', function (key, oldValue, newValue)
  7812. {
  7813. var remainingCoal = win.charcoalFactoryCharcoal;
  7814. remainingEl.textContent = remainingCoal.toString();
  7815. });
  7816. }
  7817.  
  7818. function init()
  7819. {
  7820. bindNewFormatter();
  7821. applyStyle();
  7822. improveSmeltingTimer();
  7823. improveTreeGrowTimer();
  7824. improveSeedGrowTimer();
  7825. addTabTimer();
  7826. addOilInfo();
  7827. addRocketTimer();
  7828. improveFoundryTimer();
  7829. addVendorRefreshTimer();
  7830. addBobsUncleTimer();
  7831. addCharcoalFactoryTimer();
  7832. //improveCharcoalFactoryTimer();
  7833. }
  7834. timer.init = init;
  7835. })(timer || (timer = {}));
  7836.  
  7837. /**
  7838. * improve smelting dialog
  7839. */
  7840. var smelting;
  7841. (function (smelting)
  7842. {
  7843. smelting.name = 'smelting';
  7844. var TIME_NEEDED_ID = 'smelting-time-needed';
  7845. var LAST_SMELTING_AMOUNT_KEY = 'lastSmeltingAmount';
  7846. var LAST_SMELTING_BAR_KEY = 'lastSmeltingBar';
  7847. var smeltingValue = null;
  7848. var amountInput;
  7849.  
  7850. function prepareAmountInput()
  7851. {
  7852. amountInput = document.getElementById('input-smelt-bars-amount');
  7853. amountInput.type = 'number';
  7854. amountInput.min = '0';
  7855. amountInput.step = '5';
  7856.  
  7857. function onValueChange()
  7858. {
  7859. smeltingValue = null;
  7860. win.selectBar('', null, amountInput, document.getElementById('smelting-furnace-capacity').value);
  7861. }
  7862. amountInput.addEventListener('mouseup', onValueChange);
  7863. amountInput.addEventListener('keyup', onValueChange);
  7864. amountInput.setAttribute('onkeyup', '');
  7865. }
  7866.  
  7867. function setBarCap(bar, capacity)
  7868. {
  7869. if (bar == '')
  7870. {
  7871. bar = win.selectedBar;
  7872. }
  7873. var requirements = SMELTING_REQUIREMENTS[bar];
  7874. var maxAmount = parseInt(capacity, 10);
  7875. for (var key in requirements)
  7876. {
  7877. var req = requirements[key];
  7878. maxAmount = Math.min(Math.floor(getGameValue(key) / req), maxAmount);
  7879. }
  7880. var value = parseInt(amountInput.value, 10);
  7881. if (value > maxAmount)
  7882. {
  7883. smeltingValue = value;
  7884. amountInput.value = maxAmount.toString();
  7885. }
  7886. else if (smeltingValue != null)
  7887. {
  7888. amountInput.value = Math.min(smeltingValue, maxAmount).toString();
  7889. if (smeltingValue <= maxAmount)
  7890. {
  7891. smeltingValue = null;
  7892. }
  7893. }
  7894. }
  7895.  
  7896. function prepareTimeNeeded()
  7897. {
  7898. var neededMatsEl = document.getElementById('dialogue-furnace-mats-needed');
  7899. var parent = neededMatsEl && neededMatsEl.parentElement;
  7900. if (!neededMatsEl || !parent)
  7901. {
  7902. return;
  7903. }
  7904. var br = document.createElement('br');
  7905. var timeBox = document.createElement('div');
  7906. timeBox.className = 'basic-smallbox';
  7907. timeBox.innerHTML = "<img src=\"images/icons/hourglass.png\" class=\"image-icon-30\">\n\t\tDuration: <span id=\"" + TIME_NEEDED_ID + "\"></span>";
  7908. var next = neededMatsEl.nextElementSibling;
  7909. parent.insertBefore(br, next);
  7910. parent.insertBefore(timeBox, next);
  7911. }
  7912.  
  7913. function updateTimeNeeded(value)
  7914. {
  7915. var timeEl = document.getElementById(TIME_NEEDED_ID);
  7916. if (!timeEl)
  7917. {
  7918. return;
  7919. }
  7920. var num = parseInt(value, 10);
  7921. var timePerBar = win.getTimerPerBar(win.selectedBar);
  7922. timeEl.textContent = format.timer(timePerBar * num);
  7923. }
  7924.  
  7925. function init()
  7926. {
  7927. prepareAmountInput();
  7928. prepareTimeNeeded();
  7929. var _selectBar = win.selectBar;
  7930. var updateSmeltingRequirements = function (bar, inputElement, inputBarsAmountEl, capacity)
  7931. {
  7932. _selectBar(bar, inputElement, inputBarsAmountEl, capacity);
  7933. var matsArea = document.getElementById('dialogue-furnace-mats-needed');
  7934. if (matsArea)
  7935. {
  7936. matsArea.innerHTML = format.numbersInText(matsArea.innerHTML);
  7937. }
  7938. updateTimeNeeded(inputBarsAmountEl.value);
  7939. };
  7940. win.selectBar = function (bar, inputElement, inputBarsAmountEl, capacity)
  7941. {
  7942. setBarCap(bar, capacity);
  7943. // save selected bar
  7944. if (bar != '')
  7945. {
  7946. store.set(LAST_SMELTING_BAR_KEY, bar);
  7947. }
  7948. // save amount
  7949. store.set(LAST_SMELTING_AMOUNT_KEY, inputBarsAmountEl.value);
  7950. updateSmeltingRequirements(bar, inputElement, inputBarsAmountEl, capacity);
  7951. };
  7952. var lastBar = store.get(LAST_SMELTING_BAR_KEY);
  7953. var lastAmount = store.get(LAST_SMELTING_AMOUNT_KEY);
  7954. var _openFurnaceDialogue = win.openFurnaceDialogue;
  7955. win.openFurnaceDialogue = function (furnace)
  7956. {
  7957. var capacity = win.getFurnaceCapacity(furnace);
  7958. if (win.smeltingBarType == 0)
  7959. {
  7960. amountInput.max = capacity.toString();
  7961. }
  7962. // restore amount
  7963. var inputBarsAmountEl = document.getElementById('input-smelt-bars-amount');
  7964. if (inputBarsAmountEl && inputBarsAmountEl.value == '-1' && lastAmount != null)
  7965. {
  7966. inputBarsAmountEl.value = lastAmount;
  7967. }
  7968. _openFurnaceDialogue(furnace);
  7969. // restore selected bar
  7970. if ((!win.selectedBar || win.selectedBar == 'none') && lastBar != null)
  7971. {
  7972. win.selectedBar = lastBar;
  7973. }
  7974. // update whether requirements are fulfilled
  7975. var barInputId = 'input-furnace-' + split2Words(win.selectedBar, '-').toLowerCase();
  7976. var inputElement = document.getElementById(barInputId);
  7977. if (inputElement && inputBarsAmountEl)
  7978. {
  7979. updateSmeltingRequirements(win.selectedBar, inputElement, inputBarsAmountEl, capacity.toString());
  7980. }
  7981. };
  7982. }
  7983. smelting.init = init;
  7984. })(smelting || (smelting = {}));
  7985.  
  7986. /**
  7987. * add chance to time calculator
  7988. */
  7989. var fishingInfo;
  7990. (function (fishingInfo)
  7991. {
  7992. fishingInfo.name = 'fishingInfo';
  7993. /**
  7994. * calculates the number of seconds until the event with the given chance happened at least once with the given
  7995. * probability p (in percent)
  7996. */
  7997. function calcSecondsTillP(chancePerSecond, p)
  7998. {
  7999. return Math.round(Math.log(1 - p / 100) / Math.log(1 - chancePerSecond));
  8000. }
  8001.  
  8002. function addChanceTooltip(headline, chancePerSecond, elId, targetEl)
  8003. {
  8004. // ensure tooltip exists and is correctly binded
  8005. var tooltipEl = ensureTooltip('chance-' + elId, targetEl);
  8006. // set elements content
  8007. var percValues = [1, 10, 20, 50, 80, 90, 99];
  8008. var percRows = '';
  8009. for (var _i = 0, percValues_1 = percValues; _i < percValues_1.length; _i++)
  8010. {
  8011. var p = percValues_1[_i];
  8012. 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>";
  8013. }
  8014. 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";
  8015. }
  8016.  
  8017. function addChanceStyle()
  8018. {
  8019. 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");
  8020. }
  8021.  
  8022. function addXp()
  8023. {
  8024. var table = document.querySelector('#dialogue-id-fishingRod table');
  8025. if (!table)
  8026. {
  8027. return;
  8028. }
  8029. var rows = table.rows;
  8030. for (var i = 0; i < rows.length; i++)
  8031. {
  8032. var row = rows.item(i);
  8033. if (row.classList.contains('xp-added'))
  8034. {
  8035. continue;
  8036. }
  8037. if (i == 0)
  8038. {
  8039. var xpCell = document.createElement('th');
  8040. xpCell.textContent = 'XP';
  8041. row.appendChild(xpCell);
  8042. }
  8043. else
  8044. {
  8045. var cell = row.insertCell(-1);
  8046. var rawFish = row.id.replace('dialogue-fishing-rod-tr-', '');
  8047. var xp = FISH_XP[rawFish];
  8048. cell.textContent = xp == null ? '?' : format.number(xp);
  8049. }
  8050. row.classList.add('xp-added');
  8051. }
  8052. }
  8053.  
  8054. function chance2TimeCalculator()
  8055. {
  8056. var table = document.querySelector('#dialogue-id-fishingRod table');
  8057. if (!table)
  8058. {
  8059. return;
  8060. }
  8061. var rows = table.rows;
  8062. for (var i = 1; i < rows.length; i++)
  8063. {
  8064. var row = rows.item(i);
  8065. var rawFish = row.id.replace('dialogue-fishing-rod-tr-', '');
  8066. var fish = rawFish.replace('raw', '').toLowerCase();
  8067. if (!rawFish || !fish)
  8068. {
  8069. continue;
  8070. }
  8071. var chanceCell = row.cells.item(row.cells.length - 2);
  8072. var chance = (chanceCell.textContent || '')
  8073. .replace(/[^\d\/]/g, '')
  8074. .split('/')
  8075. .reduce(function (p, c)
  8076. {
  8077. return p / parseInt(c, 10);
  8078. }, 1);
  8079. addChanceTooltip("One raw " + fish + " at least every:", chance, rawFish, row);
  8080. }
  8081. }
  8082.  
  8083. function init()
  8084. {
  8085. addChanceStyle();
  8086. var _clicksShovel = win.clicksShovel;
  8087. win.clicksShovel = function ()
  8088. {
  8089. _clicksShovel();
  8090. var shovelChance = document.getElementById('dialogue-shovel-chance');
  8091. var titleEl = shovelChance.parentElement;
  8092. var chance = 1 / win.getChanceOfDiggingSand();
  8093. addChanceTooltip('One sand at least every:', chance, 'shovel', titleEl);
  8094. };
  8095. // depends on fishingXp
  8096. var _clicksFishingRod = win.clicksFishingRod;
  8097. win.clicksFishingRod = function ()
  8098. {
  8099. _clicksFishingRod();
  8100. addXp();
  8101. chance2TimeCalculator();
  8102. };
  8103. }
  8104. fishingInfo.init = init;
  8105. })(fishingInfo || (fishingInfo = {}));
  8106.  
  8107. /**
  8108. * add tooltips for recipes
  8109. */
  8110. var recipeTooltips;
  8111. (function (recipeTooltips)
  8112. {
  8113. recipeTooltips.name = 'recipeTooltips';
  8114.  
  8115. function updateRecipeTooltips(recipeKey, recipes)
  8116. {
  8117. var table = document.getElementById('table-' + recipeKey + '-recipe');
  8118. var rows = table.rows;
  8119.  
  8120. function recipe2Title(recipe)
  8121. {
  8122. return recipe.recipe
  8123. .map(function (name, i)
  8124. {
  8125. return format.number(recipe.recipeCost[i]) + String.fromCharCode(160)
  8126. + split2Words(name).toLowerCase();
  8127. })
  8128. .join(' + ');
  8129. };
  8130. for (var i = 1; i < rows.length; i++)
  8131. {
  8132. var row = rows.item(i);
  8133. var key = row.id.replace(recipeKey + '-', '');
  8134. var recipe = recipes[key];
  8135. var requirementCell = row.cells.item(3);
  8136. requirementCell.title = recipe2Title(recipe);
  8137. win.$(requirementCell).tooltip();
  8138. }
  8139. }
  8140.  
  8141. function updateTooltipsOnReinitRecipes(key)
  8142. {
  8143. var capitalKey = capitalize(key);
  8144. var processKey = 'process' + capitalKey + 'Tab';
  8145. var _processTab = win[processKey];
  8146. win[processKey] = function ()
  8147. {
  8148. var reinit = !!getGameValue('refreshLoad' + capitalKey + 'Table');
  8149. _processTab();
  8150. if (reinit)
  8151. {
  8152. updateRecipeTooltips(key, getGameValue(key + 'Recipes'));
  8153. }
  8154. };
  8155. }
  8156.  
  8157. function init()
  8158. {
  8159. updateTooltipsOnReinitRecipes('crafting');
  8160. updateTooltipsOnReinitRecipes('brewing');
  8161. updateTooltipsOnReinitRecipes('magic');
  8162. updateTooltipsOnReinitRecipes('cooksBook');
  8163. }
  8164. recipeTooltips.init = init;
  8165. })(recipeTooltips || (recipeTooltips = {}));
  8166.  
  8167. /**
  8168. * fix formatting of numbers
  8169. */
  8170. var fixNumbers;
  8171. (function (fixNumbers)
  8172. {
  8173. fixNumbers.name = 'fixNumbers';
  8174.  
  8175. function prepareRecipeForTable(recipe)
  8176. {
  8177. // create a copy of the recipe to prevent requirement check from failing
  8178. var newRecipe = JSON.parse(JSON.stringify(recipe));
  8179. newRecipe.recipeCost = recipe.recipeCost.map(function (cost)
  8180. {
  8181. return format.number(cost);
  8182. });
  8183. newRecipe.description = format.numbersInText(newRecipe.description);
  8184. newRecipe.xp = format.number(recipe.xp);
  8185. return newRecipe;
  8186. }
  8187.  
  8188. function init()
  8189. {
  8190. var _addRecipeToBrewingTable = win.addRecipeToBrewingTable;
  8191. win.addRecipeToBrewingTable = function (brewingRecipe)
  8192. {
  8193. _addRecipeToBrewingTable(prepareRecipeForTable(brewingRecipe));
  8194. };
  8195. var _addRecipeToMagicTable = win.addRecipeToMagicTable;
  8196. win.addRecipeToMagicTable = function (magicRecipe)
  8197. {
  8198. _addRecipeToMagicTable(prepareRecipeForTable(magicRecipe));
  8199. };
  8200. var _addRecipeToCooksBookTable = win.addRecipeToCooksBookTable;
  8201. win.addRecipeToCooksBookTable = function (cooksBookRecipe)
  8202. {
  8203. _addRecipeToCooksBookTable(prepareRecipeForTable(cooksBookRecipe));
  8204. };
  8205. var tooltipList = document.querySelectorAll('#tooltip-list div[id^="tooltip-"][id$="Seeds"]');
  8206. for (var i = 0; i < tooltipList.length; i++)
  8207. {
  8208. var tooltip = tooltipList[i];
  8209. tooltip.innerHTML = format.numbersInText(tooltip.innerHTML);
  8210. }
  8211. var fightEnergyCells = document.querySelectorAll('#dialogue-fight tr > td:nth-child(4)');
  8212. for (var i = 0; i < fightEnergyCells.length; i++)
  8213. {
  8214. var cell = fightEnergyCells[i];
  8215. cell.innerHTML = format.numbersInText(cell.innerHTML);
  8216. }
  8217. var _rocketTick = win.rocketTick;
  8218. win.rocketTick = function ()
  8219. {
  8220. _rocketTick();
  8221. var rocketBox = document.getElementById('itembox-rocket');
  8222. if (rocketBox && /^\d+\s*Km$/i.test(rocketBox.textContent || ''))
  8223. {
  8224. rocketBox.innerHTML = format.numbersInText(rocketBox.innerHTML).replace('Km', 'km');
  8225. }
  8226. };
  8227. }
  8228. fixNumbers.init = init;
  8229. })(fixNumbers || (fixNumbers = {}));
  8230.  
  8231. /**
  8232. * add slider for machines
  8233. */
  8234. var machineDialog;
  8235. (function (machineDialog)
  8236. {
  8237. machineDialog.name = 'machineDialog';
  8238. var $slider;
  8239.  
  8240. function createSlider()
  8241. {
  8242. var br = document.querySelector('#dialogue-machinery-current-total ~ br');
  8243. var parent = br && br.parentElement;
  8244. if (!br || !parent)
  8245. {
  8246. return;
  8247. }
  8248. 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");
  8249. var slider = document.createElement('div');
  8250. parent.insertBefore(slider, br);
  8251. $slider = win.$(slider)
  8252. .slider(
  8253. {
  8254. range: 'max'
  8255. , min: 0
  8256. , max: 10
  8257. , value: 0
  8258. , slide: function (event, ui)
  8259. {
  8260. return updateValue(ui.value);
  8261. }
  8262. });
  8263. // hide br and up/down arrows
  8264. br.style.display = 'none';
  8265. var arrows = document.querySelectorAll('input[onclick^="turnOn("]');
  8266. for (var i = 0; i < arrows.length; i++)
  8267. {
  8268. arrows[i].style.display = 'none';
  8269. }
  8270. var els = document.querySelectorAll('[onclick*="openMachineryDialogue("]');
  8271. var boundMachineKeyList = [];
  8272. for (var i = 0; i < els.length; i++)
  8273. {
  8274. var match = els[i].id.match(/openMachineryDialogue\('(.+?)'\)/);
  8275. if (match)
  8276. {
  8277. boundMachineKeyList.push(getBoundKey(match[1]));
  8278. }
  8279. }
  8280. observer.add(boundMachineKeyList, function ()
  8281. {
  8282. return updateMax();
  8283. });
  8284. }
  8285.  
  8286. function updateMax()
  8287. {
  8288. var machineEl = document.getElementById('dialogue-machinery-chosen');
  8289. if (machineEl && machineEl.value != '')
  8290. {
  8291. var boundMachineKey = getBoundKey(machineEl.value);
  8292. var ownedNum = getGameValue(boundMachineKey);
  8293. $slider.slider('option', 'max', ownedNum);
  8294. $slider.get(0).dataset.owned = ownedNum.toString();
  8295. }
  8296. }
  8297.  
  8298. function updateValue(value)
  8299. {
  8300. var typeEl = document.getElementById('dialogue-machinery-chosen');
  8301. var numEl = document.getElementById('dialogue-machinery-current-on');
  8302. if (numEl && typeEl)
  8303. {
  8304. var valueBefore = parseInt(numEl.textContent || '0', 10);
  8305. var machine = typeEl.value;
  8306. var increment = valueBefore < value;
  8307. var diff = Math.abs(valueBefore - value);
  8308. for (var i = 0; i < diff; i++)
  8309. {
  8310. win.turnOn(machine, increment);
  8311. }
  8312. }
  8313. }
  8314.  
  8315. function init()
  8316. {
  8317. if (!settings.get(settings.KEY.changeMachineDialog))
  8318. {
  8319. return;
  8320. }
  8321. createSlider();
  8322. var _openMachineryDialogue = win.openMachineryDialogue;
  8323. win.openMachineryDialogue = function (machineType)
  8324. {
  8325. _openMachineryDialogue(machineType);
  8326. updateMax();
  8327. $slider.slider('value', getGameValue(machineType + 'On'));
  8328. };
  8329. }
  8330. machineDialog.init = init;
  8331. })(machineDialog || (machineDialog = {}));
  8332.  
  8333. /**
  8334. * improve behaviour of amount inputs
  8335. */
  8336. var amountInputs;
  8337. (function (amountInputs)
  8338. {
  8339. amountInputs.name = 'amountInputs';
  8340.  
  8341. function getVialType(recipe)
  8342. {
  8343. return recipe.levelReq < 35 ? 'vialOfWater' : (recipe.levelReq < 65 ? 'largeVialOfWater' : 'hugeVialOfWater');
  8344. }
  8345.  
  8346. function getSimpleMax(recipe)
  8347. {
  8348. var max = Number.MAX_SAFE_INTEGER;
  8349. for (var i = 0; i < recipe.recipe.length; i++)
  8350. {
  8351. max = Math.min(max, Math.floor(getGameValue(recipe.recipe[i]) / recipe.recipeCost[i]));
  8352. }
  8353. return max;
  8354. }
  8355.  
  8356. function getMax(recipe)
  8357. {
  8358. var max = getSimpleMax(recipe);
  8359. if (/Potion$/.test(recipe.itemName))
  8360. {
  8361. var vialType = getVialType(recipe);
  8362. max = Math.min(max, getGameValue(vialType));
  8363. }
  8364. return max;
  8365. }
  8366.  
  8367. function ensureNumberInput(idOrEl)
  8368. {
  8369. var numInput = typeof idOrEl === 'string' ? document.getElementById(idOrEl) : idOrEl;
  8370. if (numInput)
  8371. {
  8372. if (numInput.type != 'number' && settings.get(settings.KEY.makeNumberInputs))
  8373. {
  8374. var width = numInput.clientWidth;
  8375. if (width !== 0)
  8376. {
  8377. numInput.style.width = width + 'px';
  8378. }
  8379. numInput.type = 'number';
  8380. numInput.min = '0';
  8381. var onkeyup_1 = numInput.getAttribute('onkeyup');
  8382. if (onkeyup_1)
  8383. {
  8384. numInput.setAttribute('onmouseup', onkeyup_1);
  8385. }
  8386. }
  8387. else if (numInput.type == 'number' && !settings.get(settings.KEY.makeNumberInputs))
  8388. {
  8389. numInput.style.width = '';
  8390. numInput.type = '';
  8391. numInput.removeAttribute('onmouseup');
  8392. }
  8393. }
  8394. return numInput;
  8395. }
  8396.  
  8397. function getCurrentMax(keyId, recipeCollection)
  8398. {
  8399. var keyEl = document.getElementById(keyId);
  8400. if (!keyEl)
  8401. {
  8402. return 0;
  8403. }
  8404. var key = keyEl.value;
  8405. return getMax(recipeCollection[key]);
  8406. };
  8407.  
  8408. function ensureMaxBtn(keyId, inputId, recipeCollection, key)
  8409. {
  8410. var recipe = recipeCollection[key];
  8411. var numInput = ensureNumberInput(inputId);
  8412. var next = numInput && numInput.nextElementSibling;
  8413. var parent = numInput && numInput.parentElement;
  8414. if (numInput && parent)
  8415. {
  8416. if ((!next || next.nodeName !== 'BUTTON') && settings.get(settings.KEY.addMaxBtn))
  8417. {
  8418. var btn = document.createElement('button');
  8419. btn.textContent = 'Max';
  8420. btn.addEventListener('click', function ()
  8421. {
  8422. numInput.value = getCurrentMax(keyId, recipeCollection).toString();
  8423. });
  8424. parent.appendChild(btn);
  8425. }
  8426. else if (next && next.nodeName === 'BUTTON' && !settings.get(settings.KEY.addMaxBtn))
  8427. {
  8428. parent.removeChild(next);
  8429. }
  8430. numInput.value = Math.min(1, getMax(recipe)).toString();
  8431. numInput.select();
  8432. }
  8433. }
  8434.  
  8435. function watchKeepInput(event)
  8436. {
  8437. var itemInput = document.getElementById('npc-sell-item-chosen');
  8438. var numInput = ensureNumberInput('dialogue-input-cmd');
  8439. if (!itemInput || !numInput)
  8440. {
  8441. return;
  8442. }
  8443. var item = itemInput.value;
  8444. var newValue = Math.max(getGameValue(item) - Number(this.value), 0);
  8445. numInput.value = newValue.toString();
  8446. }
  8447.  
  8448. function updateKeepMaxValue(keepInput, init)
  8449. {
  8450. if (init === void 0)
  8451. {
  8452. init = false;
  8453. }
  8454. var itemInput = document.getElementById('npc-sell-item-chosen');
  8455. if (!itemInput)
  8456. {
  8457. return;
  8458. }
  8459. var item = itemInput.value;
  8460. var max = getGameValue(item);
  8461. keepInput.max = max.toString();
  8462. if (init)
  8463. {
  8464. observer.addTick(function ()
  8465. {
  8466. return updateKeepMaxValue(keepInput);
  8467. });
  8468. }
  8469. }
  8470.  
  8471. function ensureKeepInput(item)
  8472. {
  8473. var numInput = ensureNumberInput('dialogue-input-cmd');
  8474. var parent = numInput && numInput.parentElement;
  8475. var next = numInput && numInput.nextElementSibling;
  8476. var nextNext = next && next.nextElementSibling;
  8477. if (next && nextNext && parent)
  8478. {
  8479. if (nextNext.nodeName === 'BR' && settings.get(settings.KEY.addKeepInput))
  8480. {
  8481. var div = document.createElement('div');
  8482. var text = document.createTextNode('Keep: ');
  8483. div.appendChild(text);
  8484. var keepInput = document.createElement('input');
  8485. keepInput.type = 'number';
  8486. keepInput.value = keepInput.min = '0';
  8487. keepInput.max = getGameValue(item).toString();
  8488. keepInput.addEventListener('keyup', watchKeepInput);
  8489. keepInput.addEventListener('mouseup', watchKeepInput);
  8490. updateKeepMaxValue(keepInput, true);
  8491. div.appendChild(keepInput);
  8492. parent.insertBefore(div, nextNext);
  8493. }
  8494. else if (nextNext.nodeName !== 'BR' && !settings.get(settings.KEY.addKeepInput))
  8495. {
  8496. var br = document.createElement('br');
  8497. parent.insertBefore(br, nextNext);
  8498. parent.removeChild(nextNext);
  8499. }
  8500. }
  8501. }
  8502.  
  8503. function init()
  8504. {
  8505. var _multiCraft = win.multiCraft;
  8506. win.multiCraft = function (item)
  8507. {
  8508. _multiCraft(item);
  8509. ensureMaxBtn('dialogue-multicraft-chosen', 'dialogue-multicraft-input', win.craftingRecipes, item);
  8510. };
  8511. var _brew = win.brew;
  8512. win.brew = function (potion)
  8513. {
  8514. _brew(potion);
  8515. ensureMaxBtn('dialogue-potion-chosen', 'dialogue-brewing-input', win.brewingRecipes, potion);
  8516. };
  8517. var _cooksBookInputDialogue = win.cooksBookInputDialogue;
  8518. win.cooksBookInputDialogue = function (food)
  8519. {
  8520. _cooksBookInputDialogue(food);
  8521. ensureMaxBtn('dialogue-cooksBook-chosen', 'dialogue-cooksBook-input', win.cooksBookRecipes, food);
  8522. };
  8523. var _openSellNPCDialogue = win.openSellNPCDialogue;
  8524. win.openSellNPCDialogue = function (item)
  8525. {
  8526. _openSellNPCDialogue(item);
  8527. ensureKeepInput(item);
  8528. };
  8529. var allowedInputs = [
  8530. 'dialogue-ashes'
  8531. , 'dialogue-bindDonorCoins'
  8532. , 'dialogue-bonemeal'
  8533. , 'dialogue-bones'
  8534. , 'dialogue-brewing'
  8535. , 'dialogue-buy-item-2'
  8536. , 'dialogue-buyFromMarket'
  8537. , 'dialogue-charcoalFoundry'
  8538. , 'dialogue-consume'
  8539. , 'dialogue-cooksBook'
  8540. , 'dialogue-createArrows'
  8541. , 'dialogue-createFireArrows'
  8542. , 'dialogue-createIceArrows'
  8543. , 'dialogue-furnace'
  8544. , 'dialogue-iceBones'
  8545. , 'dialogue-id-boundHammer'
  8546. , 'dialogue-id-boundPickaxe'
  8547. , 'dialogue-id-cook-food'
  8548. , 'dialogue-id-oven-addheat'
  8549. , 'dialogue-market-chosenpostitem'
  8550. , 'dialogue-multicraft'
  8551. , 'dialogue-oilBarrels'
  8552. , 'dialogue-oilFactory'
  8553. , 'dialogue-sell-item'
  8554. , 'dialogue-stardustCrystals'
  8555. , 'dialogue-wand'
  8556. ];
  8557. var _openDialogue = win.openDialogue;
  8558. win.openDialogue = function (id, width, position)
  8559. {
  8560. _openDialogue(id, width, position);
  8561. if (allowedInputs.indexOf(id) === -1
  8562. || id === 'dialogue-buyFromMarket' && market.detectTedsUI()
  8563. || id === 'dialogue-market-chosenpostitem' && market.detectTedsUI())
  8564. {
  8565. return;
  8566. }
  8567. var dialog = document.getElementById(id);
  8568. var input = dialog && dialog.querySelector('input[type="text"],input[type="number"]');
  8569. if (!input)
  8570. {
  8571. return;
  8572. }
  8573. ensureNumberInput(input);
  8574. };
  8575. }
  8576. amountInputs.init = init;
  8577. })(amountInputs || (amountInputs = {}));
  8578.  
  8579. /**
  8580. * improves the top bar
  8581. */
  8582. var newTopbar;
  8583. (function (newTopbar)
  8584. {
  8585. newTopbar.name = 'newTopbar';
  8586. var linkCell, tabCell, infoCell;
  8587. var addQueues = {
  8588. link: []
  8589. , tab: []
  8590. , info: []
  8591. };
  8592.  
  8593. function createPipeNode()
  8594. {
  8595. return document.createTextNode('|');
  8596. }
  8597.  
  8598. function addLinkEntry(el)
  8599. {
  8600. if (!linkCell)
  8601. {
  8602. addQueues.link.push(el);
  8603. }
  8604. else
  8605. {
  8606. linkCell.appendChild(createPipeNode());
  8607. linkCell.appendChild(el);
  8608. }
  8609. }
  8610. newTopbar.addLinkEntry = addLinkEntry;
  8611.  
  8612. function addTabEntry(el)
  8613. {
  8614. if (!tabCell)
  8615. {
  8616. addQueues.tab.push(el);
  8617. }
  8618. else
  8619. {
  8620. tabCell.appendChild(createPipeNode());
  8621. tabCell.appendChild(el);
  8622. }
  8623. }
  8624. newTopbar.addTabEntry = addTabEntry;
  8625.  
  8626. function addInfoEntry(el)
  8627. {
  8628. if (!infoCell)
  8629. {
  8630. addQueues.info.push(el);
  8631. }
  8632. else
  8633. {
  8634. if (infoCell.firstChild)
  8635. {
  8636. infoCell.insertBefore(createPipeNode(), infoCell.firstChild);
  8637. infoCell.insertBefore(el, infoCell.firstChild);
  8638. }
  8639. else
  8640. {
  8641. infoCell.appendChild(createPipeNode());
  8642. infoCell.appendChild(el);
  8643. }
  8644. }
  8645. }
  8646. newTopbar.addInfoEntry = addInfoEntry;
  8647.  
  8648. function init()
  8649. {
  8650. if (!settings.get(settings.KEY.useNewToolbar))
  8651. {
  8652. return;
  8653. }
  8654. 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");
  8655. var table = document.querySelector('table.top-links');
  8656. if (!table)
  8657. {
  8658. return;
  8659. }
  8660. var row = table.rows.item(0);
  8661. var cells = row.cells;
  8662. var tabIdx = [2, 5];
  8663. var infoIdx = [6, 7];
  8664. var newRow = table.insertRow(-1);
  8665. linkCell = newRow.insertCell(-1);
  8666. tabCell = newRow.insertCell(-1);
  8667. tabCell.style.textAlign = 'center';
  8668. infoCell = newRow.insertCell(-1);
  8669. infoCell.style.textAlign = 'right';
  8670. for (var i = 0; i < cells.length; i++)
  8671. {
  8672. var container = linkCell;
  8673. if (tabIdx.indexOf(i) != -1)
  8674. {
  8675. container = tabCell;
  8676. }
  8677. else if (infoIdx.indexOf(i) != -1)
  8678. {
  8679. container = infoCell;
  8680. }
  8681. var cell = cells.item(i);
  8682. var el = cell.firstElementChild;
  8683. if (cell.childNodes.length > 1)
  8684. {
  8685. el = document.createElement('span');
  8686. el.style.color = 'yellow';
  8687. while (cell.childNodes.length > 0)
  8688. {
  8689. el.appendChild(cell.childNodes[0]);
  8690. }
  8691. }
  8692. if (container.children.length > 0)
  8693. {
  8694. container.appendChild(createPipeNode());
  8695. }
  8696. if (el)
  8697. {
  8698. container.appendChild(el);
  8699. }
  8700. }
  8701. var parent = row.parentElement;
  8702. if (parent)
  8703. {
  8704. parent.removeChild(row);
  8705. }
  8706. for (var _i = 0, _a = addQueues.link; _i < _a.length; _i++)
  8707. {
  8708. var el = _a[_i];
  8709. addLinkEntry(el);
  8710. }
  8711. for (var _b = 0, _c = addQueues.tab; _b < _c.length; _b++)
  8712. {
  8713. var el = _c[_b];
  8714. addTabEntry(el);
  8715. }
  8716. for (var _d = 0, _e = addQueues.info; _d < _e.length; _d++)
  8717. {
  8718. var el = _e[_d];
  8719. addInfoEntry(el);
  8720. }
  8721. var _openTab = win.openTab;
  8722. win.openTab = function (newTab)
  8723. {
  8724. var oldTab = win.currentOpenTab;
  8725. _openTab(newTab);
  8726. var children = tabCell.children;
  8727. for (var i = 0; i < children.length; i++)
  8728. {
  8729. var el = children[i];
  8730. var match = (el.getAttribute('onclick') || '').match(/openTab\('([^']+)'\)/);
  8731. if (!match)
  8732. {
  8733. continue;
  8734. }
  8735. var tab = match[1];
  8736. if (oldTab == tab)
  8737. {
  8738. el.style.color = '';
  8739. }
  8740. if (newTab == tab)
  8741. {
  8742. el.style.color = 'white';
  8743. }
  8744. }
  8745. };
  8746. }
  8747. newTopbar.init = init;
  8748. })(newTopbar || (newTopbar = {}));
  8749.  
  8750. /**
  8751. * style tweaks
  8752. */
  8753. var styleTweaks;
  8754. (function (styleTweaks)
  8755. {
  8756. styleTweaks.name = 'styleTweaks';
  8757. var bodyRegex = /(\bbody)(\s|$)/i;
  8758.  
  8759. function addTweakStyle(setting, style)
  8760. {
  8761. if (setting != '')
  8762. {
  8763. var prefix_1 = setting === '' ? '' : 'body.' + setting + ' ';
  8764. style = style
  8765. .replace(/(^\s*|\}\s*)([^\{\}]+)(?=\s*\{)/g, function (wholeMatch, before, rules)
  8766. {
  8767. return before + rules.split(',').map(function (rule)
  8768. {
  8769. if (bodyRegex.test(rule) && setting !== '')
  8770. {
  8771. return rule.replace(bodyRegex, '$1.' + setting + '$2');
  8772. }
  8773. return rule.replace(/^(\s*\n\s*)?/, '$1' + prefix_1);
  8774. }).join(',');
  8775. });
  8776. document.body.classList.add(setting);
  8777. }
  8778. addStyle(style, setting != '' ? setting : null);
  8779. }
  8780. // tweak oil production/consumption
  8781. function tweakOil()
  8782. {
  8783. 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");
  8784. // make room for oil cell on small devices
  8785. var oilFlowValues = document.getElementById('oil-flow-values');
  8786. var oilFlowCell = oilFlowValues.parentElement;
  8787. oilFlowCell.style.width = '30%';
  8788. }
  8789.  
  8790. function tweakSelection()
  8791. {
  8792. 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");
  8793. }
  8794. // tweak stardust monitor of DH2QoL to keep it in place
  8795. function tweakStardust()
  8796. {
  8797. 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");
  8798. }
  8799.  
  8800. function tweakSkillLevelText()
  8801. {
  8802. addTweakStyle('', "\ndiv.skill-xp-label\n{\n\ttext-shadow: white 0px 0px 0.5rem;\n}\n\t\t");
  8803. }
  8804.  
  8805. function tweakFightDialog()
  8806. {
  8807. 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");
  8808. }
  8809.  
  8810. function addAdditionalSkillBars()
  8811. {
  8812. var _loadSkillTabs = win.loadSkillTabs;
  8813. win.loadSkillTabs = function ()
  8814. {
  8815. _loadSkillTabs();
  8816. for (var _i = 0, SKILL_LIST_1 = SKILL_LIST; _i < SKILL_LIST_1.length; _i++)
  8817. {
  8818. var skill = SKILL_LIST_1[_i];
  8819. var unlocked = getGameValue(skill + 'Unlocked') == 1;
  8820. if (!unlocked)
  8821. {
  8822. continue;
  8823. }
  8824. var xp = getGameValue(skill + 'Xp');
  8825. var currentLevelXp = win.getXpNeeded(win.getLevel(xp));
  8826. var nextLevelXp = win.getXpNeeded(win.getLevel(xp) + 1);
  8827. var perc = (xp - currentLevelXp) / (nextLevelXp - currentLevelXp) * 100;
  8828. var progress = document.getElementById('skill-progress-' + skill);
  8829. if (progress)
  8830. {
  8831. if (currentLevelXp >= 10000000)
  8832. {
  8833. perc = 100;
  8834. progress.style.backgroundColor = "yellow";
  8835. }
  8836. progress.style.width = perc + '%';
  8837. }
  8838. }
  8839. };
  8840. // init additional skill bars
  8841. 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");
  8842. for (var _i = 0, SKILL_LIST_2 = SKILL_LIST; _i < SKILL_LIST_2.length; _i++)
  8843. {
  8844. var skill = SKILL_LIST_2[_i];
  8845. var cell = document.getElementById('top-bar-level-td-' + skill);
  8846. if (!cell)
  8847. {
  8848. continue;
  8849. }
  8850. var levelBar = document.createElement('div');
  8851. levelBar.className = 'skill-bar';
  8852. var progress = document.createElement('div');
  8853. progress.id = 'skill-progress-' + skill;
  8854. progress.className = 'skill-progress';
  8855. levelBar.appendChild(progress);
  8856. cell.appendChild(levelBar);
  8857. // update skill level progress bars on click
  8858. levelBar.addEventListener('click', function ()
  8859. {
  8860. return win.loadSkillTabs();
  8861. });
  8862. }
  8863. win.loadSkillTabs();
  8864. }
  8865. // highlight cooking level requirement when not matched
  8866. function highlightCookinglevel()
  8867. {
  8868. var _cookFoodDialogue = win.cookFoodDialogue;
  8869. win.cookFoodDialogue = function (rawFood)
  8870. {
  8871. _cookFoodDialogue(rawFood);
  8872. var dialog = document.getElementById('dialogue-id-cook-food');
  8873. if (!dialog)
  8874. {
  8875. return;
  8876. }
  8877. var levelReq = document.getElementById('dialogue-cook-levelReq');
  8878. var levelReqLabel = levelReq && levelReq.previousElementSibling;
  8879. if (!levelReq || !levelReqLabel)
  8880. {
  8881. return;
  8882. }
  8883. var fulfilled = win.getCookingLevelReq(rawFood) > win.getLevel(win.cookingXp);
  8884. levelReq.style.color = fulfilled ? 'rgb(204, 0, 0)' : '';
  8885. levelReq.style.fontWeight = fulfilled ? 'bold' : '';
  8886. levelReqLabel.style.color = fulfilled ? 'rgb(204, 0, 0)' : '';
  8887. var ratioEl = document.getElementById('dialogue-cook-ratio');
  8888. if (!ratioEl)
  8889. {
  8890. var cookReqBox = levelReq.parentElement;
  8891. var br = document.createElement('br');
  8892. cookReqBox.appendChild(br);
  8893. var b = document.createElement('b');
  8894. 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\">: ";
  8895. cookReqBox.appendChild(b);
  8896. ratioEl = document.createElement('span');
  8897. ratioEl.id = 'dialogue-cook-ratio';
  8898. cookReqBox.appendChild(ratioEl);
  8899. }
  8900. var heat = win.getHeatNeeded(rawFood);
  8901. var energy = win.getEnergyGained(rawFood);
  8902. ratioEl.textContent = format.number(Math.round(energy / heat * 100) / 100);
  8903. };
  8904. }
  8905.  
  8906. function amountStyle()
  8907. {
  8908. var tweakName = 'amount-symbol';
  8909. 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");
  8910.  
  8911. function setAmountSymbolVisibility(init)
  8912. {
  8913. if (init === void 0)
  8914. {
  8915. init = false;
  8916. }
  8917. var show = settings.get(settings.KEY.amountSymbol);
  8918. document.body.classList[show ? 'add' : 'remove'](tweakName);
  8919. if (init)
  8920. {
  8921. settings.observe(settings.KEY.amountSymbol, function ()
  8922. {
  8923. return setAmountSymbolVisibility();
  8924. });
  8925. }
  8926. }
  8927. setAmountSymbolVisibility(true);
  8928. }
  8929.  
  8930. function efficiency()
  8931. {
  8932. var EFFICIENCY_CLASS = 'efficiency';
  8933. 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");
  8934. var farmingTab = document.getElementById('tab-container-farming');
  8935. if (farmingTab)
  8936. {
  8937. removeWhitespaceChildNodes(farmingTab);
  8938. }
  8939. var combatSubTab = document.getElementById('tab-sub-container-combat');
  8940. if (combatSubTab)
  8941. {
  8942. removeWhitespaceChildNodes(combatSubTab);
  8943. }
  8944.  
  8945. function checkSetting(init)
  8946. {
  8947. if (init === void 0)
  8948. {
  8949. init = false;
  8950. }
  8951. var show = settings.get(settings.KEY.useEfficiencyStyle);
  8952. document.body.classList[show ? 'add' : 'remove'](EFFICIENCY_CLASS);
  8953. if (init)
  8954. {
  8955. settings.observe(settings.KEY.useEfficiencyStyle, function ()
  8956. {
  8957. return checkSetting();
  8958. });
  8959. }
  8960. }
  8961. checkSetting(true);
  8962. }
  8963.  
  8964. function hardcore()
  8965. {
  8966. if (win.isHardcore != 1)
  8967. {
  8968. return;
  8969. }
  8970. addStyle("\nspan#shop-giant-button-playermarket\n{\n\tbackground-color: gray;\n\tbackground-image: none;\n\tcursor: not-allowed;\n}\n\t\t");
  8971. var marketBtn = document.getElementById('shop-giant-button-playermarket');
  8972. if (marketBtn)
  8973. {
  8974. marketBtn.removeAttribute('onclick');
  8975. marketBtn.setAttribute('title', 'The player market is disabled for hardcore accounts');
  8976. }
  8977. }
  8978.  
  8979. function smallScreen()
  8980. {
  8981. addStyle("\ntable.top-links\n{\n\tz-index: 10;\n}\n\t\t");
  8982. }
  8983.  
  8984. function init()
  8985. {
  8986. tweakOil();
  8987. tweakSelection();
  8988. tweakStardust();
  8989. tweakSkillLevelText();
  8990. tweakFightDialog();
  8991. addAdditionalSkillBars();
  8992. highlightCookinglevel();
  8993. amountStyle();
  8994. efficiency();
  8995. //hardcore();
  8996. smallScreen();
  8997. }
  8998. styleTweaks.init = init;
  8999. })(styleTweaks || (styleTweaks = {}));
  9000.  
  9001. /**
  9002. * add ingame notification boxes
  9003. */
  9004. var notifBoxes;
  9005. (function (notifBoxes)
  9006. {
  9007. notifBoxes.name = 'notifBoxes';
  9008.  
  9009. function addNotifBox(imageKey, itemKey, showFront)
  9010. {
  9011. if (itemKey === void 0)
  9012. {
  9013. itemKey = null;
  9014. }
  9015. if (showFront === void 0)
  9016. {
  9017. showFront = false;
  9018. }
  9019. var notifBox = document.createElement('span');
  9020. notifBox.className = 'notif-box';
  9021. notifBox.id = 'notification-static-' + imageKey;
  9022. notifBox.style.display = 'none';
  9023. if (showFront)
  9024. {
  9025. notifBox.style.cssFloat = 'left';
  9026. }
  9027. notifBox.innerHTML = "<img src=\"images/" + imageKey + ".png\" class=\"image-icon-50\" id=\"notif-" + imageKey + "-img\">";
  9028. if (itemKey != null)
  9029. {
  9030. notifBox.innerHTML += "<span data-item-display=\"" + itemKey + "\" style=\"margin-left: 10px;\"></span>";
  9031. }
  9032. var notifArea = document.getElementById('notifaction-area');
  9033. if (notifArea)
  9034. {
  9035. notifArea.appendChild(notifBox);
  9036. }
  9037. return notifBox;
  9038. }
  9039.  
  9040. function addWorker()
  9041. {
  9042. var notifBox = addNotifBox('workers', null, true);
  9043.  
  9044. function setVisibility()
  9045. {
  9046. var show = win.workersTimer === 1 && settings.get(settings.KEY.useWorkerNotif);
  9047. notifBox.style.display = show ? '' : 'none';
  9048. }
  9049. setVisibility();
  9050. observer.addTick(function ()
  9051. {
  9052. return setVisibility();
  9053. });
  9054. }
  9055. function addFaradoxCrystal()
  9056. {
  9057. var notifBox = addNotifBox('faradoxsLair/tombIcon', null, true);
  9058.  
  9059. function setVisibility()
  9060. {
  9061. var show = win.tombCd == 0 && quest16 == -1 && settings.get(settings.KEY.useTombNotif);
  9062. notifBox.style.display = show ? '' : 'none';
  9063. }
  9064. setVisibility();
  9065. observer.addTick(function ()
  9066. {
  9067. return setVisibility();
  9068. });
  9069. }
  9070. function addBobsUncle()
  9071. {
  9072. var notifBox = addNotifBox('bobsUncle', null, true);
  9073.  
  9074. function setVisibility()
  9075. {
  9076. var show = win.farmingPatchStage7 == 4 && settings.get(settings.KEY.useBobsUncleNotif);
  9077. notifBox.style.display = show ? '' : 'none';
  9078. }
  9079. setVisibility();
  9080. observer.addTick(function ()
  9081. {
  9082. return setVisibility();
  9083. });
  9084. }
  9085. function addRedMap()
  9086. {
  9087. var notifBox = addNotifBox('redTreasureMap', null, true);
  9088.  
  9089. function setVisibility()
  9090. {
  9091. var show = win.redTreasureMap === 1;
  9092. notifBox.style.display = show ? '' : 'none';
  9093. }
  9094. setVisibility();
  9095. observer.addTick(function ()
  9096. {
  9097. return setVisibility();
  9098. });
  9099. }
  9100. function init()
  9101. {
  9102. addStyle("\n#notifaction-area\n{\n\tpadding: 5px 0;\n}\nspan.notif-box\n{\n\tfont-size: 1rem;\n\tmargin: 0;\n\tmargin-right: 5px;\n}\ntable.tab-bar\n{\n\tmargin-top: 0;\n}\nspan.notif-box,\ntable.tab-bar td\n{\n\tborder-color: gray;\n}\nspan.notif-box[id^=\"notification-static-\"]\n{\n\tbackground: linear-gradient(rgb(22, 22, 24), rgb(72, 171, 50));\n}\n\t\t");
  9103. // remove pure text nodes
  9104. var notifArea = document.getElementById('notifaction-area');
  9105. if (notifArea)
  9106. {
  9107. removeWhitespaceChildNodes(notifArea);
  9108. }
  9109. addWorker();
  9110. addBobsUncle();
  9111. //addFaradoxCrystal();
  9112. addRedMap();
  9113. }
  9114. notifBoxes.init = init;
  9115. })(notifBoxes || (notifBoxes = {}));
  9116.  
  9117.  
  9118. /**
  9119. * extend market
  9120. */
  9121. var market;
  9122. (function (market)
  9123. {
  9124. market.name = 'market';
  9125. // max limit age: 5min
  9126. var MAX_LIMIT_AGE = 5 * 60 * 1e3;
  9127. var PRICE_HISTORY_KEY = 'priceHistory';
  9128. // 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)
  9129. var MAX_ENTRIES_PER_ITEM = 2e3;
  9130. var SYNC_URL_REGEX = /^(?:https?:\/\/)?(?:(?:www\.)?myjson\.com\/|api\.myjson\.com\/bins\/)([^\/]+)$/i;
  9131. var detectedTedsUIOnce = false;
  9132.  
  9133. function detectTedsUI()
  9134. {
  9135. return detectedTedsUIOnce = detectedTedsUIOnce || typeof win.changeSetting === 'function';
  9136. }
  9137. market.detectTedsUI = detectTedsUI;
  9138. var priceHistory = store.has(PRICE_HISTORY_KEY) ? store.get(PRICE_HISTORY_KEY) :
  9139. {};
  9140. var getItemColor = function (H, S, L)
  9141. {
  9142. return [
  9143. "hsl(" + H + ", " + S + "%, " + L + "%)"
  9144. , "hsl(" + H + ", " + S + "%, " + (L < 35 ? L + 35 : L - 35) + "%)"
  9145. ];
  9146. };
  9147. var itemColor = {
  9148. 'blewitMushroom': getItemColor(255, 100, 78)
  9149. , 'bronzeBar': getItemColor(39, 100, 46)
  9150. , 'crystalLeaf': getItemColor(226, 100, 50)
  9151. , 'diamond': getItemColor(186, 76, 82)
  9152. , 'dottedGreenLeaf': getItemColor(92, 63, 19)
  9153. , 'emerald': getItemColor(110, 100, 48)
  9154. , 'goldLeaf': getItemColor(50, 100, 50)
  9155. , 'goldBar': getItemColor(54, 100, 46)
  9156. , 'greenLeaf': getItemColor(92, 63, 28)
  9157. , 'ironBar': getItemColor(44, 11, 46)
  9158. , 'limeLeaf': getItemColor(110, 72, 40)
  9159. , 'promethiumBar': getItemColor(354, 81, 46)
  9160. , 'redMushroom': getItemColor(0, 83, 48)
  9161. , 'ruby': getItemColor(5, 87, 45)
  9162. , 'sapphire': getItemColor(197, 100, 32)
  9163. , 'shrimp': getItemColor(17, 88, 50)
  9164. , 'silverBar': getItemColor(0, 0, 74)
  9165. , 'snapegrass': getItemColor(120, 99, 42)
  9166. , 'stardust': getItemColor(37, 100, 50)
  9167. //, 'strangeLeaf': getItemColor(195, 100, 40)
  9168. };
  9169. // use ambassadors to name the categories
  9170. var categoryAmbassador2CategoryName = {
  9171. 'stone': 'Ores' // 0
  9172. , 'emptyChisel': 'Crystals' // 1
  9173. , 'bronzeBar': 'Bars' // 2
  9174. , 'dottedGreenLeafSeeds': 'Seeds' // 3
  9175. , 'logs': 'Logs' // 4
  9176. , 'dottedGreenLeaf': 'Ingredients' // 5
  9177. , 'rawShrimp': 'Fish' // 6
  9178. , 'shrimp': 'Food' // 7
  9179. , 'stinger': 'Equipment' // 8
  9180. , 'promethiumHelmetMould': 'Mould' // 9
  9181. //, 'essence': 'Magic' // 10
  9182. , 'blueFishingRodOrb': 'Orbs' // 10
  9183. , 'stardust': 'Other' // 11
  9184. };
  9185. var item2Category = new Map();
  9186. var category2Name = new Map();
  9187. var item2Resolver = new Map();
  9188. var itemLimits = new Map();
  9189. var offerPerItem = new Map();
  9190. var offerList = new Array();
  9191. var lastSyncValue = '{}';
  9192.  
  9193. function getSyncUrl()
  9194. {
  9195. if (!settings.get(settings.KEY.syncPriceHistory))
  9196. {
  9197. return null;
  9198. }
  9199. var url = settings.getSub(settings.KEY.syncPriceHistory, 'url');
  9200. var match = url.match(SYNC_URL_REGEX);
  9201. if (!match)
  9202. {
  9203. console.error('URL "' + url + '" does not match the expected pattern: ' + SYNC_URL_REGEX.source);
  9204. return null;
  9205. }
  9206. return 'https://api.myjson.com/bins/' + match[1];
  9207. }
  9208.  
  9209. function integratePriceData(data, responseText)
  9210. {
  9211. var changed = recIntegrate(data, priceHistory);
  9212. lastSyncValue = responseText;
  9213. return changed;
  9214.  
  9215. function recIntegrate(source, target)
  9216. {
  9217. var changed = false;
  9218. if (typeof source !== typeof target)
  9219. {
  9220. console.error('Different data types. Could not integrate data into local price history.\nsource: ' + JSON.stringify(source) + '\ntarget: ' + JSON.stringify(target));
  9221. }
  9222. else if (typeof source === 'object')
  9223. {
  9224. for (var key in source)
  9225. {
  9226. if (source.hasOwnProperty(key))
  9227. {
  9228. if (!target.hasOwnProperty(key))
  9229. {
  9230. target[key] = source[key];
  9231. changed = true;
  9232. }
  9233. else if (recIntegrate(source[key], target[key]))
  9234. {
  9235. changed = true;
  9236. }
  9237. }
  9238. }
  9239. }
  9240. else
  9241. {
  9242. // do nothing and prefer the local value
  9243. }
  9244. return changed;
  9245. }
  9246. }
  9247.  
  9248. function loadPriceHistory()
  9249. {
  9250. var url = getSyncUrl();
  9251. if (url)
  9252. {
  9253. win.$.get(url, function (data, textStatus, jqXHR)
  9254. {
  9255. if (integratePriceData(data, jqXHR.responseText))
  9256. {
  9257. savePriceHistory(true);
  9258. }
  9259. });
  9260. }
  9261. }
  9262.  
  9263. function savePriceHistory(forceWrite)
  9264. {
  9265. if (forceWrite === void 0)
  9266. {
  9267. forceWrite = false;
  9268. }
  9269. for (var itemKey in priceHistory)
  9270. {
  9271. var history_1 = priceHistory[itemKey];
  9272. var timestampList = Object.keys(history_1).sort();
  9273. var i = 0;
  9274. for (var _i = 0, timestampList_1 = timestampList; _i < timestampList_1.length; _i++)
  9275. {
  9276. var timestamp = timestampList_1[_i];
  9277. i++;
  9278. if (i > MAX_ENTRIES_PER_ITEM)
  9279. {
  9280. delete history_1[timestamp];
  9281. }
  9282. }
  9283. }
  9284. store.set(PRICE_HISTORY_KEY, priceHistory);
  9285. var url = getSyncUrl();
  9286. if (url)
  9287. {
  9288. var doPut_1 = function ()
  9289. {
  9290. $.ajax(
  9291. {
  9292. url: url
  9293. , type: 'PUT'
  9294. , data: JSON.stringify(priceHistory)
  9295. , contentType: 'application/json; charset=utf-8'
  9296. , dataType: 'json'
  9297. , success: function (data, textStatus, jqXHR)
  9298. {
  9299. lastSyncValue = jqXHR.responseText;
  9300. }
  9301. });
  9302. };
  9303. if (forceWrite === true)
  9304. {
  9305. doPut_1();
  9306. }
  9307. else
  9308. {
  9309. win.$.get(url, function (data, textStatus, jqXHR)
  9310. {
  9311. if (lastSyncValue !== jqXHR.responseText)
  9312. {
  9313. integratePriceData(data, jqXHR.responseText);
  9314. }
  9315. doPut_1();
  9316. });
  9317. }
  9318. }
  9319. }
  9320.  
  9321. function processMarketData(data)
  9322. {
  9323. var nowKey = now();
  9324. offerPerItem = new Map();
  9325. offerList = new Array();
  9326. if (data != 'NONE')
  9327. {
  9328. offerList = data.split(';').map(function (offerData)
  9329. {
  9330. var values = offerData.split('~');
  9331. var itemId = Number(values[1]);
  9332. var itemKey = win.jsItemArray[itemId];
  9333. var itemName = key2Name(itemKey);
  9334. var categoryId = item2Category.has(itemKey) ? item2Category.get(itemKey) : -1;
  9335. var offer = {
  9336. offerId: Number(values[0])
  9337. , itemId: itemId
  9338. , itemKey: itemKey
  9339. , itemName: itemName
  9340. , categoryId: categoryId
  9341. , amount: Number(values[2])
  9342. , price: Number(values[3])
  9343. , timeLeft: values[4]
  9344. , playerId: Number(values[5])
  9345. };
  9346. if (!offerPerItem.has(itemKey))
  9347. {
  9348. offerPerItem.set(itemKey, []);
  9349. }
  9350. offerPerItem.get(itemKey).push(offer);
  9351. var history = priceHistory[itemKey];
  9352. if (!history)
  9353. {
  9354. history = {};
  9355. priceHistory[itemKey] = history;
  9356. }
  9357. if (!history.hasOwnProperty(nowKey)
  9358. || history[nowKey] > offer.price)
  9359. {
  9360. history[nowKey] = offer.price;
  9361. }
  9362. return offer;
  9363. });
  9364. }
  9365. savePriceHistory();
  9366. }
  9367.  
  9368. function processItemLimits(itemKey, lowerLimit, upperLimit)
  9369. {
  9370. var limit = {
  9371. timestamp: now()
  9372. , min: lowerLimit
  9373. , max: upperLimit
  9374. };
  9375. itemLimits.set(itemKey, limit);
  9376. if (item2Resolver.has(itemKey))
  9377. {
  9378. var limitArr_1 = [lowerLimit, upperLimit];
  9379. item2Resolver.get(itemKey).forEach(function (resolve)
  9380. {
  9381. return resolve(limitArr_1);
  9382. });
  9383. item2Resolver.delete(itemKey);
  9384. return false;
  9385. }
  9386. return true;
  9387. }
  9388.  
  9389. function showOfferCancelCooldown()
  9390. {
  9391. if (detectTedsUI())
  9392. {
  9393. return;
  9394. }
  9395. 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");
  9396.  
  9397. function slotCooldown(i, init)
  9398. {
  9399. if (init === void 0)
  9400. {
  9401. init = false;
  9402. }
  9403. var cooldownKey = 'marketCancelCooldownSlot' + i;
  9404. var btn = document.getElementById('market-slot-' + i + '-cancel-btn');
  9405. if (btn)
  9406. {
  9407. btn.dataset.cooldown = detectTedsUI() ? '0' : getGameValue(cooldownKey).toString();
  9408. }
  9409. if (init)
  9410. {
  9411. observer.add(cooldownKey, function ()
  9412. {
  9413. return slotCooldown(i);
  9414. });
  9415. }
  9416. }
  9417. for (var i = 1; i <= 3; i++)
  9418. {
  9419. slotCooldown(i, true);
  9420. }
  9421. }
  9422.  
  9423. function addExtraBtns()
  9424. {
  9425. var browseBtn = document.querySelector('.market-browse-button');
  9426. if (!browseBtn)
  9427. {
  9428. return;
  9429. }
  9430. var HISTORY_CLASS = 'local-history';
  9431. var paddingLeft = 30 + 42;
  9432. var paddingRight = 30;
  9433. 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");
  9434. var historyBtn = document.createElement('span');
  9435. historyBtn.className = 'market-browse-button ' + HISTORY_CLASS;
  9436. browseBtn.appendChild(historyBtn);
  9437. var historyItemKey = null;
  9438. var _postItemDialogue = win.postItemDialogue;
  9439. win.postItemDialogue = function (offerTypeEl, itemName, inputEl)
  9440. {
  9441. historyItemKey = itemName;
  9442. _postItemDialogue(offerTypeEl, itemName, inputEl);
  9443. };
  9444. var PRICE_HISTORY_DIALOG_ID = 'dialog-price-history';
  9445. var PRICE_HISTORY_ID = 'price-history';
  9446. var PRICE_HISTORY_ITEM_SELECT_ID = 'price-history-item-select';
  9447. 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");
  9448. var dialog = document.createElement('dialog');
  9449. dialog.id = PRICE_HISTORY_DIALOG_ID;
  9450. dialog.style.display = 'none';
  9451. dialog.style.overflowX = 'hidden';
  9452. 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";
  9453. document.body.appendChild(dialog);
  9454. var itemSelect = document.getElementById(PRICE_HISTORY_ITEM_SELECT_ID);
  9455. var $itemSelect = win.$(itemSelect);
  9456.  
  9457. function loadScripts(urlList, callback)
  9458. {
  9459. var url = urlList[0];
  9460. if (!url)
  9461. {
  9462. callback && callback();
  9463. return;
  9464. }
  9465. var script = document.createElement('script');
  9466. script.src = url;
  9467. script.onload = function ()
  9468. {
  9469. return loadScripts(urlList.slice(1), callback);
  9470. };
  9471. document.head.appendChild(script);
  9472. }
  9473. var monthArray = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  9474. var lastHistoryItemKey;
  9475. var itemKey2SeriesId = {};
  9476. var chart;
  9477. var stage;
  9478. // add style for select2
  9479. var style = document.createElement('link');
  9480. style.rel = 'stylesheet';
  9481. style.href = 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css';
  9482. document.head.appendChild(style);
  9483. loadScripts([
  9484. 'https://cdn.anychart.com/js/7.14.3/anychart.min.js'
  9485. , 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js'
  9486. ], function ()
  9487. {
  9488. chart = win.anychart.area();
  9489. // pass the container id, chart will be displayed there
  9490. stage = anychart.graphics.create(PRICE_HISTORY_ID);
  9491. chart.container(stage);
  9492. var tooltip = chart.tooltip();
  9493. tooltip.displayMode('union');
  9494. tooltip.format(passThis(function (context)
  9495. {
  9496. var name = context.seriesName || 'Price';
  9497. return name + ': ' + (isNaN(context.value) ? '-' : format.number(context.value));
  9498. }));
  9499. tooltip.titleFormat(passThis(function (context)
  9500. {
  9501. var d = new Date(context.x);
  9502. return monthArray[d.getMonth()] + ' ' + d.getDate() + ' @ ' + zeroPadLeft(d.getHours()) + ':' + zeroPadLeft(d.getMinutes()) + ':' + zeroPadLeft(d.getSeconds());
  9503. }));
  9504. var valueAxis = chart.yAxis();
  9505. valueAxis.title().text('Price').enabled(true);
  9506. valueAxis.labels().format(passThis(function (context)
  9507. {
  9508. return format.number(context.value);
  9509. }));
  9510. var timeAxis = chart.xAxis();
  9511. timeAxis.labels().format(passThis(function (context)
  9512. {
  9513. var d = new Date(context.tickValue);
  9514. return d.getDate() + '. ' + monthArray[d.getMonth()];
  9515. }));
  9516. var timeScale = win.anychart.scales.dateTime();
  9517. var ticks = timeScale.ticks();
  9518. ticks.interval(0, 0, 1);
  9519. chart.xScale(timeScale);
  9520. var timeScroller = chart.xScroller();
  9521. timeScroller.enabled(true);
  9522. chart.animation(true, 300);
  9523. chart.legend(true);
  9524. });
  9525. historyBtn.addEventListener('click', function (event)
  9526. {
  9527. event.preventDefault();
  9528. event.stopPropagation();
  9529. var height = Math.floor(.66 * window.innerHeight);
  9530. var width = Math.min(Math.floor(.66 * window.innerWidth), window.innerWidth - 30);
  9531. win.$(dialog).dialog(
  9532. {
  9533. title: 'Price history from local data'
  9534. , height: height
  9535. , width: width
  9536. });
  9537. dialog.style.height = (height) + 'px';
  9538. var itemKeyList = Object.keys(priceHistory).sort();
  9539. itemSelect.innerHTML = "";
  9540. var category2OptGroup = {};
  9541.  
  9542. function ensureOptGroup(categoryId)
  9543. {
  9544. var optGroup = category2OptGroup[categoryId];
  9545. if (!optGroup)
  9546. {
  9547. optGroup = document.createElement('optgroup');
  9548. optGroup.label = category2Name.get(categoryId) || 'Stuff';
  9549. itemSelect.appendChild(optGroup);
  9550. category2OptGroup[categoryId] = optGroup;
  9551. }
  9552. return optGroup;
  9553. }
  9554. var categoryList = Array.from(category2Name.keys()).map(function (id)
  9555. {
  9556. return Number(id);
  9557. }).sort();
  9558. for (var _i = 0, categoryList_1 = categoryList; _i < categoryList_1.length; _i++)
  9559. {
  9560. var categoryId = categoryList_1[_i];
  9561. ensureOptGroup(categoryId);
  9562. }
  9563. var itemKey2EnabledFn = {};
  9564.  
  9565. function replaceEnabled(itemKey, series)
  9566. {
  9567. var _enabled = series.enabled.bind(series);
  9568. itemKey2EnabledFn[itemKey] = _enabled;
  9569. series.enabled = function (value)
  9570. {
  9571. if (value !== undefined)
  9572. {
  9573. var itemList = $itemSelect.val();
  9574. var index = itemList.indexOf(itemKey);
  9575. if (index !== -1)
  9576. {
  9577. itemList.splice(index, 1);
  9578. }
  9579. else
  9580. {
  9581. itemList.push(itemKey);
  9582. }
  9583. $itemSelect.val(itemList).trigger('change');
  9584. }
  9585. return _enabled(value);
  9586. };
  9587. }
  9588. var min = Number.MAX_SAFE_INTEGER;
  9589. var max = 0;
  9590. var enabledSeriesList = [];
  9591. var _loop_1 = function (itemKey)
  9592. {
  9593. if (!itemColor[itemKey])
  9594. {
  9595. var baseColor = colorGenerator.getRandom(
  9596. {
  9597. format: 'hslArray'
  9598. });
  9599. var borderColor = baseColor.slice(0);
  9600. if (borderColor[2] < 35)
  9601. {
  9602. borderColor[2] += 35;
  9603. }
  9604. else
  9605. {
  9606. borderColor[2] -= 35;
  9607. }
  9608. itemColor[itemKey] = [
  9609. "hsl(" + baseColor[0] + ", " + baseColor[1] + "%, " + baseColor[2] + "%)"
  9610. , "hsl(" + borderColor[0] + ", " + borderColor[1] + "%, " + borderColor[2] + "%)"
  9611. ];
  9612. }
  9613. var history_2 = priceHistory[itemKey];
  9614. var keyList = Object.keys(history_2).sort();
  9615. var data = keyList
  9616. .map(function (n)
  9617. {
  9618. return ([
  9619. Number(n)
  9620. , history_2[n]
  9621. ]);
  9622. });
  9623. min = Math.min(Number(keyList[0]), min);
  9624. max = Math.max(Number(keyList[keyList.length - 1]), max);
  9625. var id = itemKey2SeriesId[itemKey];
  9626. var series = void 0;
  9627. if (id != null)
  9628. {
  9629. series = chart.getSeries(id);
  9630. series.data(data);
  9631. }
  9632. else
  9633. {
  9634. var hoverifyColor = function (hslColor)
  9635. {
  9636. return (
  9637. {
  9638. color: hslColor
  9639. , opacity: .8
  9640. });
  9641. };
  9642. series = chart.area(data);
  9643. itemKey2SeriesId[itemKey] = series.id();
  9644. series.name(key2Name(itemKey));
  9645. var bgColor = itemColor[itemKey][0];
  9646. var strokeColor = itemColor[itemKey][1];
  9647. series.fill(bgColor);
  9648. var bgColorHover = hoverifyColor(bgColor);
  9649. series.selectFill(bgColorHover);
  9650. series.hoverFill(bgColorHover);
  9651. series.stroke(strokeColor, 2);
  9652. var strokeColorHover = hoverifyColor(strokeColor);
  9653. series.hoverStroke(strokeColorHover, 2);
  9654. series.selectStroke(strokeColorHover, 2);
  9655. var markerOptions = {
  9656. fill: strokeColor
  9657. , size: 5
  9658. , type: 'circle'
  9659. };
  9660. series.hoverMarkers(markerOptions);
  9661. series.selectMarkers(markerOptions);
  9662. replaceEnabled(itemKey, series);
  9663. }
  9664. if (lastHistoryItemKey !== historyItemKey)
  9665. {
  9666. if (itemKey === historyItemKey)
  9667. {
  9668. enabledSeriesList.push(series);
  9669. }
  9670. series.enabled(false);
  9671. }
  9672. var categoryId = item2Category.has(itemKey) ? item2Category.get(itemKey) : -1;
  9673. var optGroup = ensureOptGroup(categoryId);
  9674. var option = document.createElement('option');
  9675. option.value = itemKey;
  9676. option.textContent = key2Name(itemKey);
  9677. optGroup.appendChild(option);
  9678. };
  9679. for (var _a = 0, itemKeyList_1 = itemKeyList; _a < itemKeyList_1.length; _a++)
  9680. {
  9681. var itemKey = itemKeyList_1[_a];
  9682. _loop_1(itemKey);
  9683. }
  9684. stage.listenOnce('renderfinish', function ()
  9685. {
  9686. enabledSeriesList.forEach(function (series)
  9687. {
  9688. return series.enabled(true);
  9689. });
  9690. });
  9691. var timeScale = chart.xScale();
  9692. timeScale.minimum(min);
  9693. timeScale.maximum(max);
  9694. var timeZoom = chart.xZoom();
  9695. var threeDaysLong = 3 * 24 * 60 * 60 * 1e3;
  9696. timeZoom.setToValues(Math.max(max - threeDaysLong, min), max);
  9697. // call the chart draw() method to initiate chart display
  9698. chart.draw(true);
  9699. // init item select
  9700. if ($itemSelect.data('select2'))
  9701. {
  9702. $itemSelect.select2('destroy');
  9703. }
  9704. $itemSelect.select2();
  9705.  
  9706. function getEnabledFn(event)
  9707. {
  9708. var data = event.params.data;
  9709. var itemKey = data.id;
  9710. var enabledFn = itemKey2EnabledFn[itemKey];
  9711. if (enabledFn)
  9712. {
  9713. return enabledFn;
  9714. }
  9715. else
  9716. {
  9717. var id = itemKey2SeriesId[itemKey];
  9718. var series = chart.getSeries(id);
  9719. return series.enabled.bind(series);
  9720. }
  9721. }
  9722. $itemSelect.on('select2:select', function (event)
  9723. {
  9724. getEnabledFn(event)(true);
  9725. });
  9726. $itemSelect.on('select2:unselect', function (event)
  9727. {
  9728. getEnabledFn(event)(false);
  9729. // close select menu when it was closed before an element has been removed
  9730. var openBefore = $itemSelect.data('select2').$container.hasClass('select2-container--open');
  9731. setTimeout(function ()
  9732. {
  9733. if (!openBefore && $itemSelect.data('select2').$container.hasClass('select2-container--open'))
  9734. {
  9735. $itemSelect.select2('close');
  9736. }
  9737. });
  9738. });
  9739. lastHistoryItemKey = historyItemKey;
  9740. });
  9741. }
  9742. var categoryList = [-1];
  9743. var itemListPerCategory = new Map();
  9744.  
  9745. function improveOfferList()
  9746. {
  9747. var itemArea = document.getElementById('dialogue-market-items-area');
  9748. if (itemArea)
  9749. {
  9750. var children = itemArea.children;
  9751. for (var i = 1; i < children.length; i++)
  9752. {
  9753. var categoryId = i - 1;
  9754. categoryList.push(categoryId);
  9755. var box = children.item(i);
  9756. var inputs = box.children;
  9757. for (var j = 0; j < inputs.length; j++)
  9758. {
  9759. var match = inputs.item(j).src.match(/images\/([^\/]+)\.(?:png|jpe?g|gif)/);
  9760. if (!match)
  9761. {
  9762. continue;
  9763. }
  9764. var itemKey = match[1];
  9765. item2Category.set(itemKey, categoryId);
  9766. if (categoryAmbassador2CategoryName[itemKey])
  9767. {
  9768. category2Name.set(categoryId, categoryAmbassador2CategoryName[itemKey]);
  9769. }
  9770. if (!itemListPerCategory.has(categoryId))
  9771. {
  9772. itemListPerCategory.set(categoryId, []);
  9773. }
  9774. itemListPerCategory.get(categoryId).push(itemKey);
  9775. }
  9776. }
  9777. }
  9778. }
  9779.  
  9780. function getItemLimit(itemKey)
  9781. {
  9782. // TODO: combine list of offers with min/max-boundries
  9783. var limit = itemLimits.get(itemKey);
  9784. if (limit && limit.timestamp > now() - MAX_LIMIT_AGE)
  9785. {
  9786. return Promise.resolve([limit.min, limit.max]);
  9787. }
  9788. else if (!win.jsTradalbeItems.hasOwnProperty(itemKey))
  9789. {
  9790. return Promise.resolve([0, 0]);
  9791. }
  9792. return new Promise(function (resolve, reject)
  9793. {
  9794. win.postItemDialogue(
  9795. {
  9796. value: 'sell'
  9797. }, itemKey, null);
  9798. if (!item2Resolver.has(itemKey))
  9799. {
  9800. item2Resolver.set(itemKey, []);
  9801. }
  9802. item2Resolver.get(itemKey).push(resolve);
  9803. setTimeout(function ()
  9804. {
  9805. return reject(new Error('Request timed out'));
  9806. }, 30e3);
  9807. });
  9808. }
  9809.  
  9810. function calcMarketValue(items)
  9811. {
  9812. var itemKeyList = Object.keys(items);
  9813. return Promise.all(itemKeyList.map(function (key)
  9814. {
  9815. return getItemLimit(key);
  9816. }))
  9817. .then(function (limitList)
  9818. {
  9819. var sum = [0, 0];
  9820. for (var i = 0; i < itemKeyList.length; i++)
  9821. {
  9822. var amount = items[itemKeyList[i]];
  9823. var limit = limitList[i];
  9824. sum[0] += amount * limit[0];
  9825. sum[1] += amount * limit[1];
  9826. }
  9827. return sum;
  9828. });
  9829. }
  9830. market.calcMarketValue = calcMarketValue;
  9831.  
  9832. function init()
  9833. {
  9834. showOfferCancelCooldown();
  9835. addExtraBtns();
  9836. improveOfferList();
  9837. var _chosenPostItemDialogue = win.chosenPostItemDialogue;
  9838. win.chosenPostItemDialogue = function (itemName, lowerLimit, upperLimit)
  9839. {
  9840. if (processItemLimits(itemName, Number(lowerLimit), Number(upperLimit)))
  9841. {
  9842. _chosenPostItemDialogue(itemName, lowerLimit, upperLimit);
  9843. }
  9844. };
  9845. var _addToPlayerMarket = win.addToPlayerMarket;
  9846. win.addToPlayerMarket = function (data)
  9847. {
  9848. processMarketData(data);
  9849. _addToPlayerMarket(data);
  9850. };
  9851. loadPriceHistory();
  9852. // delay (debounce) sending the request for 3s
  9853. var startDebouncedRequest = debounce(function ()
  9854. {
  9855. return loadPriceHistory();
  9856. }, 3e3);
  9857. settings.observe(settings.KEY.syncPriceHistory, function ()
  9858. {
  9859. return startDebouncedRequest();
  9860. });
  9861. settings.observeSub(settings.KEY.syncPriceHistory, 'url', function ()
  9862. {
  9863. return startDebouncedRequest();
  9864. });
  9865. }
  9866. market.init = init;
  9867. })(market || (market = {}));
  9868.  
  9869. var combat;
  9870. (function (combat)
  9871. {
  9872. combat.name = 'combat';
  9873. var LOOT_TABLE_URL = '/wiki/combat.php';
  9874. var COMBAT_LOOT_TABLES_ID = 'combat-loot-tables';
  9875. var CAT_2_NAME = {
  9876. 'always': 'Always'
  9877. , 'common': 'Common'
  9878. , 'uncommon': 'Uncommon'
  9879. , 'rare': 'Rare'
  9880. , 'veryrare': 'Very Rare'
  9881. };
  9882. var lootInfoInitialized = false;
  9883. var lootInfo = {};
  9884.  
  9885. function readLootTable(table)
  9886. {
  9887. var monsterImg = table.getElementsByTagName('img').item(0);
  9888. var src = monsterImg.getAttribute('src') || '';
  9889. var monsterId = src.replace(/.+npc\/(\d+)\.png$/, '$1');
  9890. var info = {
  9891. always: []
  9892. , common: []
  9893. , uncommon: []
  9894. , rare: []
  9895. , veryrare: []
  9896. };
  9897. for (var i = 2; i < table.rows.length; i++)
  9898. {
  9899. var row = table.rows.item(i);
  9900. var match = row.cells.item(0).innerHTML.match(/images\/(.+)\.png/) || row.cells.item(0).innerHTML.match(/images\/(.+)\.gif/);
  9901. if (!match)
  9902. {
  9903. console.error('no item key found:', row.innerHTML);
  9904. continue;
  9905. }
  9906. var itemKey = match[1];
  9907. var amount = row.cells.item(1).textContent || '';
  9908. var rarityCategory = row.cells.item(2).className;
  9909. var dropRate = (rarityCategory == 'Always') ? 'Always' : row.cells.item(2).textContent;
  9910. if (!info.hasOwnProperty(rarityCategory))
  9911. {
  9912. console.error('unknown rarity category:', rarityCategory);
  9913. continue;
  9914. }
  9915. info[rarityCategory].push(
  9916. {
  9917. key: itemKey
  9918. , amount: amount.split(' - ').map(function (s)
  9919. {
  9920. return Number(s.replace(/\D/g, ''));
  9921. })
  9922. , dropRate: dropRate
  9923. });
  9924. }
  9925. lootInfo[monsterId] = info;
  9926. lootInfoInitialized = true;
  9927. }
  9928.  
  9929. function updateLootTableInfo()
  9930. {
  9931. return doGet(LOOT_TABLE_URL)
  9932. .then(function (response)
  9933. {
  9934. var parser = new DOMParser();
  9935. var doc = parser.parseFromString(response, 'text/html');
  9936. var tables = doc.getElementsByTagName('table');
  9937. for (var i = 0; i < tables.length; i++)
  9938. {
  9939. readLootTable(tables.item(i));
  9940. }
  9941. return lootInfo;
  9942. })
  9943. .then(function (info)
  9944. {
  9945. setLootTableTabContent(info);
  9946. });
  9947. }
  9948.  
  9949. function addLootTableTab()
  9950. {
  9951. var subTabContainer = document.getElementById('tab-sub-container-combat');
  9952. var itemContainer = document.getElementById('tab-sub-container-combat-large-btns');
  9953. var afterEl = itemContainer && itemContainer.previousElementSibling;
  9954. if (!subTabContainer || !afterEl)
  9955. {
  9956. return;
  9957. }
  9958. 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");
  9959. var REFRESH_LOOT_TABLE_ID = 'refresh-loot-table';
  9960. var subTab = document.createElement('span');
  9961. subTab.className = 'large-button';
  9962. subTab.innerHTML = "<img class=\"image-icon-50\" src=\"images/combatDropTable.png\" style=\"filter: grayscale(100%);\">Loot";
  9963. subTab.addEventListener('click', function ()
  9964. {
  9965. var _confirmDialogue = win.confirmDialogue;
  9966. win.confirmDialogue = function () {};
  9967. win.clicksOpenDropTable();
  9968. win.confirmDialogue = _confirmDialogue;
  9969. win.openSubTab('loot');
  9970. });
  9971.  
  9972. function setLootTabVisibility()
  9973. {
  9974. var show = settings.get(settings.KEY.showLootTab);
  9975. subTab.style.display = show ? '' : 'none';
  9976. var dropTableItemBox = document.getElementById('item-box-combatDropTable');
  9977. if (dropTableItemBox)
  9978. {
  9979. dropTableItemBox.style.display = show ? 'none' : '';
  9980. }
  9981. if (show && !lootInfoInitialized)
  9982. {
  9983. updateLootTableInfo();
  9984. }
  9985. }
  9986. setLootTabVisibility();
  9987. settings.observe(settings.KEY.showLootTab, function ()
  9988. {
  9989. return setLootTabVisibility();
  9990. });
  9991. subTabContainer.insertBefore(subTab, afterEl);
  9992. var combatSubTab = document.getElementById('tab-sub-container-combat');
  9993. var equipSubTab = document.getElementById('tab-sub-container-equip');
  9994. var spellsSubTab = document.getElementById('tab-sub-container-spells');
  9995. var subPanelContainer = combatSubTab.parentElement;
  9996. var lootSubTab = document.createElement('div');
  9997. lootSubTab.id = 'tab-sub-container-loot';
  9998. lootSubTab.style.display = 'none';
  9999. 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>";
  10000. subPanelContainer.appendChild(lootSubTab);
  10001. var refreshBtn = document.getElementById(REFRESH_LOOT_TABLE_ID);
  10002. if (refreshBtn)
  10003. {
  10004. refreshBtn.addEventListener('click', function ()
  10005. {
  10006. if (refreshBtn.classList.contains('active'))
  10007. {
  10008. return;
  10009. }
  10010. refreshBtn.classList.add('active');
  10011. updateLootTableInfo()
  10012. .then(function ()
  10013. {
  10014. return refreshBtn.classList.remove('active');
  10015. })
  10016. .catch(function ()
  10017. {
  10018. return refreshBtn.classList.remove('active');
  10019. });
  10020. });
  10021. }
  10022. var _openSubTab = win.openSubTab;
  10023. win.openSubTab = function (tab)
  10024. {
  10025. combatSubTab.style.display = 'none';
  10026. equipSubTab.style.display = 'none';
  10027. spellsSubTab.style.display = 'none';
  10028. lootSubTab.style.display = 'none';
  10029. _openSubTab(tab);
  10030. if (tab == 'loot')
  10031. {
  10032. lootSubTab.style.display = 'block';
  10033. }
  10034. };
  10035. var _loadDefaultCombatTab = win.loadDefaultCombatTab;
  10036. win.loadDefaultCombatTab = function ()
  10037. {
  10038. _loadDefaultCombatTab();
  10039. lootSubTab.style.display = 'none';
  10040. };
  10041. }
  10042.  
  10043. function setLootTableTabContent(lootInfo)
  10044. {
  10045. var combatTableWrapper = document.getElementById(COMBAT_LOOT_TABLES_ID);
  10046. if (!combatTableWrapper)
  10047. {
  10048. return;
  10049. }
  10050. combatTableWrapper.innerHTML = "";
  10051. for (var monsterId in lootInfo)
  10052. {
  10053. var info = lootInfo[monsterId];
  10054. var monsterNum = Number(monsterId);
  10055. if (monsterNum > 1 && monsterNum % 3 === 1)
  10056. {
  10057. var lineBreak = document.createElement('div');
  10058. lineBreak.style.clear = 'both';
  10059. lineBreak.innerHTML = "<br>";
  10060. combatTableWrapper.appendChild(lineBreak);
  10061. }
  10062. var table = document.createElement('table');
  10063. table.className = 'hiscores-table';
  10064. var imgRow = table.insertRow(-1);
  10065. 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>";
  10066. var headerRow = table.insertRow(-1);
  10067. headerRow.innerHTML = "<th>Item</th><th>Amount</th><th>Rarity</th>";
  10068. for (var rarityCategory in info)
  10069. {
  10070. var itemList = info[rarityCategory];
  10071. for (var i = 0; i < itemList.length; i++)
  10072. {
  10073. var item = itemList[i];
  10074. var row = table.insertRow(-1);
  10075. row.innerHTML = "<td><img src=\"../images/" + item.key + ".png\" class=\"image-icon-40\"></td><td>" + item.amount.map(function (n)
  10076. {
  10077. return format.number(n);
  10078. }).join(' - ') + "</td><td class=\"" + rarityCategory + "\">" + item.dropRate + "</td>";
  10079. }
  10080. }
  10081. combatTableWrapper.appendChild(table);
  10082. }
  10083. var images = document.querySelectorAll('.hiscores-table .image-icon-40');
  10084. for (var i=0; i < images.length; i++){
  10085. var enchantSG = images[i];
  10086. var fixURL = enchantSG.src = enchantSG.src.replace('/images/enchantedStargemPotion.png','/images/enchantedStargemPotion.gif');
  10087. }
  10088. }
  10089.  
  10090.  
  10091. function init()
  10092. {
  10093. addLootTableTab();
  10094. if (settings.get(settings.KEY.showLootTab))
  10095. {
  10096. updateLootTableInfo();
  10097. }
  10098. }
  10099. combat.init = init;
  10100. })(combat || (combat = {}));
  10101.  
  10102. /**
  10103. * farming improvements
  10104. */
  10105. var farming;
  10106. (function (farming)
  10107. {
  10108. farming.name = 'farming';
  10109. var SEED_INFO_REGEX = {
  10110. minLevel: />\s*Level:/
  10111. , stopsDyingLevel: />\s*Stops\s+Dying\s+Level:/
  10112. , bonemeal: />\s*Bonemeal:/
  10113. , woodcuttingLevel: />\s*Woodcutting\s+Level:/
  10114. };
  10115. var seedInfoSpans = {};
  10116. var seedInfo = {};
  10117. var checkInfo = {
  10118. bonemeal: function (amount)
  10119. {
  10120. return amount <= win.bonemeal;
  10121. }
  10122. , minLevel: function (level)
  10123. {
  10124. return level <= win.getLevel(win.farmingXp);
  10125. }
  10126. , stopsDyingLevel: function (level)
  10127. {
  10128. return level <= win.getLevel(win.farmingXp);
  10129. }
  10130. , woodcuttingLevel: function (level)
  10131. {
  10132. return level <= win.getLevel(win.woodcuttingXp);
  10133. }
  10134. };
  10135. var RED = 'rgb(204, 0, 0)';
  10136.  
  10137. function addBetterStyle()
  10138. {
  10139. var CLASS_NAME = 'seedHighlight';
  10140. 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");
  10141. // seedHighlight
  10142. function updateHoverStyle()
  10143. {
  10144. document.body.classList[settings.get(settings.KEY.highlightUnplantableSeed) ? 'add' : 'remove'](CLASS_NAME);
  10145. }
  10146. updateHoverStyle();
  10147. settings.observe(settings.KEY.highlightUnplantableSeed, function ()
  10148. {
  10149. return updateHoverStyle();
  10150. });
  10151. }
  10152.  
  10153. function readSeedInfo(seedName, tooltipEl)
  10154. {
  10155. var spans = tooltipEl.querySelectorAll(':scope > span');
  10156. var infoSpans = {
  10157. bonemeal: null
  10158. , minLevel: null
  10159. , stopsDyingLevel: null
  10160. , woodcuttingLevel: null
  10161. };
  10162. var info = {
  10163. bonemeal: 0
  10164. , minLevel: 0
  10165. , stopsDyingLevel: 0
  10166. , woodcuttingLevel: 0
  10167. };
  10168. var i = 0;
  10169. for (var key in SEED_INFO_REGEX)
  10170. {
  10171. if (SEED_INFO_REGEX[key].test(spans[i].innerHTML))
  10172. {
  10173. infoSpans[key] = spans.item(i);
  10174. var textNode = spans.item(i).lastChild;
  10175. info[key] = parseInt(textNode.textContent || '', 10);
  10176. i++;
  10177. }
  10178. }
  10179. seedInfoSpans[seedName] = infoSpans;
  10180. seedInfo[seedName] = info;
  10181. }
  10182.  
  10183. function checkSpan(span, fulfilled)
  10184. {
  10185. span.style.color = fulfilled ? '' : RED;
  10186. span.style.fontWeight = fulfilled ? '' : 'bold';
  10187. }
  10188.  
  10189. function checkSeedInfo(seedName, init)
  10190. {
  10191. if (init === void 0)
  10192. {
  10193. init = false;
  10194. }
  10195. var highlight = settings.get(settings.KEY.highlightUnplantableSeed);
  10196. var info = seedInfo[seedName];
  10197. var spans = seedInfoSpans[seedName];
  10198. var canBePlanted = true;
  10199. for (var key in info)
  10200. {
  10201. var span = spans[key];
  10202. if (span)
  10203. {
  10204. var fulfilled = checkInfo[key](info[key]);
  10205. checkSpan(span, !highlight || fulfilled);
  10206. canBePlanted = !highlight || canBePlanted && (key == 'stopsDyingLevel' || fulfilled);
  10207. }
  10208. }
  10209. var itemBox = document.getElementById('item-box-' + seedName);
  10210. if (itemBox)
  10211. {
  10212. itemBox.style.opacity = (!highlight || canBePlanted) ? '' : '.5';
  10213. }
  10214. var plantInput = document.getElementById('dialogue-plant-' + seedName);
  10215. if (plantInput)
  10216. {
  10217. plantInput.style.backgroundColor = (!highlight || canBePlanted) ? '' : 'hsla(0, 100%, 50%, .5)';
  10218. }
  10219. if (init)
  10220. {
  10221. observer.add('bonemeal', function ()
  10222. {
  10223. return checkSeedInfo(seedName);
  10224. });
  10225. observer.add('farmingXp', function ()
  10226. {
  10227. return checkSeedInfo(seedName);
  10228. });
  10229. observer.add('woodcuttingXp', function ()
  10230. {
  10231. return checkSeedInfo(seedName);
  10232. });
  10233. settings.observe(settings.KEY.highlightUnplantableSeed, function ()
  10234. {
  10235. return checkSeedInfo(seedName);
  10236. });
  10237. }
  10238. }
  10239.  
  10240. function getSeedInfo(seedName)
  10241. {
  10242. return seedInfo[seedName];
  10243. }
  10244. farming.getSeedInfo = getSeedInfo;
  10245.  
  10246. function init()
  10247. {
  10248. addBetterStyle();
  10249. // read all seed information
  10250. var tooltipEls = document.querySelectorAll('div[id^="tooltip-"][id$="Seeds"]');
  10251. for (var i = 0; i < tooltipEls.length; i++)
  10252. {
  10253. var tooltipEl = tooltipEls[i];
  10254. var seedName = tooltipEl.id.replace(/^tooltip-/, '');
  10255. readSeedInfo(seedName, tooltipEl);
  10256. checkSeedInfo(seedName, true);
  10257. }
  10258. }
  10259. farming.init = init;
  10260. })(farming || (farming = {}));
  10261.  
  10262. /**
  10263. * add in-game calculators
  10264. */
  10265. var calc;
  10266. (function (calc)
  10267. {
  10268. var mining = {};
  10269. var crafting = {};
  10270. mining.XPConvert = 'xp-gain-pickaxe-convert';
  10271. mining.dialog = 'dialogue-id-boundPickaxe';
  10272. mining.name = 'mining';
  10273. crafting.XPConvert = 'xp-gain-hammer-convert';
  10274. crafting.dialog = 'dialogue-id-boundHammer';
  10275. crafting.name = 'crafting';
  10276.  
  10277. function doubleCalcs(skill){
  10278. var getXPConvert = document.getElementById(skill.XPConvert).innerHTML;
  10279. getXPConvert = getXPConvert.replace(/\,/g,'');
  10280. getXPConvert = parseInt(getXPConvert, 10);
  10281. var currentXP = getGameValue(skill.name + 'Xp');
  10282. var totalXP = currentXP + getXPConvert;
  10283. var level = getLevel(totalXP);
  10284.  
  10285. $('#'+skill.name+'-level').html(format.number(level));
  10286. $('#'+skill.name+'-xp').html(format.number(totalXP));
  10287. }
  10288. function doubleSkills(skill){
  10289. var getSkillDialog = document.getElementById(skill.dialog);
  10290. var div = document.createElement("div");
  10291. div.className = 'basic-smallbox';
  10292. 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)';
  10293.  
  10294. var smallboxes = getSkillDialog.querySelectorAll('div.basic-smallbox');
  10295. getSkillDialog.insertBefore(div, smallboxes[0]);
  10296. }
  10297.  
  10298.  
  10299. function magic(){
  10300.  
  10301. var getSkillDialog = document.getElementById("dialogue-id-meditate");
  10302. var div = document.createElement("div");
  10303. var div2 = document.createElement("div");
  10304. var title = document.createElement("h1");
  10305. title.className = 'container-title';
  10306. title.innerHTML = "Meditation Calculator";
  10307. var closeButton= '<br/><input type="button" value="Close"/>';
  10308.  
  10309. div2.className = 'basic-smallbox';
  10310. div.className = 'basic-smallbox';
  10311. div2.innerHTML = '<b>Desire level? </b><input type="number" value="1" id="magic-level" size="4" min="1" max="100" style="width: 47px;">';
  10312. div.innerHTML = '<span> \
  10313. <input type="image" width="50px" id="stone" src="images/empoweredStone.png"> \
  10314. <input type="image" width="50px" id="moonstone" src="images/empoweredMoonstone.png"> \
  10315. <input type="image" width="50px" id="marsrock" src="images/empoweredMarsRock.png"> \
  10316. <input type="image" width="50px" id="promethium" src="images/empoweredPromethium.png"> \
  10317. <input type="image" width="50px" id="runite" src="images/empoweredRunite.png"> \
  10318. </span><br /><b>Empowered Rocks needed:</b> \
  10319. <input type="number" value="0" id="input-empowered-amount" size="4" min="0" max="9999" style="width: 67px;"> \
  10320. <br><img src="images/icons/wizardhat.png" class="image-icon-20"> +<span id="xp-gain-meditate-convert"></span> xp \
  10321. <br><span id="stone-display"><img src="images/stone.png" class="image-icon-20"> -<span id="stone-cost-meditate-convert"></span></span> \
  10322. <span id="moonstone-display" style="display: none"> \
  10323. <img src="images/moonstone.png" class="image-icon-20"> -<span id="moonstone-cost-meditate-convert"></span></span></span> \
  10324. <span id="marsrock-display" style="display: none"> \
  10325. <img src="images/marsRock.png" class="image-icon-20"> -<span id="marsrock-cost-meditate-convert"></span></span> \
  10326. <span id="promethium-display" style="display: none"> \
  10327. <img src="images/promethium.png" class="image-icon-20"> -<span id="promethium-cost-meditate-convert"></span></span> \
  10328. <span id="runite-display" style="display: none"><img src="images/runite.png" class="image-icon-20"> -<span id="runite-cost-meditate-convert"></span></span> \
  10329. <br><img src="images/icons/stardust.png" class="image-icon-20"> -<span id="stardust-cost-meditate-convert"></span> \
  10330. <br><img src="images/icons/hourglass.png" class="image-icon-20"> <span id="duration-meditate-convert"></span> hours \
  10331. ';
  10332. $(getSkillDialog).append(title, div2, div, closeButton);
  10333. }
  10334. function magicCalcXP(number, node){
  10335. if (!number){
  10336. return;
  10337. }
  10338. if (!node){
  10339. return;
  10340. }
  10341. var rock;
  10342. var inputLevel = $('#magic-level');
  10343. var inputRock = $('#input-empowered-amount');
  10344.  
  10345. var getRocks = inputRock.val();
  10346. var donorXPBoost = (win.donorXpBoost > win.currentTimeMillis) ? 1.1 : 1;
  10347. var greenRockOrb = (boundGreenEmpoweredRockOrb) ? 0.8 : 1;
  10348. var achvPerk = (achMagicMediumCompleted) ? 0.5 : 1;
  10349. var blueMeditateOrb = (boundBlueMeditationOrb) ? 0.5 : 1;
  10350.  
  10351. var materials = 1;
  10352. if (number === 1){
  10353. rock = 'stone';
  10354. materials = 1000000 * achvPerk;
  10355. }else if (number === 2){
  10356. rock = 'moonstone';
  10357. materials = 100 * achvPerk;
  10358. }else if (number === 3){
  10359. rock = 'marsrock';
  10360. materials = 10 * achvPerk;
  10361. }else if (number === 4){
  10362. rock = 'promethium';
  10363. materials = 30 * achvPerk;
  10364. }else if (number === 5){
  10365. rock = 'runite';
  10366. materials = 1;
  10367. }
  10368. //find meditate level and time
  10369. var meditateTime = 0;
  10370. for (var i = 1; i <= 9; i++){
  10371. if (getGameValue("meditate"+i) === 1){
  10372. meditateTime = 11 - i;
  10373. }
  10374. }
  10375.  
  10376. var gainXP = (getRocks > 9999) ? Number.NaN : getRocks*10000*donorXPBoost;
  10377. var sdCost = (getRocks > 9999) ? Number.NaN : getRocks*100000*greenRockOrb;
  10378. var matCost = (getRocks > 9999) ? Number.NaN : getRocks*materials;
  10379. var duration = (getRocks > 9999) ? Number.NaN : getRocks*meditateTime*blueMeditateOrb;
  10380. gainXP = parseInt(Math.round(gainXP), 10);
  10381. sdCost = parseInt(Math.round(sdCost), 10);
  10382. var totalXP = win.magicXp + gainXP;
  10383. var level = getLevel(totalXP);
  10384.  
  10385. $('#xp-gain-meditate-convert').html(format.number(gainXP));
  10386. $('#stardust-cost-meditate-convert').html(format.number(sdCost));
  10387. $('#'+node.id+'-cost-meditate-convert').html(format.number(matCost));
  10388. $('#duration-meditate-convert').html(format.number(duration));
  10389. inputLevel.val(level);
  10390.  
  10391. if (node.id == rock){
  10392. document.getElementById('stone').style.backgroundColor = '';
  10393. document.getElementById('moonstone').style.backgroundColor = '';
  10394. document.getElementById('marsrock').style.backgroundColor = '';
  10395. document.getElementById('promethium').style.backgroundColor = '';
  10396. document.getElementById('runite').style.backgroundColor = '';
  10397. node.style.backgroundColor = 'red';
  10398. document.getElementById('stone-display').style.display = "none";
  10399. document.getElementById('moonstone-display').style.display = "none";
  10400. document.getElementById('marsrock-display').style.display = "none";
  10401. document.getElementById('promethium-display').style.display = "none";
  10402. document.getElementById('runite-display').style.display = "none";
  10403. document.getElementById(node.id+'-display').style.display = "";
  10404. }
  10405. }
  10406.  
  10407. function magicCalcLevel(number, node){
  10408. if (!number){
  10409. return;
  10410. }
  10411. if (!node){
  10412. return;
  10413. }
  10414.  
  10415. var inputLevel = $('#magic-level');
  10416. var inputRock = $('#input-empowered-amount');
  10417.  
  10418. var desireLevel = inputLevel.val();
  10419. var donorXPBoost = (win.donorXpBoost > win.currentTimeMillis) ? 1.1 : 1;
  10420. var greenRockOrb = (boundGreenEmpoweredRockOrb) ? 0.8 : 1;
  10421. var achvPerk = (achMagicMediumCompleted) ? 0.5 : 1;
  10422. var blueMeditateOrb = (boundBlueMeditationOrb) ? 0.5 : 1;
  10423. var rock;
  10424. var materials = 1;
  10425. if (number === 1){
  10426. rock = 'stone';
  10427. materials = 1000000 * achvPerk;
  10428. }else if (number === 2){
  10429. rock = 'moonstone';
  10430. materials = 100 * achvPerk;
  10431. }else if (number === 3){
  10432. rock = 'marsrock';
  10433. materials = 10 * achvPerk;
  10434. }else if (number === 4){
  10435. rock = 'promethium';
  10436. materials = 30 * achvPerk;
  10437. }else if (number === 5){
  10438. rock = 'runite';
  10439. materials = 1;
  10440. }
  10441. //find meditate level and time
  10442. var meditateTime = 0;
  10443. for (var i = 1; i <= 9; i++){
  10444. if (getGameValue("meditate"+i) === 1){
  10445. meditateTime = 11 - i;
  10446. }
  10447. }
  10448.  
  10449. var desireXP = Math.round(Math.pow(desireLevel, 3 + desireLevel/200));
  10450. var actualXPneed = (desireLevel > 100) ? Number.NaN : (desireXP - win.magicXp);
  10451. var rockneed = Math.round(actualXPneed/(donorXPBoost * 10000));
  10452. var rockneed2 = (rockneed < 1) ? 1 : rockneed;
  10453. var sdneed = (desireLevel > 100) ? Number.NaN : rockneed2*100000*greenRockOrb;
  10454. var matneed = (desireLevel > 100) ? Number.NaN : rockneed2*materials;
  10455. var duration = (desireLevel > 100) ? Number.NaN : rockneed2*meditateTime*blueMeditateOrb;
  10456.  
  10457. inputRock.val(rockneed2);
  10458. $('#xp-gain-meditate-convert').html(format.number(actualXPneed));
  10459. $('#stardust-cost-meditate-convert').html(format.number(sdneed));
  10460. $('#'+node.id+'-cost-meditate-convert').html(format.number(matneed));
  10461. $('#duration-meditate-convert').html(format.number(duration));
  10462.  
  10463. if (node.id == rock){
  10464. document.getElementById('stone').style.backgroundColor = '';
  10465. document.getElementById('moonstone').style.backgroundColor = '';
  10466. document.getElementById('marsrock').style.backgroundColor = '';
  10467. document.getElementById('promethium').style.backgroundColor = '';
  10468. document.getElementById('runite').style.backgroundColor = '';
  10469. node.style.backgroundColor = 'red';
  10470. document.getElementById('stone-display').style.display = "none";
  10471. document.getElementById('moonstone-display').style.display = "none";
  10472. document.getElementById('marsrock-display').style.display = "none";
  10473. document.getElementById('promethium-display').style.display = "none";
  10474. document.getElementById('runite-display').style.display = "none";
  10475. document.getElementById(node.id+'-display').style.display = "";
  10476. }
  10477. }
  10478. function woodcuttingCalc(){
  10479. var treeXP = {0: 0, 1: 1000, 2: 2500, 3: 5000, 4: 10000, 5: 16000, 6: 20000, 7: 1000,
  10480. 8: 2500, 9: 5000, 10: 10000, 11: 16000, 12: 20000, 13: 40000, 14: 40000};
  10481. var getXP = 0;
  10482.  
  10483. for (var i = 1; i <= 6 ;i++){
  10484. getXP += treeXP[getGameValue('treeId'+ i)];
  10485. }
  10486. var donorXPBoost = (win.donorXpBoost > win.currentTimeMillis) ? 1.1 : 1;
  10487. getXP = getXP*donorXPBoost;
  10488. var bonusPerk = (achWoodcuttingMediumCompleted) ? 5 : 0;
  10489. var bonusGem;
  10490.  
  10491. if (emptyAxe){
  10492. bonusGem = 0;
  10493. }else if (boundSapphireAxe){
  10494. bonusGem = 5;
  10495. }else if (boundEmeraldAxe){
  10496. bonusGem = 10;
  10497. }else if (boundRubyAxe){
  10498. bonusGem = 15;
  10499. }else if (boundDiamondAxe){
  10500. bonusGem = 20;
  10501. }
  10502. var bonusLevel = {};
  10503. bonusLevel = {max: 1, average: 1};
  10504. var WCLevel = win.getLevel(win.woodcuttingXp);
  10505. if (WCLevel < 20){
  10506. bonusLevel = {max: 1, average: 1};
  10507. }else if (WCLevel >= 20 && WCLevel < 30){
  10508. bonusLevel = {max: 2, average: 1};
  10509. }else if (WCLevel >= 30 && WCLevel < 40){
  10510. bonusLevel = {max: 3, average: 2};
  10511. }else if (WCLevel >= 40 && WCLevel < 50){
  10512. bonusLevel = {max: 4, average: 2};
  10513. }else if (WCLevel >= 50 && WCLevel < 60){
  10514. bonusLevel = {max: 5, average: 3};
  10515. }else if (WCLevel >= 60 && WCLevel < 70){
  10516. bonusLevel = {max: 6, average: 3};
  10517. }else if (WCLevel >= 70 && WCLevel < 80){
  10518. bonusLevel = {max: 7, average: 4};
  10519. }else if (WCLevel >= 80 && WCLevel < 90){
  10520. bonusLevel = {max: 8, average: 4};
  10521. }else if (WCLevel >= 90 && WCLevel < 100){
  10522. bonusLevel = {max: 9, average: 5};
  10523. }else if (WCLevel == 100){
  10524. bonusLevel = {max: 10, average: 5};
  10525. }
  10526. var totalMin = 15+bonusPerk+bonusGem+1;
  10527. var totalMax = 30+bonusPerk+bonusGem+bonusLevel.max;
  10528. var totalAverage = (totalMin+totalMax)/2;
  10529. $('#wc-xp').html(format.number(getXP));
  10530. $('#wc-logs-perk').html(format.number(bonusPerk));
  10531. $('#wc-logs-gem').html(format.number(bonusGem));
  10532. $('#wc-level-max').html(format.number(bonusLevel.max));
  10533. $('#wc-level-average').html(format.number(bonusLevel.average));
  10534. $('#wc-total-min').html(format.number(totalMin));
  10535. $('#wc-total-max').html(format.number(totalMax));
  10536. $('#wc-total-logs-average').html(format.number(totalAverage));
  10537. }
  10538. function woodcutting(){
  10539. addStyle('div.smallbox-fix-lines \n{\n\tline-height: 1.6;\n}');
  10540. $("#dialogue-axe-chance").parentsUntil("div").css({"display": "none"});
  10541. $("#dialogue-id-axe").find("br:first").remove();
  10542. var getSkillDialog = document.getElementById('dialogue-id-axe');
  10543. var div = document.createElement("div");
  10544. div.className = 'basic-smallbox';
  10545.  
  10546. 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 /> \
  10547. <b>Current total logs per tree: <x id="wc-total-min" style="color: blue"></x> - <x id="wc-total-max" style="color: blue"></x> \
  10548. (<x id="wc-total-logs-average" style="color: blue"></x> on average)</b><br/> \
  10549. Original logs per tree: 15 - 30 (22 on average)<br/> \
  10550. Bonus logs from woodcutting level: random between 1 - <x id="wc-level-max"></x> \
  10551. (<x id="wc-level-average"></x> on average)</b><br/> \
  10552. Bonus logs from gems: <x id="wc-logs-gem"></x><br/> \
  10553. Bonus logs from achievement perk: <x id="wc-logs-perk"></x></div><br/> \
  10554. <table><tr><th>1</th><th>15</th><th>30</th><th>50</th><th>70</th><th>85</th><th>95</th></tr> \
  10555. <tr><td><img src="images/woodcutting/tree4.png" width="65"></td><td><img src="images/woodcutting/oakTree4.png" width="65"></td> \
  10556. <td><img src="images/woodcutting/willowTree4.png" width="65"></td><td><img src="images/woodcutting/mapleTree4.png" width="65"></td> \
  10557. <td><img src="images/woodcutting/stardustTree4.png" width="65"></td><td><img src="images/woodcutting/strangeLeafTree4.png" width="65"></td> \
  10558. <td><img src="images/woodcutting/ancientTree4.png" width="65"></td> \
  10559. <tr><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> \
  10560. </table>';
  10561.  
  10562. getSkillDialog.insertBefore(div, document.getElementById('dialgoue-axe-upgrade-with'));
  10563. }
  10564. function bonemealBinCalc(){
  10565. var stripedCrystalLeafSeeds = ['stripedCrystalLeafSeeds', 100];
  10566. var ancientTreeSeeds = ['ancientTreeSeeds', 100];
  10567. var strangeLeafTreeSeeds = ['strangeLeafTreeSeeds', 65];
  10568. var stardustTreeSeeds = ['stardustTreeSeeds', 50];
  10569. var crystalLeafSeeds = ['crystalLeafSeeds', 50];
  10570. var mapleTreeSeeds = ['mapleTreeSeeds', 30];
  10571. var willowTreeSeeds = ['willowTreeSeeds', 15];
  10572. var goldLeafSeeds = ['goldLeafSeeds', 10];
  10573. var stardustSeeds = ['stardustSeeds', 5];
  10574.  
  10575. var stripedCrystalBM = getGameValue(stripedCrystalLeafSeeds[0]) * stripedCrystalLeafSeeds[1];
  10576. var ancientTreeBM = getGameValue(ancientTreeSeeds[0]) * ancientTreeSeeds[1];
  10577. var strangeLeafTreeBM = getGameValue(strangeLeafTreeSeeds[0]) * strangeLeafTreeSeeds[1];
  10578. var stardustTreeBM = getGameValue(stardustTreeSeeds[0]) * stardustTreeSeeds[1];
  10579. var crystalLeafBM = getGameValue(crystalLeafSeeds[0]) * crystalLeafSeeds[1];
  10580. var mapleTreeBM = getGameValue(mapleTreeSeeds[0]) * mapleTreeSeeds[1];
  10581. var willowTreeBM = getGameValue(willowTreeSeeds[0]) * willowTreeSeeds[1];
  10582. var goldLeafBM = getGameValue(goldLeafSeeds[0]) * goldLeafSeeds[1];
  10583. var stardustBM = getGameValue(stardustSeeds[0]) * stardustSeeds[1];
  10584.  
  10585. var totalBM = stripedCrystalBM+ancientTreeBM+strangeLeafTreeBM+stardustTreeBM +crystalLeafBM +mapleTreeBM +willowTreeBM +goldLeafBM +stardustBM;
  10586. $("#bonemeal-need").text(format.number(totalBM));
  10587. }
  10588. function bonemealBin(){
  10589. $('#bonemeal-bones-input').css('width', "51px");
  10590. var getSkillDialog = document.getElementById('dialogue-bonemeal');
  10591. var div = document.createElement("div");
  10592. div.className = 'basic-smallbox';
  10593. div.innerHTML = '<div class="smallbox-fix-lines"><b>You would need <x id="bonemeal-need" style="color: blue"></x> bonemeal to grow all of your seeds</b><br /> \
  10594. Bone Amulet (Skeleton in Caves) or Bone Ring (Vendor) x2 bones in lootbags<br /> \
  10595. Green Bonemeal Bin Orb +1 bonemeal for every bonemeal item<br /></div> \
  10596. ';
  10597. $(div).insertAfter("#dialogue-bonemeal h2:first");
  10598. $("#dialogue-bonemeal h2:first").css("display", "none");
  10599. var boneSource = " <b>Source: </b><img title='Treasure Chest' src='images/treasureChest.png' class='image-icon-50'> \
  10600. <img title='Chicken' src='images/hero/npc/1.png' class='image-icon-50'> \
  10601. <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'> \
  10602. <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'> \
  10603. <img title='Vendor' src='images/vendor.png' class='image-icon-50'> \
  10604. ";
  10605. var ashesSource = " <b>Source: </b><img title='Green Treasure Chest' src='images/greenTreasureChest.png' class='image-icon-50'> \
  10606. <img title='Golem' src='images/hero/npc/10.png' class='image-icon-50'> \
  10607. <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'> \
  10608. ";
  10609. var iceBonesSource = " <b>Source: </b><img title='Lizard' src='images/hero/npc/13.png' class='image-icon-50'> \
  10610. <img title='Ice Bird' src='images/hero/npc/15.png' class='image-icon-50'> \
  10611. ";
  10612. var moonBonesSource = " <b>Source: </b><img title='Giant' src='images/hero/npc/19.png' class='image-icon-50'> \
  10613. <img title='Five Eyed' src='images/hero/npc/20.png' class='image-icon-50'> \
  10614. ";
  10615. var darkBonesSource = " <b>Source: </b><img title='Dark Mage' src='images/hero/npc/22.png' class='image-icon-50'> \
  10616. <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'> \
  10617. ";
  10618. $("#bonemeal-bones-box").append(boneSource);
  10619. $("#bonemeal-ashes-box").append(ashesSource);
  10620. $("#bonemeal-iceBones-box").append(iceBonesSource);
  10621. $("#bonemeal-moonBones-box").append(moonBonesSource);
  10622. $("#bonemeal-darkBones-box").append(darkBonesSource);
  10623. }
  10624. function brewing(){
  10625. var getSkillDialog = document.getElementById("dialogue-id-brewingkit");
  10626. 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' : '';
  10627. var title = "<h1 class='container-title'>Brewing Calculator</h1>";
  10628. var closeButton= '<br/><input type="button" value="Close"/>';
  10629. var div = `<br/><div class='basic-smallbox' style="line-height: 1.6"><b>You need <span style="color:blue" id="total-current-pot-xp"></span> to drink all \
  10630. of current potions</b> <br/>(click on headers to sort the table)<br/> \
  10631. The <b>Brewable XP</b> column will give you an idea about the priority of which potion<br/> should be brewed<br/> \
  10632. <table class="tablesorter" id="brewing-calc-table" border="1" style="text-align:center"><thead><tr><th>Potion</th><th>Current</th> \
  10633. <th>Brewable</th><th>Total</th><th>Current XP</th><th>Brewable XP</th><th>Total XP</th><th>Current Time</th></tr></thead><tbody> \
  10634. <tr><td><img src='images/stardustPotion.png' class="image-icon-40"></td><td id ="stardust-current"></td><td id ="stardust-brewable"></td> \
  10635. <td id ="stardust-total"></td><td id ="stardust-current-xp"></td><td id ="stardust-brewable-xp"></td><td id ="stardust-total-xp"></td> \
  10636. <td id ="stardust-current-time"></td></tr> \
  10637. <tr><td><img src='images/treePotion.png' class="image-icon-40"></td><td id ="tree-current"></td><td id ="tree-brewable"></td> \
  10638. <td id ="tree-total"></td><td id ="tree-current-xp"></td><td id ="tree-brewable-xp"></td><td id ="tree-total-xp"></td> \
  10639. <td id ="tree-current-time"></td></tr> \
  10640. <tr><td><img src='images/seedPotion.png' class="image-icon-40"></td><td id ="seed-current"></td><td id ="seed-brewable"></td> \
  10641. <td id ="seed-total"></td><td id ="seed-current-xp"></td><td id ="seed-brewable-xp"></td><td id ="seed-total-xp"></td> \
  10642. <td id ="seed-current-time"></td></tr> \
  10643. <tr><td><img src='images/smeltingPotion.png' class="image-icon-40"></td><td id ="smelting-current"></td><td id ="smelting-brewable"></td> \
  10644. <td id ="smelting-total"></td><td id ="smelting-current-xp"></td><td id ="smelting-brewable-xp"></td><td id ="smelting-total-xp"></td> \
  10645. <td id ="smelting-current-time"></td></tr> \
  10646. <tr><td><img src='images/oilPotion.png' class="image-icon-40"></td><td id ="oil-current"></td><td id ="oil-brewable"></td> \
  10647. <td id ="oil-total"></td><td id ="oil-current-xp"></td><td id ="oil-brewable-xp"></td><td id ="oil-total-xp"></td> \
  10648. <td id ="oil-current-time"></td></tr> \
  10649. <tr><td><img src='images/barPotion.png' class="image-icon-40"></td><td id ="bar-current"></td><td id ="bar-brewable"></td> \
  10650. <td id ="bar-total"></td><td id ="bar-current-xp"></td><td id ="bar-brewable-xp"></td><td id ="bar-total-xp"></td> \
  10651. <td id ="bar-current-time"></td></tr> \
  10652. <tr><td><img src='images/superStardustPotion.png' class="image-icon-40"></td><td id ="supersd-current"></td><td id ="supersd-brewable"></td> \
  10653. <td id ="supersd-total"></td><td id ="supersd-current-xp"></td><td id ="supersd-brewable-xp"></td><td id ="supersd-total-xp"></td> \
  10654. <td id ="supersd-current-time"></td></tr> \
  10655. <tr><td><img src='images/combatCooldownPotion.png' class="image-icon-40"></td><td id ="cd-current"></td><td id ="cd-brewable"></td> \
  10656. <td id ="cd-total"></td><td id ="cd-current-xp"></td><td id ="cd-brewable-xp"></td><td id ="cd-total-xp"></td> \
  10657. <td id ="cd-current-time"></td></tr> \
  10658. <tr><td><img src='images/farmingSpeedPotion.png' class="image-icon-40"></td><td id ="farmingspeed-current"></td><td id ="farmingspeed-brewable"></td> \
  10659. <td id ="farmingspeed-total"></td><td id ="farmingspeed-current-xp"></td><td id ="farmingspeed-brewable-xp"></td><td id ="farmingspeed-total-xp"></td> \
  10660. <td id ="farmingspeed-current-time"></td></tr> \
  10661. <tr><td><img src='images/stargemPotion.png' class="image-icon-40"></td><td id ="stargem-current"></td><td id ="stargem-brewable"></td> \
  10662. <td id ="stargem-total"></td><td id ="stargem-current-xp"></td><td id ="stargem-brewable-xp"></td><td id ="stargem-total-xp"></td> \
  10663. <td id ="stargem-current-time"></td></tr> \
  10664. <tr><td><img src='images/manaPotion.png' class="image-icon-40"></td><td id ="mana-current"></td><td id ="mana-brewable"></td> \
  10665. <td id ="mana-total"></td><td id ="mana-current-xp"></td><td id ="mana-brewable-xp"></td><td id ="mana-total-xp"></td> \
  10666. <td id ="mana-current-time"></td></tr> \
  10667. <tr><td><img src='images/superOilPotion.png' class="image-icon-40"></td><td id ="superoil-current"></td><td id ="superoil-brewable"></td> \
  10668. <td id ="superoil-total"></td><td id ="superoil-current-xp"></td><td id ="superoil-brewable-xp"></td><td id ="superoil-total-xp"></td> \
  10669. <td id ="superoil-current-time"></td></tr> \
  10670. <tr><td><img src='images/superTreePotion.png' class="image-icon-40"></td><td id ="supertree-current"></td><td id ="supertree-brewable"></td> \
  10671. <td id ="supertree-total"></td><td id ="supertree-current-xp"></td><td id ="supertree-brewable-xp"></td><td id ="supertree-total-xp"></td> \
  10672. <td id ="supertree-current-time"></td></tr> \
  10673. <tr><td><img src='images/superCombatCooldownPotion.png' class="image-icon-40"></td><td id ="supercombatcd-current"></td><td id ="supercombatcd-brewable"></td> \
  10674. <td id ="supercombatcd-total"></td><td id ="supercombatcd-current-xp"></td><td id ="supercombatcd-brewable-xp"></td><td id ="supercombatcd-total-xp"></td> \
  10675. <td id ="supercombatcd-current-time"></td></tr> \
  10676. <tr><td><img src='images/superCompostPotion.png' class="image-icon-40"></td><td id ="supercompost-current"></td><td id ="supercompost-brewable"></td> \
  10677. <td id ="supercompost-total"></td><td id ="supercompost-current-xp"></td><td id ="supercompost-brewable-xp"></td><td id ="supercompost-total-xp"></td> \
  10678. <td id ="supercompost-current-time"></td></tr> \
  10679. <tr><td><img src='images/superManaPotion.png' class="image-icon-40"></td><td id ="supermana-current"></td><td id ="supermana-brewable"></td> \
  10680. <td id ="supermana-total"></td><td id ="supermana-current-xp"></td><td id ="supermana-brewable-xp"></td><td id ="supermana-total-xp"></td> \
  10681. <td id ="supermana-current-time"></td></tr> \
  10682. <tr><td><img src='images/darkPotion.png' class="image-icon-40"></td><td id ="dark-current"></td><td id ="dark-brewable"></td> \
  10683. <td id ="dark-total"></td><td id ="dark-current-xp"></td><td id ="dark-brewable-xp"></td><td id ="dark-total-xp"></td> \
  10684. <td id ="dark-current-time"></td></tr> \
  10685. <tr><td><img src='images/oxygenPotion.png' class="image-icon-40"></td><td id ="oxygen-current"></td><td id ="oxygen-brewable"></td> \
  10686. <td id ="oxygen-total"></td><td id ="oxygen-current-xp"></td><td id ="oxygen-brewable-xp"></td><td id ="oxygen-total-xp"></td> \
  10687. <td id ="oxygen-current-time"></td></tr> \
  10688. <tr><td><img src='images/criticalStrikePotion.png' class="image-icon-40"></td><td id ="crit-current"></td><td id ="crit-brewable"></td> \
  10689. <td id ="crit-total"></td><td id ="crit-current-xp"></td><td id ="crit-brewable-xp"></td><td id ="crit-total-xp"></td> \
  10690. <td id ="crit-current-time"></td></tr> \
  10691. <tr><td><img src='images/lootBagPotion.png' class="image-icon-40"></td><td id ="lootbag-current"></td><td id ="lootbag-brewable"></td> \
  10692. <td id ="lootbag-total"></td><td id ="lootbag-current-xp"></td><td id ="lootbag-brewable-xp"></td><td id ="lootbag-total-xp"></td> \
  10693. <td id ="lootbag-current-time"></td></tr> \
  10694. </tbody></table></div>`;
  10695. $(getSkillDialog).append(title);
  10696. $(getSkillDialog).append(note);
  10697. $(getSkillDialog).append(div);
  10698. $(getSkillDialog).append(closeButton);
  10699. }
  10700. function findMinPot(ingre1, ratio1, ingre2, ratio2, ingre3, ratio3, ingre4, ratio4, ingre5, ratio5){
  10701.  
  10702. var first = isNaN(ingre1/ratio1)? Infinity : ingre1/ratio1;
  10703. var second = isNaN(ingre2/ratio2)? Infinity : ingre2/ratio2;
  10704. var third = isNaN(ingre3/ratio3)? Infinity : ingre3/ratio3;
  10705. var fourth = isNaN(ingre4/ratio4)? Infinity : ingre4/ratio4;
  10706. var fifth = isNaN(ingre5/ratio5)? Infinity : ingre5/ratio5;
  10707. var getMin = Math.min(first, second, third, fourth, fifth);
  10708. getMin = Math.floor(getMin);
  10709. return getMin;
  10710. }
  10711. function formatRound(value){
  10712. return format.number(Math.floor(value));
  10713.  
  10714. }
  10715. function fullTime(time)
  10716. {
  10717. if (typeof time === 'string')
  10718. {
  10719. time = parseInt(time, 10);
  10720. }
  10721. time = Math.max(time, 0);
  10722. var hours = Math.floor((time / 3600));
  10723. var minutes = Math.floor((time % 3600) / 60);
  10724. var seconds = time % 60;
  10725. return (zeroPadLeft(hours) + ':' + zeroPadLeft(minutes) + ':' + zeroPadLeft(seconds));
  10726. }
  10727. function brewingCalc(){
  10728.  
  10729. var donorXPBoost = (win.donorXpBoost > win.currentTimeMillis) ? 1.1 : 1;
  10730. var bonusDuration = 1;
  10731. var bonusAch = 0;
  10732. var bonusLevel = 0;
  10733. var brewingLevel = win.getLevel(win.brewingXp);
  10734. if (achBrewingHardCompleted){
  10735. bonusAch = 15;
  10736. }else if (achBrewingMediumCompleted){
  10737. bonusAch = 10;
  10738. }else if (achBrewingEasyCompleted){
  10739. bonusAch = 5;
  10740. }else{
  10741. bonusAch = 0;
  10742. }
  10743. for(let i = 0; i <= 100; i += 5){
  10744. if (brewingLevel >= i && brewingLevel < (i+5)){
  10745. bonusLevel = i/5;
  10746. }
  10747. }
  10748. bonusDuration = bonusDuration * (1 + (bonusAch+bonusLevel)/100);
  10749.  
  10750. var sdBrewable = findMinPot(dottedGreenLeaf, 1, redMushroom, 25);
  10751. var treeBrewable = findMinPot(dottedGreenLeaf, 2, redMushroom, 15);
  10752. var seedBrewable = findMinPot(dottedGreenLeaf, 1, redMushroom, 30);
  10753. var smeltingBrewable = findMinPot(dottedGreenLeaf, 3);
  10754. var oilBrewable = findMinPot(greenLeaf, 1, redMushroom, 50);
  10755. var barBrewable = findMinPot(greenLeaf, 3, blewitMushroom, 50);
  10756. var supersdBrewable = findMinPot(limeLeaf, 5, snapegrass, 50);
  10757. var cdBrewable = findMinPot(strangeBlueLeaf, 1, greenLeaf, 5);
  10758. var farmingspeedBrewable = findMinPot(redMushroom, 100, blewitMushroom, 50, snapegrass, 10);
  10759. var stargemBrewable = findMinPot(goldLeaf, 1, blewitMushroom, 100);
  10760. var manaBrewable = findMinPot(goldLeaf, 1, limeLeaf, 10, strangePurpleLeaf, 1);
  10761. var superoilBrewable = findMinPot(goldLeaf, 3, redMushroom, 150);
  10762. var supertreeBrewable = findMinPot(goldLeaf, 3, blewitMushroom, 50);
  10763. var supercombatcdBrewable = findMinPot(strangeBlueLeaf, 4, greenLeaf, 20);
  10764. var supercompostBrewable = findMinPot(crystalLeaf, 5, redMushroom, 200, blewitMushroom, 100, snapegrass, 50);
  10765. var supermanaBrewable = findMinPot(crystalLeaf, 5, limeLeaf, 25, strangePurpleLeaf, 5);
  10766. var darkBrewable = findMinPot(limeLeaf, 25, goldLeaf, 10, darkMushroomLair, 10);
  10767. var oxygenBrewable = findMinPot(greenLeaf, 100, limeLeaf, 50, goldLeaf, 20, crystalLeaf, 10, strangePinkLeaf, 1);
  10768. var critBrewable = findMinPot(crystalLeaf, 10, stripedCrystalLeaf, 1, strangeBlueLeaf, 5);
  10769. var lootbagBrewable = findMinPot(crystalLeaf, 10, stripedCrystalLeaf, 2, goldLeaf, 15, strangePurpleLeaf, 1);
  10770.  
  10771. var stardust = {"current" : win.stardustPotion, "brewable" : sdBrewable, "xp": 50, "time": 5};
  10772. var tree = {"current" : win.treePotion, "brewable" : treeBrewable, "xp": 70, "time": 10};
  10773. var seed = {"current" : win.seedPotion, "brewable" : seedBrewable, "xp": 75, "time": 30};
  10774. var smelting = {"current" : win.smeltingPotion, "brewable" : smeltingBrewable, "xp": 200, "time": 30};
  10775. var oil = {"current" : win.oilPotion, "brewable" : oilBrewable, "xp": 210, "time": 15};
  10776. var bar = {"current" : win.barPotion, "brewable" : barBrewable, "xp": 380, "time": 30};
  10777. var supersd = {"current" : win.superStardustPotion, "brewable" : supersdBrewable, "xp": 480, "time": 5};
  10778. var cd = {"current" : win.combatCooldownPotion, "brewable" : cdBrewable, "xp": 555, "time": 0};
  10779. var farmingspeed = {"current" : win.farmingSpeedPotion, "brewable" : farmingspeedBrewable, "xp": 900, "time": 30};
  10780. var stargem = {"current" : win.stargemPotion, "brewable" : stargemBrewable, "xp": 1000, "time": 0};
  10781. var mana = {"current" : win.manaPotion, "brewable" : manaBrewable, "xp": 1250, "time": 1};
  10782. var superoil = {"current" : win.superOilPotion, "brewable" : superoilBrewable, "xp": 2200, "time": 15};
  10783. var supertree = {"current" : win.superTreePotion, "brewable" : supertreeBrewable, "xp": 2350, "time": 30};
  10784. var supercombatcd = {"current" : win.superCombatCooldownPotion, "brewable" : supercombatcdBrewable, "xp": 2550, "time": 0};
  10785. var supercompost = {"current" : win.superCompostPotion, "brewable" : supercompostBrewable, "xp": 4550, "time": 0};
  10786. var supermana = {"current" : win.superManaPotion, "brewable" : supermanaBrewable, "xp": 5000, "time": 1};
  10787. var dark = {"current" : win.darkPotion, "brewable" : darkBrewable, "xp": 6000, "time": 1440};
  10788. var oxygen = {"current" : win.oxygenPotion, "brewable" : oxygenBrewable, "xp": 6650, "time": 0};
  10789. var crit = {"current" : win.criticalStrikePotion, "brewable" : critBrewable, "xp": 7000, "time": 1};
  10790. var lootbag = {"current" : win.lootBagPotion, "brewable" : lootbagBrewable, "xp": 15000, "time": 0};
  10791.  
  10792. var allPots = ['stardust', 'tree', 'seed', 'smelting', 'oil', 'bar','supersd', 'cd', 'farmingspeed', 'stargem', 'mana', 'superoil',
  10793. 'supertree', 'supercombatcd', 'supercompost', 'supermana', 'dark', 'oxygen', 'crit', 'lootbag'];
  10794.  
  10795. var totalTime = 0;
  10796.  
  10797. for (let i = 0; i < allPots.length; i++){
  10798. totalTime += eval(allPots[i]).current * Math.floor(eval(allPots[i]).time * 60 * bonusDuration);
  10799.  
  10800. $('#'+allPots[i]+'-current').html(formatRound(eval(allPots[i]).current));
  10801. $('#'+allPots[i]+'-brewable').html(formatRound(eval(allPots[i]).brewable));
  10802. $('#'+allPots[i]+'-total').html(formatRound(eval(allPots[i]).current + eval(allPots[i]).brewable));
  10803. $('#'+allPots[i]+'-current-xp').html(formatRound(eval(allPots[i]).current * eval(allPots[i]).xp * donorXPBoost));
  10804. $('#'+allPots[i]+'-brewable-xp').html(formatRound(eval(allPots[i]).brewable * eval(allPots[i]).xp * 2* donorXPBoost));
  10805. $('#'+allPots[i]+'-total-xp').html(formatRound(eval(allPots[i]).current * eval(allPots[i]).xp* donorXPBoost +
  10806. eval(allPots[i]).brewable * eval(allPots[i]).xp * 2* donorXPBoost));
  10807. $('#'+allPots[i]+'-current-time').html(fullTime(eval(allPots[i]).current * Math.floor(eval(allPots[i]).time * 60 * bonusDuration)));
  10808. }
  10809. $('#total-current-pot-xp').html(format.timer(totalTime));
  10810.  
  10811. }
  10812. function initBrewingCalc(){
  10813.  
  10814. var brewingKit = $("#item-box-boundBrewingKit");
  10815. if(!boundBrewingKit){
  10816. brewingKit.css("display", "inline-block");
  10817. }
  10818. var dialog = document.createElement('dialog');
  10819. dialog.id = 'dialogue-id-brewingkit';
  10820. document.body.appendChild(dialog);
  10821.  
  10822. brewingKit.click(function(){
  10823. $(dialog).dialog(
  10824. {
  10825. title: 'Brewing Kit',
  10826. height: 'auto',
  10827. width: 'auto'
  10828.  
  10829. });
  10830. brewingCalc();
  10831. $("#brewing-calc-table").tablesorter({
  10832. headers: {
  10833. 1: {sorter:'sortComma'},
  10834. 2: {sorter:'sortComma'},
  10835. 3: {sorter:'sortComma'},
  10836. 4: {sorter:'sortComma'},
  10837. 5: {sorter:'sortComma'},
  10838. 6: {sorter:'sortComma'},
  10839. 7: {sorter:'time'}
  10840. }
  10841. });
  10842. });
  10843. brewing();
  10844. $("#dialogue-id-brewingkit :button").click(function(){
  10845. $(this).closest(".ui-dialog-content").dialog("close");
  10846. });
  10847. $.tablesorter.addParser({
  10848. id: "sortComma",
  10849. is: function(s) {
  10850. return /^[0-9]?[0-9,\.]*$/.test(s);
  10851. },
  10852. format: function(s) {
  10853. return jQuery.tablesorter.formatFloat( s.replace(/,/g,'') );
  10854. },
  10855. type: "numeric"
  10856. });
  10857. $.tablesorter.addParser({
  10858. id:"customTime",
  10859. is:function(s){
  10860. return/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);
  10861. },
  10862. format:function(s){
  10863. return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime());
  10864. },
  10865. type:"numeric"
  10866. });
  10867. }
  10868. function initBonemealBinCalc(){
  10869. bonemealBin();
  10870. var _clicksBonemealBin = win.clicksBonemealBin;
  10871. win.clicksBonemealBin = function()
  10872. {
  10873. _clicksBonemealBin();
  10874. bonemealBinCalc();
  10875. };
  10876. }
  10877. function initMagicCalc()
  10878. {
  10879.  
  10880. var dialog = document.createElement('dialog');
  10881. dialog.id = 'dialogue-id-meditate';
  10882. document.body.appendChild(dialog);
  10883.  
  10884. var _clicksMeditate = win.clicksMeditate;
  10885. win.clicksMeditate = function()
  10886. {
  10887. //openDialogue('dialogue-id-1');
  10888. var height = 430;
  10889. var width = 370;
  10890. $(dialog).dialog(
  10891. {
  10892. title: 'Magic Meditation',
  10893. height: height,
  10894. width: width
  10895. });
  10896. };
  10897. magic();
  10898. $("#stone").click(function(){
  10899. magicCalcXP(1, this);
  10900. });
  10901. $("#moonstone").click(function(){
  10902. magicCalcXP(2, this);
  10903. });
  10904. $("#marsrock").click(function(){
  10905. magicCalcXP(3, this);
  10906. });
  10907. $("#promethium").click(function(){
  10908. magicCalcXP(4, this);
  10909. });
  10910. $("#runite").click(function(){
  10911. magicCalcXP(5, this);
  10912. });
  10913. $("#dialogue-id-meditate :button").click(function(){
  10914. $(this).closest(".ui-dialog-content").dialog("close");
  10915. });
  10916.  
  10917. function checkRock(){
  10918. var rock = [];
  10919. var getstone = document.getElementById('stone');
  10920. var getmoonstone = document.getElementById('moonstone');
  10921. var getmarsrock = document.getElementById('marsrock');
  10922. var getpromethium = document.getElementById('promethium');
  10923. var getrunite = document.getElementById('runite');
  10924.  
  10925. if (getstone.style.backgroundColor == 'red'){
  10926. rock[0] = 1;
  10927. rock[1] = getstone;
  10928. }else if (getmoonstone.style.backgroundColor == 'red'){
  10929. rock[0] = 2;
  10930. rock[1] = getmoonstone;
  10931. }else if (getmarsrock.style.backgroundColor == 'red'){
  10932. rock[0] = 3;
  10933. rock[1] = getmarsrock;
  10934. }else if (getpromethium.style.backgroundColor == 'red'){
  10935. rock[0] = 4;
  10936. rock[1] = getpromethium;
  10937. }else if (getrunite.style.backgroundColor == 'red'){
  10938. rock[0] = 5;
  10939. rock[1] = getrunite;
  10940. }
  10941. return rock;
  10942. }
  10943.  
  10944. document.getElementById("magic-level").addEventListener("keyup", function(){
  10945. magicCalcLevel(checkRock()[0], checkRock()[1]);
  10946. });
  10947. document.getElementById("magic-level").addEventListener("mouseup", function(){
  10948.  
  10949. magicCalcLevel(checkRock()[0], checkRock()[1]);
  10950. });
  10951.  
  10952. document.getElementById("input-empowered-amount").addEventListener("keyup", function(){
  10953. magicCalcXP(checkRock()[0], checkRock()[1]);
  10954. });
  10955. document.getElementById("input-empowered-amount").addEventListener("mouseup", function(){
  10956.  
  10957. magicCalcXP(checkRock()[0], checkRock()[1]);
  10958. });
  10959.  
  10960. }
  10961.  
  10962. function initWoodcuttingCalc(){
  10963. woodcutting();
  10964. var _clicksAxe = win.clicksAxe;
  10965. win.clicksAxe = function()
  10966. {
  10967. _clicksAxe();
  10968. woodcuttingCalc();
  10969. };
  10970. }
  10971.  
  10972. function initMiningCalc()
  10973. {
  10974. doubleSkills(mining);
  10975. document.getElementById("xp-gain-pickaxe-convert").addEventListener("DOMSubtreeModified", function(){
  10976. doubleCalcs(mining);
  10977. });
  10978. }
  10979.  
  10980. function initCraftingCalc()
  10981. {
  10982. doubleSkills(crafting);
  10983. document.getElementById("xp-gain-hammer-convert").addEventListener("DOMSubtreeModified", function(){
  10984. doubleCalcs(crafting);
  10985. });
  10986. }
  10987. function init(){
  10988. initMiningCalc();
  10989. initCraftingCalc();
  10990. initMagicCalc();
  10991. initWoodcuttingCalc();
  10992. initBonemealBinCalc();
  10993. initBrewingCalc();
  10994. }
  10995. calc.init = init;
  10996.  
  10997. })(calc || (calc = {}));
  10998.  
  10999. /**
  11000. * general features which doesn't really belong anywhere
  11001. */
  11002. var general;
  11003. (function (general)
  11004. {
  11005. general.name = 'general';
  11006. // disable the drink button for 3 seconds
  11007. var DRINK_DELAY = 3;
  11008.  
  11009. function getSentBoat()
  11010. {
  11011. for (var i = 0; i < BOAT_LIST.length; i++)
  11012. {
  11013. if (getGameValue(BOAT_LIST[i] + 'Timer') > 0)
  11014. {
  11015. return BOAT_LIST[i];
  11016. }
  11017. }
  11018. return null;
  11019. }
  11020.  
  11021. function checkBoat(boat)
  11022. {
  11023. var boatDialog = null;
  11024. var sendBtn = null;
  11025. var initiatedDialogs = document.querySelectorAll('div[role="dialog"]');
  11026. for (var i = 0; i < initiatedDialogs.length; i++)
  11027. {
  11028. var dialog = initiatedDialogs[i];
  11029. if (dialog.style.display !== 'none')
  11030. {
  11031. var btn = dialog.querySelector('input[type="button"][value="Send Boat"]');
  11032. if (btn)
  11033. {
  11034. sendBtn = btn;
  11035. boatDialog = dialog;
  11036. break;
  11037. }
  11038. }
  11039. }
  11040. if (!boatDialog || !sendBtn)
  11041. {
  11042. return;
  11043. }
  11044. var smallboxes = boatDialog.querySelectorAll('div.basic-smallbox');
  11045. var baitBox = smallboxes[0];
  11046. var runningBox = smallboxes[1];
  11047. if (smallboxes.length === 1)
  11048. {
  11049. runningBox = document.createElement('div');
  11050. runningBox.className = 'basic-smallbox';
  11051. runningBox.style.display = 'none';
  11052. var parent_1 = baitBox.parentElement;
  11053. var next = baitBox.nextElementSibling;
  11054. if (parent_1)
  11055. {
  11056. if (next)
  11057. {
  11058. parent_1.insertBefore(runningBox, next);
  11059. }
  11060. else
  11061. {
  11062. parent_1.appendChild(runningBox);
  11063. }
  11064. }
  11065. }
  11066. var sentBoat = getSentBoat();
  11067. baitBox.style.display = sentBoat !== null ? 'none' : '';
  11068. runningBox.style.display = sentBoat !== null ? '' : 'none';
  11069. // just in case Smitty changes this game mechanic somehow, don't disable the button:
  11070. // sendBtn.disabled = sentBoat !== null;
  11071.  
  11072. sendBtn.style.color = sentBoat !== null ? 'gray' : '';
  11073. win.$(boatDialog).on('dialogclose', function ()
  11074. {
  11075. if (sendBtn)
  11076. {
  11077. sendBtn.style.color = '';
  11078. }
  11079. });
  11080. if (sentBoat === boat)
  11081. {
  11082. runningBox.innerHTML = "<b>Returning in:</b> <span data-item-display=\"" + boat + "Timer\">" + format.timer(getGameValue(boat + 'Timer')) + "</span>";
  11083. }
  11084.  
  11085. else if (sentBoat !== null)
  11086. {
  11087. runningBox.innerHTML = "Wait for the other boat to return.";
  11088. }
  11089.  
  11090. else
  11091. {
  11092. var enoughBaitAndCoal = win.fishingBait >= win.fishingBaitCost(boat)
  11093. && (boat !== 'steamBoat' || win.charcoal >= 300);
  11094. baitBox.style.color = enoughBaitAndCoal ? '' : 'red';
  11095. }
  11096.  
  11097. }
  11098.  
  11099. function initBoatDialog()
  11100. {
  11101. var _clicksBoat = win.clicksBoat;
  11102. win.clicksBoat = function (boat)
  11103. {
  11104. _clicksBoat(boat);
  11105. checkBoat(boat);
  11106. };
  11107. var _doCommand = win.doCommand;
  11108. win.doCommand = function (data)
  11109. {
  11110. _doCommand(data);
  11111. if (data.startsWith('RUN_FUNC=SAIL_BOAT_WIND'))
  11112. {
  11113. checkBoat('sailBoat');
  11114. }
  11115. };
  11116. }
  11117. var potionDrinkEnable = null;
  11118. var POTION_ACTIVE_HTML = "<br>It's already active.";
  11119. function updateDialogEls(timerKey, dialog, close)
  11120. {
  11121. if (close === void 0)
  11122. {
  11123. close = false;
  11124. }
  11125. var timer = getGameValue(timerKey);
  11126. var showActive = settings.get(settings.KEY.usePotionWarning) && timer > 0 && !close;
  11127. var confirmText = document.getElementById('dialogue-confirm-text');
  11128. var br = confirmText && confirmText.nextElementSibling;
  11129. if (confirmText && br)
  11130. {
  11131. if (showActive)
  11132. {
  11133. confirmText.innerHTML += POTION_ACTIVE_HTML;
  11134. }
  11135. else
  11136. {
  11137. confirmText.innerHTML = confirmText.innerHTML.replace(POTION_ACTIVE_HTML, '');
  11138. }
  11139. br.style.display = showActive ? 'none' : '';
  11140. }
  11141. var confirmBtn = document.getElementById('dialogue-confirm-yes');
  11142. if (confirmBtn && showActive)
  11143. {
  11144. confirmBtn.disabled = true;
  11145. var i_1 = DRINK_DELAY;
  11146. var updateValue_1 = function ()
  11147. {
  11148. confirmBtn.value = 'Drink' + (i_1 > 0 ? ' (' + i_1 + ')' : '');
  11149. if (i_1 === 0)
  11150. {
  11151. potionDrinkEnable && potionDrinkEnable();
  11152. }
  11153. else
  11154. {
  11155. i_1--;
  11156. }
  11157. };
  11158. var countDownInterval_1;
  11159. var dialogClose_1 = function ()
  11160. {
  11161. return potionDrinkEnable && potionDrinkEnable();
  11162. };
  11163. potionDrinkEnable = function ()
  11164. {
  11165. potionDrinkEnable = null;
  11166. win.$(dialog).off('dialogclose', dialogClose_1);
  11167. countDownInterval_1 && clearInterval(countDownInterval_1);
  11168. confirmBtn.disabled = false;
  11169. confirmBtn.value = 'Drink';
  11170. };
  11171. updateValue_1();
  11172. countDownInterval_1 = setInterval(function ()
  11173. {
  11174. return updateValue_1();
  11175. }, 1e3);
  11176. win.$(dialog).on('dialogclose', dialogClose_1);
  11177. }
  11178. else if (!showActive)
  11179. {
  11180. potionDrinkEnable && potionDrinkEnable();
  11181. }
  11182. }
  11183.  
  11184. function checkPotionActive(potion)
  11185. {
  11186. var dialog = document.getElementById('dialogue-confirm');
  11187. var parent = dialog && dialog.parentElement;
  11188. if (!dialog || !parent || parent.style.display === 'none')
  11189. {
  11190. return;
  11191. }
  11192. var timerKey = potion + 'Timer';
  11193. updateDialogEls(timerKey, dialog);
  11194. var fn = observer.add(timerKey, function (key, oldValue, newValue)
  11195. {
  11196. if (oldValue < newValue && oldValue === 0
  11197. || oldValue > newValue && newValue === 0)
  11198. {
  11199. updateDialogEls(timerKey, dialog);
  11200. }
  11201. });
  11202. win.$(dialog).on('dialogclose', function ()
  11203. {
  11204. updateDialogEls(timerKey, dialog, true);
  11205. observer.remove(timerKey, fn);
  11206. });
  11207. }
  11208.  
  11209. function initPotionDialog()
  11210. {
  11211. var _confirmDialogue = win.confirmDialogue;
  11212. win.confirmDialogue = function (width, text, btn1Text, btn2Text, cmd)
  11213. {
  11214. potionDrinkEnable && potionDrinkEnable();
  11215. _confirmDialogue(width, text, btn1Text, btn2Text, cmd);
  11216. };
  11217. var _clicksPotion = win.clicksPotion;
  11218. win.clicksPotion = function (potion)
  11219. {
  11220. _clicksPotion(potion);
  11221. checkPotionActive(potion);
  11222. };
  11223. }
  11224. function init()
  11225. {
  11226. //initBoatDialog();
  11227. initPotionDialog();
  11228. }
  11229. general.init = init;
  11230. })(general || (general = {}));
  11231.  
  11232. /**
  11233. * init
  11234. */
  11235. var scriptInitialized = false;
  11236.  
  11237. function init()
  11238. {
  11239. console.info('[%s] "DH2 Fixed %s" up and running.', (new Date).toLocaleTimeString(), version);
  11240.  
  11241. scriptInitialized = true;
  11242. var initModules = [
  11243. settings
  11244. , notifications
  11245. , log
  11246. , gameEvents
  11247. , temporaryFixes
  11248. , crafting
  11249. , itemBoxes
  11250. , chat
  11251. , timer
  11252. , smelting
  11253. , fishingInfo
  11254. //, recipeTooltips
  11255. //, fixNumbers
  11256. , machineDialog
  11257. , amountInputs
  11258. , newTopbar
  11259. , styleTweaks
  11260. , notifBoxes
  11261. , market
  11262. , combat
  11263. , farming
  11264. , general
  11265. , calc
  11266. ];
  11267. for (var _i = 0, initModules_1 = initModules; _i < initModules_1.length; _i++)
  11268. {
  11269. var module = initModules_1[_i];
  11270. try
  11271. {
  11272. module.init();
  11273. }
  11274. catch (error)
  11275. {
  11276. console.error('Error during initialization in module "' + module.name + '":', error);
  11277. }
  11278. }
  11279. }
  11280. document.addEventListener('DOMContentLoaded', function ()
  11281. {
  11282. var oldValues = new Map();
  11283. var _doCommand = win.doCommand;
  11284. win.doCommand = function (data)
  11285. {
  11286. if (data.startsWith('REFRESH_ITEMS='))
  11287. {
  11288. oldValues = new Map();
  11289. for (var _i = 0, _a = win.jsItemArray; _i < _a.length; _i++)
  11290. {
  11291. var key = _a[_i];
  11292. oldValues.set(key, getGameValue(key));
  11293. }
  11294. _doCommand(data);
  11295. if (!scriptInitialized)
  11296. {
  11297. init();
  11298. }
  11299. return;
  11300. }
  11301. else if (!scriptInitialized)
  11302. {
  11303. if (data.startsWith('CHAT='))
  11304. {
  11305. var parts = data.substr(5).split('~');
  11306. return chat.newAddToChatBox(parts[0], parts[1], parts[2], parts[3], 0);
  11307. }
  11308. else if (data.startsWith('PM='))
  11309. {
  11310. return chat.newAddToChatBox(win.username, '0', '0', data.substr(3), 1);
  11311. }
  11312. }
  11313. var ret = commands.process(data);
  11314. if (ret === void 0)
  11315. {
  11316. ret = _doCommand(commands.formatData(data));
  11317. }
  11318. return ret;
  11319. };
  11320. var _refreshItemValues = win.refreshItemValues;
  11321. win.refreshItemValues = function (itemKeyList, firstLoad)
  11322. {
  11323. _refreshItemValues(itemKeyList, firstLoad);
  11324. for (var _i = 0, itemKeyList_2 = itemKeyList; _i < itemKeyList_2.length; _i++)
  11325. {
  11326. var key = itemKeyList_2[_i];
  11327. observer.notify(key, oldValues.get(key));
  11328. }
  11329. observer.notifyTick();
  11330. };
  11331. });
  11332.  
  11333. /**
  11334. * fix web socket errors
  11335. */
  11336. var main;
  11337. (function (main)
  11338. {
  11339. var WS_TIMEOUT_SEC = 30;
  11340. var WS_TIMEOUT_CODE = 3000;
  11341. var WS_OPEN_TIMEOUT_SEC = 2 * 60; // 2 minutes
  11342. // reload the page after 5 consecutive reconnect attempts without successfully opening the websocket once
  11343. var MAX_RECONNECTS = 5;
  11344.  
  11345. function webSocketLoaded(event)
  11346. {
  11347. if (win.webSocket == null)
  11348. {
  11349. //console.error('WebSocket instance not initialized!');
  11350. return;
  11351. }
  11352. // cache old event listener
  11353. var _onClose = win.webSocket.onclose;
  11354. var _onError = win.webSocket.onerror;
  11355. var _onMessage = win.webSocket.onmessage;
  11356. var _onOpen = win.webSocket.onopen;
  11357. var commandQueue = [];
  11358. var _cBytes = win.cBytes;
  11359. win.cBytes = function (command)
  11360. {
  11361. if (win.webSocket && win.webSocket.readyState === WebSocket.OPEN)
  11362. {
  11363. _cBytes(command);
  11364. }
  11365. else
  11366. {
  11367. commandQueue.push(command);
  11368. }
  11369. };
  11370. var pageLoaded = false;
  11371. var wsTimeout = null;
  11372. var reconnectAttempts = 0;
  11373.  
  11374. function onTimeout()
  11375. {
  11376. wsTimeout = null;
  11377. // renew the websocket
  11378. if (reconnectAttempts <= MAX_RECONNECTS)
  11379. {
  11380. win.webSocket = new WebSocket(win.SSL_ENABLED);
  11381. win.ignoreBytesTracker = Date.now();
  11382. initWSListener(win.webSocket);
  11383. reconnectAttempts++;
  11384. }
  11385. if (win.webSocket)
  11386. {
  11387. win.webSocket.close(WS_TIMEOUT_CODE, 'Connection timed out after ' + WS_TIMEOUT_SEC + ' seconds');
  11388. }
  11389. }
  11390.  
  11391. function updateWSTimeout()
  11392. {
  11393. if (wsTimeout)
  11394. {
  11395. win.clearTimeout(wsTimeout);
  11396. }
  11397. wsTimeout = win.setTimeout(onTimeout, WS_TIMEOUT_SEC * 1e3);
  11398. }
  11399. var messageQueue = [];
  11400.  
  11401. function onMessage(event)
  11402. {
  11403. if (pageLoaded)
  11404. {
  11405. updateWSTimeout();
  11406. return _onMessage.call(this, event);
  11407. }
  11408. else
  11409. {
  11410. messageQueue.push(event);
  11411. }
  11412. };
  11413. var wsOpenTimeout = null;
  11414.  
  11415. function onOpenTimeout()
  11416. {
  11417. wsOpenTimeout = null;
  11418. location.reload();
  11419. }
  11420.  
  11421. function onOpen(event)
  11422. {
  11423. reconnectAttempts = 0;
  11424. if (wsOpenTimeout)
  11425. {
  11426. win.clearTimeout(wsOpenTimeout);
  11427. wsOpenTimeout = null;
  11428. }
  11429. // do the handshake first
  11430. _onOpen.call(this, event);
  11431. commandQueue.forEach(function (command)
  11432. {
  11433. return win.cBytes(command);
  11434. });
  11435. }
  11436.  
  11437. function onError(event)
  11438. {
  11439. console.error('error in websocket:', event);
  11440. return _onError.call(this, event);
  11441. }
  11442.  
  11443. function onClose(event)
  11444. {
  11445. console.info('websocket closed:', event);
  11446. if (event.code !== WS_TIMEOUT_CODE || reconnectAttempts > MAX_RECONNECTS)
  11447. {
  11448. location.reload();
  11449. }
  11450. return _onClose.call(this, event);
  11451. }
  11452.  
  11453. function initWSListener(ws)
  11454. {
  11455. if (ws.readyState === WebSocket.CONNECTING)
  11456. {
  11457. wsOpenTimeout = win.setTimeout(onOpenTimeout, WS_OPEN_TIMEOUT_SEC * 1e3);
  11458. }
  11459. ws.onclose = onClose;
  11460. ws.onerror = onError;
  11461. ws.onmessage = onMessage;
  11462. ws.onopen = onOpen;
  11463. }
  11464. initWSListener(win.webSocket);
  11465. document.addEventListener('DOMContentLoaded', function ()
  11466. {
  11467. pageLoaded = true;
  11468. messageQueue.forEach(function (event)
  11469. {
  11470. return win.webSocket.onmessage(event);
  11471. });
  11472. });
  11473. }
  11474.  
  11475. function isScriptElement(el)
  11476. {
  11477. return el.nodeName === 'SCRIPT';
  11478. }
  11479.  
  11480. function isWebSocketScript(script)
  11481. {
  11482. return script.src.includes('socket.js');
  11483. }
  11484. var found = false;
  11485. if (document.head)
  11486. {
  11487. var scripts = document.head.querySelectorAll('script');
  11488. for (var i = 0; i < scripts.length; i++)
  11489. {
  11490. if (isWebSocketScript(scripts[i]))
  11491. {
  11492. // does this work?
  11493. scripts[i].onload = webSocketLoaded;
  11494. found = true;
  11495. }
  11496. }
  11497. }
  11498. if (!found)
  11499. {
  11500. // create an observer instance
  11501. var mutationObserver_1 = new MutationObserver(function (mutationList)
  11502. {
  11503. mutationList.forEach(function (mutation)
  11504. {
  11505. if (mutation.addedNodes.length === 0)
  11506. {
  11507. return;
  11508. }
  11509. for (var i = 0; i < mutation.addedNodes.length; i++)
  11510. {
  11511. var node = mutation.addedNodes[i];
  11512. if (isScriptElement(node) && isWebSocketScript(node))
  11513. {
  11514. mutationObserver_1.disconnect();
  11515. node.onload = webSocketLoaded;
  11516. return;
  11517. }
  11518. }
  11519. });
  11520. });
  11521. mutationObserver_1.observe(document.head
  11522. , {
  11523. childList: true
  11524. });
  11525. }
  11526. // fix scrollText (e.g. when joining the game and receiving xp at that moment)
  11527. win.mouseX = win.innerWidth / 2;
  11528. win.mouseY = win.innerHeight / 2;
  11529. var _confirm = win.confirm;
  11530. win.confirm = function (message)
  11531. {
  11532. // don't show the annoying update confirm box (instead of a confirm box, an ingame dialog could be used...)
  11533. if (message && message.indexOf('Ted\'s Market Script') !== -1)
  11534. {
  11535. return false;
  11536. }
  11537. return _confirm(message);
  11538. };
  11539. })(main || (main = {}));
  11540.  
  11541. })();