HRPG+

Heroes RPG+: Less effort, more info

Från och med 2015-10-14. Se den senaste versionen.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name        HRPG+
// @namespace   HRPG
// @description Heroes RPG+: Less effort, more info
// @include     http://heroesrpg.com/game.php*
// @include     http://www.heroesrpg.com/game.php*
// @version     1.1.6.16
// @grant       none
// ==/UserScript==
// todo: customise anything from github, sound on death option, filter globals,  minimise
// todon't: sell all accessories
$('#chat1').prepend(/*`<input type="submit" value="Cancel Autobuy" onclick="javascript:autoDo = false;"></input>*/
`Volume: <input id="volume" type="number" min="0" max="100" value="100" width="30" size="3"></input><br/>
<input type="checkbox" id="removeChatLines" ${window.localStorage.getItem('removeChatLines')=='true'?'checked="checked"':''}></input> Remove chat lines<br/>
Nugget's Alerts: 
<input type="checkbox" id="riftAlerts" ${window.localStorage.getItem('riftAlerts')=='true'?'checked="checked"':''}></input> Rift™ 
<input type="checkbox" id="riftTabTitle" ${window.localStorage.getItem('riftTabTitle')=='true'?'checked="checked"':''}></input> Title 
<input type="checkbox" id="pingAlerts" ${window.localStorage.getItem('pingAlerts')=='true'?'checked="checked"':''}></input> Ping™ 
<input type="checkbox" id="pingTabTitle" ${window.localStorage.getItem('pingTabTitle')=='true'?'checked="checked"':''}></input> Title 
<input type="checkbox" id="clanAttentionAlerts" ${window.localStorage.getItem('clanAttentionAlerts')=='true'?'checked="checked"':''}></input> Clan Attention™ 
<input type="checkbox" id="clanAttentionTabTitle" ${window.localStorage.getItem('clanAttentionTabTitle')=='true'?'checked="checked"':''}></input> Title <br/>
Show: 
<input type="checkbox" id="showMain" ${window.localStorage.getItem('showMain')=='true'?'checked="checked"':''}></input> Main 
<input type="checkbox" id="showClan" ${window.localStorage.getItem('showClan')=='true'?'checked="checked"':''}></input> Clan 
<input type="checkbox" id="showTrade" ${window.localStorage.getItem('showTrade')=='true'?'checked="checked"':''}></input> Trade 
<input type="checkbox" id="showGlobal" ${window.localStorage.getItem('showGlobal')=='true'?'checked="checked"':''}></input> Globals 
<input type="checkbox" id="showClanGlobal" ${window.localStorage.getItem('showClanGlobal')=='true'?'checked="checked"':''}></input> Clan Globals `);
$('#riftAlerts').change(function () {window.localStorage.setItem('riftAlerts',$('#riftAlerts').is(':checked'));});
$('#riftTabTitle').change(function () {window.localStorage.setItem('riftTabTitle',$('#riftTabTitle').is(':checked'));});
$('#pingAlerts').change(function () {window.localStorage.setItem('pingAlerts',$('#pingAlerts').is(':checked'));});
$('#pingTabTitle').change(function () {window.localStorage.setItem('pingTabTitle',$('#pingTabTitle').is(':checked'));});
$('#clanAttentionAlerts').change(function () {window.localStorage.setItem('clanAttentionAlerts',$('#clanAttentionAlerts').is(':checked'));});
$('#clanAttentionTabTitle').change(function () {window.localStorage.setItem('clanAttentionTabTitle',$('#clanAttentionTabTitle').is(':checked'));});
$('#removeChatLines').change(function () {window.localStorage.setItem('removeChatLines',$('#removeChatLines').is(':checked'));});
$('#volume').change(function () {window.localStorage.setItem('volume',$('#volume').val());});
$('#showMain').change(function () {window.localStorage.setItem('showMain',$('#showMain').is(':checked'));messageTypesVisible[0]=$('#showMain').is(':checked');chatVisibilityChanged();});
$('#showClan').change(function () {window.localStorage.setItem('showClan',$('#showClan').is(':checked'));messageTypesVisible[1]=$('#showClan').is(':checked');chatVisibilityChanged();});
$('#showTrade').change(function () {window.localStorage.setItem('showTrade',$('#showTrade').is(':checked'));messageTypesVisible[2]=$('#showTrade').is(':checked');chatVisibilityChanged();});
$('#showGlobal').change(function () {window.localStorage.setItem('showGlobal',$('#showGlobal').is(':checked'));messageTypesVisible[3]=$('#showGlobal').is(':checked');chatVisibilityChanged();});
$('#showClanGlobal').change(function () {window.localStorage.setItem('showClanGlobal',$('#showClanGlobal').is(':checked'));messageTypesVisible[4]=$('#showClanGlobal').is(':checked');chatVisibilityChanged();});

$('body').append(`<script>Array.prototype.after = function (o){return this[this.indexOf(o)+1];}
String.prototype.replaceAt = function(n, t) {return this.substring(0, n) + t + this.substring(n + 1);}
String.prototype.trim = function() {return this.replace(/^\s*(.*)\s*$/,'$1');}
String.prototype.underscorify = function(){ return this.toLowerCase().replace(' ','_'); }
String.prototype.linkify = function() {
  return ` +'` ${this} `' +`.replace(/(?!.*\\.\\..*|.*\\/\\..*|.*x\\d\\.\\d.*)\s+([^\\s<>\\(\\)]+\.[^\\s<>\\(\\)]+)\\s+/gi, function(match, p1, string) {
    var address = /[a-z]+:\\/\\//.test(p1) ? p1 : 'http://' + p1;
    p1 = p1.replace(/^https?:\\/\\//, '');
    return ' <a href="'+ address + '" target="_blank">' + p1 + '</a> ';
  });
}
String.prototype.removeLast = function(i) { return this.slice(0,this.length-i); }
String.prototype.makeHtml = function() {
  g_urls = [];
  g_titles = [];
  g_html_blocks = [];
  return _UnescapeSpecialChars(_RunSpanGamut(_RunBlockGamut(_StripLinkDefinitions(_HashHTMLBlocks(
    _Detab(this.replace(/~/g,"~T").replace(/\\$/g,"~D").replace(/\\r\\n/g,"\\n").replace(/\\r/g,"\\n")).replace(/^[ \\t]+$/mg,"")
  ))))).replace(/~D/g,"$$").replace(/~T/g,"~");
}</script>`);

Array.prototype.after = function (o){return this[this.indexOf(o)+1];}
String.prototype.replaceAt = function(n, t) {return this.substring(0, n) + t + this.substring(n + 1);}
String.prototype.trim = function(s) {return this.replace(/^\s*(.*)\s*$/,'$1');}
String.prototype.underscorify = function(s){ return this.toLowerCase().replace(' ','_'); }
String.prototype.linkify = function() {
  return ` ${this} `.replace(/(?!.*\.\..*|.*\/\..*|.*x\d\.\d.*)\s+([^\s<>\(\)]+\.[^\s<>\(\)]+)\s+/gi, function(match, p1, string) {
    var address = /[a-z]+:\/\//.test(p1) ? p1 : 'http://' + p1;
    p1 = p1.replace(/^https?:\/\//, '');
    return ' <a href="'+ address + '" target="_blank">' + p1 + '</a> ';
  });
}
String.prototype.removeLast = function(i) { return this.slice(0,this.length-i); }

//window.autoDo = true;

$('#bright_select').append(`
<option value="100">Boosts</option>
<option value="101">Stats</option>
<option value="102">Skills</option>
<option value="103">Referrals</option>`);
$('#chat_input').before(`<select id="chat_channel">
<option value="1">Main</option>
<option value="2">Clan</option>
<option value="3">Trade</option></select>`);

window.playAudio = function(name){
	audio = new Audio(`http://cdn.rawgit.com/somebody1234/misc-files/master/${name}.mp3`);
	audio.volume = parseFloat($('#volume').val())/100;
	audio.play();
}

window.tabTitleChanged = false;

$(window).on('focus', function() { resetTitle(); tabTitleChanged = false;});

window.displayAutosRemaining = function(autos) { if(!tabTitleChanged) { if(autos > 0) { document.title = 'Heroes RPG ('+autos+' Autos)'; } else { document.title = 'Heroes RPG (END OF AUTO)'; } } }

window.id = 1;
window.boost = 0;
window.name = '';
window.yourName = $('#s_cname')[0].textContent;

window.rarityNum = new Object();
window.rarityNum.common = 1;
window.rarityNum.uncommon = 2;
window.rarityNum.rare = 3;
window.rarityNum.epic = 4;
window.rarityNum.legendary = 5;

window.command = new Object();
window.command.c = 'Posts <message> to clan chat.'
window.command.t = 'Posts <message> to trade chat.'
window.command.double = 'Shows length of double and haste remaining.'
window.command.haste = 'Shows length of double and haste remaining.'
window.command.commands = 'Shows a list of commands.'
window.command.command = 'Shows information about <commandname>.'
window.command.profile = 'Shows profile of <username>.'
window.command.who = 'Shows basic information of <username>.'
window.command.misc = 'Shows battles and quests of <username>.'
window.command.crafting = 'Shows crafting levels of <username>.'
window.command.gathering = 'Shows gathering levels of <username>.'
//window.command.pick = 'Picks <number> <rarity> chests.'
//window.command.pickall = 'Picks all <rarity> chests.'
//window.command.buyboost = 'Buys <number> <name> boosts.'
//window.command.buyauto = 'Buys <number> autos.'

window.hideableMessageTypes = ['main, .emote','clan','trade','global','clanglobal'];
window.messageTypesVisible = [window.localStorage.getItem('showMain'),window.localStorage.getItem('showClan'),window.localStorage.getItem('showTrade'),window.localStorage.getItem('showGlobal'),window.localStorage.getItem('showClanGlobal')];

window.chatVisibilityChanged = function(){
  var filter = '';
  for(var i = 0; i < hideableMessageTypes.length; i++){
    if(!messageTypesVisible[i]) { filter = filter + `.${hideableMessageTypes[i]}, ` }
  }
  $('tr','#chat_table1').show().filter($(filter.removeLast(2))).hide();
}

//Start Showdown

window.g_list_level = 0;

String.prototype.makeHtml = function() {
  g_urls = [];
  g_titles = [];
  g_html_blocks = [];
  return _UnescapeSpecialChars(_RunSpanGamut(_RunBlockGamut(_StripLinkDefinitions(_HashHTMLBlocks(
    _Detab(this.replace(/~/g,"~T").replace(/\$/g,"~D").replace(/\r\n/g,"\n").replace(/\r/g,"\n")).replace(/^[ \t]+$/mg,"")
  ))))).replace(/~D/g,"$$").replace(/~T/g,"~");
}

window._StripLinkDefinitions = function(text) {
  return text.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|\Z)/gm,
    function (wholeMatch,m1,m2,m3,m4) {
      m1 = m1.toLowerCase();
      g_urls[m1] = _EncodeAmpsAndAngles(m2);
      if (m3) { return m3+m4; } else if (m4) { g_titles[m1] = m4.replace(/"/g,"&quot;"); }
      return "";
    });
}

window.block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del";
window.block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math";

window._HashHTMLBlocks = function(text) {
  return text.replace(/\n/g,"\n\n")
             .replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm,hashElement)
             .replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math)\b[^\r]*?.*<\/\2>[ \t]*(?=\n+)\n)/gm,hashElement)
             .replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,hashElement)
             .replace(/(\n\n[ ]{0,3}<!(--[^\r]*?--\s*)+>[ \t]*(?=\n{2,}))/g,hashElement)
             .replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,hashElement)
             .replace(/\n\n/g,"\n");
}

window.hashElement = function(wholeMatch,m1) {
  return "~K" + (g_html_blocks.push(
    m1.replace(/\n\n/g,"\n")
      .replace(/^\n/,"")
      .replace(/\n+$/g,"")
  )-1).toString() + "K";
}

window._RunBlockGamut = function(text) {
	var key = hashBlock("<hr />");
  return _FormParagraphs(_HashHTMLBlocks(_DoBlockQuotes(_DoCodeBlocks(_DoLists(
		_DoHeaders(text).replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm,key).replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm,key).replace(/^[ ]{0,2}([ ]?\_[ ]?){3,}[ \t]*$/gm,key)
	)))));
}

_FormParagraphs = function(text, doNotUnhash) {
  var grafs = text.replace(/^\n+/g,'').replace(/\n+$/g,'').split(/\n{2,}/g);
  var grafsOut = [];
  for (i = 0; i < grafs.length; i++) {
    var str = grafs[i];
    if (str.search(/~K(\d+)K/g) >= 0) { grafsOut.push(str); }
    else if (str.search(/\S/) >= 0) {
      str = _RunSpanGamut(str).replace(/^([ \t]*)/g,'');
      grafsOut.push(str);
    }
  }
  for (i=0; i<grafsOut.length; i++) {while(grafsOut[i].search(/~K(\d+)K/) >= 0) {grafsOut[i] = grafsOut[i].replace(/~K\d+K/,g_html_blocks[RegExp.$1].replace(/\$/g,"$$$$"));}}
  return grafsOut.join('/n/n');//\n\n?
}

window._RunSpanGamut = function(text) { return _DoItalicsAndBold(_EncodeAmpsAndAngles(_DoAutoLinks(_DoAnchors(_DoImages(_EncodeBackslashEscapes(_EscapeSpecialCharsWithinTagAttributes(_DoCodeSpans(text)))))))).replace(/  +\n/g," <br />\n"); }
window._EscapeSpecialCharsWithinTagAttributes = function(text) { return text.replace(/(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi, function(wholeMatch) { return escapeCharacters(wholeMatch.replace(/(.)<\/?code>(?=.)/g,"$1`"),"\\`*_"); }); }

window._DoAnchors = function(text) {
  return text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeAnchorTag)
             .replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()<?(.*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeAnchorTag)
             .replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag);
}

window.writeAnchorTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {
  if (m7 == undefined) m7 = "";
  var whole_match = m1;
  var link_text   = m2;
  var link_id   = m3.toLowerCase();
  var url    = m4;
  var title  = m7;
  if (url == "") {
    if (link_id == "") { link_id = link_text.toLowerCase().replace(/ ?\n/g," "); }
    url = "#"+link_id;
    if (g_urls[link_id] != undefined) {
      url = g_urls[link_id];
      if (g_titles[link_id] != undefined) { title = g_titles[link_id]; }
    }
    else { if (whole_match.search(/\(\s*\)$/m)>-1) { url = ""; } else { return whole_match; } }
  }
  url = escapeCharacters(url,"*_");
  var result = "<a href=\"" + url + "\"";
  if (title != "") {
    title = title.replace(/"/g,"&quot;");
    title = escapeCharacters(title,"*_");
    result +=  " title=\"" + title + "\"";
  }
  result += ">" + link_text + "</a>";
  return result;
}

window._DoImages = function(text) {
  text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeImageTag);
  text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()<?(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeImageTag);
  return text;
}

window.writeImageTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {
  var alt_text = m2;
  var link_id = m3.toLowerCase();
  var url = m4;
  var title= m7;
  if (!title) title = "";
  if (url == "") {
    if (link_id == "") { link_id = alt_text.toLowerCase().replace(/ ?\n/g," "); }
    url = "#"+link_id;
    if (g_urls[link_id] != undefined) {
      url = g_urls[link_id];
      if (g_titles[link_id] != undefined) { title = g_titles[link_id]; }
    }
    else { return m1; }
  }
  alt_text = alt_text.replace(/"/g,"&quot;");
  url = escapeCharacters(url,"*_");
  var result = "<img src=\"" + url + "\" alt=\"" + alt_text + "\"";
  title = title.replace(/"/g,"&quot;");
  title = escapeCharacters(title,"*_");
  result +=  " title=\"" + title + "\"";
  result += " />";
  return result;
}

window._DoHeaders = function(text) {
  return text.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm,function(wholeMatch,m1){return hashBlock("<h1>" + _RunSpanGamut(m1) + "</h1>");})
             .replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,function(matchFound,m1){return hashBlock("<h2>" + _RunSpanGamut(m1) + "</h2>");})
             .replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,function(wholeMatch,m1,m2) {
               var h_level = m1.length;
               return hashBlock("<h" + h_level + ">" + _RunSpanGamut(m2) + "</h" + h_level + ">");
             });
}

window._ProcessListItems;//what

window._DoLists = function(text) {
  text += "~0";
  var whole_list = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
  if (g_list_level) {
    text = text.replace(whole_list,function(wholeMatch,m1,m2) {
      var list_type = (m2.search(/[*+-]/g)>-1) ? "ul" : "ol";
      return "<"+list_type+">" + _ProcessListItems(m1.replace(/\n{2,}/g,"\n\n\n")).replace(/\s+$/,"") + "</"+list_type+">\n";
    });
  } else {
    whole_list = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g;
    text = text.replace(whole_list,function(wholeMatch,m1,m2,m3) {
      var list_type = (m3.search(/[*+-]/g)>-1) ? "ul" : "ol";
      return m1 + "<"+list_type+">\n" + _ProcessListItems(m2.replace(/\n{2,}/g,"\n\n\n")) + "</"+list_type+">\n";
    });
  }
  return text.replace(/~0/,"");
}

window._ProcessListItems = function(list_str) {
  g_list_level++;
  list_str = (list_str.replace(/\n{2,}$/,"\n")+"~0").replace(/(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
    function(wholeMatch,m1,m2,m3,m4){
      //var leading_space = m2;
      if (m1 || (m4.search(/\n{2,}/)>-1)) { m4 = _RunBlockGamut(_Outdent(m4)); }
      else { m4 = _RunSpanGamut(_DoLists(_Outdent(m4)).replace(/\n$/,"")); }
      return  "<li>" + m4 + "</li>\n";
    }  );
  g_list_level--;
  return list_str.replace(/~0/g,"");
}

window._DoCodeBlocks = function(text) { return (text+"~0").replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g, function(wholeMatch,m1,m2) { return hashBlock("<pre><code>" + _Detab(_EncodeCode( _Outdent(m1))).replace(/^\n+/g,"").replace(/\n+$/g,"") + "\n</code></pre>") + m2;}).replace(/~0/,""); }
window.hashBlock = function(text) { return "~K" + (g_html_blocks.push(text.replace(/(^\n+|\n+$)/g,""))-1).toString() + "K"; }
window._DoCodeSpans = function(text) { return text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(wholeMatch,m1,m2,m3,m4) { return m1+"<code>"+_EncodeCode(m3.replace(/^([ \t]*)/g,"").replace(/[ \t]*$/g,""))+"</code>";}); }
window._EncodeCode = function(text) { return escapeCharacters(text.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;"),"\*_{}[]\\",false); }
window._DoItalicsAndBold = function(text) {   return text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,"<strong>$2</strong>").replace(/(\w)_(\w)/g, "$1~E95E$2").replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,"<em>$2</em>"); }

window._DoBlockQuotes = function(text) {
  return text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm, function(wholeMatch,m1) {
    return hashBlock("<blockquote>\n" + _RunBlockGamut(m1.replace(/^[ \t]*>[ \t]?/gm,"~0")
      .replace(/~0/g,"")
      .replace(/^[ \t]+$/gm,""))
      .replace(/(^|\n)/g,"$1  ")
      .replace(/(\s*<pre>[^\r]+?<\/pre>)/gm, function(wholeMatch,m1) { return m1.replace(/^  /mg,"~0").replace(/~0/g,""); }) + "\n</blockquote>");
  });
}

window._EncodeAmpsAndAngles = function(text) { return text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&amp;").replace(/<(?![a-z\/?\$!])/gi,"&lt;"); }
window._EncodeBackslashEscapes = function(text) { return text.replace(/\\(\\)/g,escapeCharacters_callback).replace(/\\([`*_{}\[\]()>#+-.!])/g,escapeCharacters_callback); }
window._DoAutoLinks = function(text) { return text.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,"<a href=\"$1\">$1</a>").replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi, function(wholeMatch,m1) { return _EncodeEmailAddress(_UnescapeSpecialChars(m1));});}

window._EncodeEmailAddress = function(addr) {
  function char2hex(ch) {
    var hexDigits = '0123456789ABCDEF';
    var dec = ch.charCodeAt(0);
    return(hexDigits.charAt(dec>>4) + hexDigits.charAt(dec&15));
  }
  encode = [
    function(ch){return "&#"+ch.charCodeAt(0)+";";},
    function(ch){return "&#x"+char2hex(ch)+";";},
    function(ch){return ch;}
  ];
  addr = ("mailto:" + addr).replace(/./g, function(ch) {
    if (ch == "@") { ch = encode[Math.floor(Math.random()*2)](ch); } else if (ch !=":") {
      var r = Math.random();
      ch =  (r > .9  ?  encode[2](ch):r > .45 ?  encode[1](ch):encode[0](ch));
    }
    return ch;
  });
  addr = "<a href=\"" + addr + "\">" + addr + "</a>";
  return addr.replace(/">.+:/g,"\">");
}

window._UnescapeSpecialChars = function(text) { return text.replace(/~E(\d+)E/g, function(wholeMatch,m1) { return String.fromCharCode(parseInt(m1)); }); }
window._Outdent = function(text) { return text.replace(/^(\t|[ ]{1,4})/gm,"~0").replace(/~0/g,""); }

window._Detab = function(text) {
  return text.replace(/\t(?=\t)/g,"    ")
             .replace(/\t/g,"~A~B")
             .replace(/~B(.+?)~A/g, function(wholeMatch,m1,m2) {
               var numSpaces = 4 - m1.length % 4;
               for (var i=0; i<numSpaces; i++) m1+=" ";
               return m1; })
             .replace(/~A/g,"    ")
             .replace(/~B/g,"");
}

window.escapeCharacters = function(text, charsToEscape, afterBackslash) {
  var regexString = "([" + charsToEscape.replace(/([\[\]\\])/g,"\\$1") + "])";
  if (afterBackslash) { regexString = "\\\\" + regexString; }
  var regex = new RegExp(regexString,"g");
  return text.replace(regex,escapeCharacters_callback);
}

window.escapeCharacters_callback = function(wholeMatch,m1) { return "~E"+m1.charCodeAt(0)+"E"; }

//End Showdown

/*window.goToChannel = function(channel) {
  $('#chat1, #chat10, #chat50, #chat100').hide();
  $('#chat' + channel).show();
  chatview = channel;
  if(channel == 1) { chatcount1 = 0; }
  else if(channel == 10) { chatcount10 = 0; }
  else if(channel == 100) { refreshBoosts(); }
  $('#chatcount'+channel).html(null);
}*/

window.boosts = ['Battle Exp', 'Gold', 'Attribute', 'Battle SP', 'Gathering Exp', 'Gathering SP', 'Drop'];
window.gemTypes = ['Ruby', 'Emerald', 'Diamond', 'Sapphire', 'Amethyst'];
window.gemRarities = ['Fractured', 'Chipped', 'Dull', 'Clouded', 'Bright', 'Glowing', 'Radiant', 'Flawless', 'Perfect', 'Priceless'];
window.gemRarityBoosts = [5, 10, 15, 20, 25, 30, 40, 50, 75, 100];

window.addCreditBoost = function(id,name) {
  $.post('upgrade.php', {mod:'boosts'}, function(data){
    var current = parseFloat($('#' + name.underscorify()).text());
    var percentage = $('td',$('tr',data.v)[id+1])[1].textContent.split(' ')[0];
    current += parseFloat(percentage.removeLast(1));
    $('#' + name.underscorify()).text(current);
  }, 'json');
}


window.addClanBoost = function(id,name) {
  $.post('clan.php', {mod:'buildinglist', id:id+10}, function(data){
    var current = parseFloat($('#' + name.underscorify()).text());
    current += parseFloat($(data.v)[5].textContent.split(' ')[2]) * (id==7?3:10);
    $('#' + name.underscorify()).text(current);
  }, 'json');
}

window.addGemBoost = function(id,name) {
  $.post('displayr.php', {mod:1}, function(data) {
    var array = $('a',data.html);
    for(var i = 0; i < array.length; i++){
      if(array[i].id!='') { continue; }
      if(array[i].href.match(/:(.*)\(/)[1] == 'viewItem'){
        $.post('misc.php', {mod:'viewitem', id:parseInt(array[i].href.match(/\((.*)\)/)[1])}, function(data) {
          var values = $.map($('td',data.v),function(data){return data.textContent;});
          var sockets = values.after('Sockets');
          for(var j = 0; j < sockets; j++) {
            var gem = values.after(`S${j+1}:`);
            var words = gem.split(' ');
            if(gemTypes.indexOf(words[1]) + 1 == id) {
              var current = parseFloat($('#' + name.underscorify()).text());
              current += parseFloat(gemRarityBoosts[gemRarities.indexOf(words[0])])/10;
              $('#' + name.underscorify()).text(current);
            }
          }
        }, 'json');
      }
      if(array[i].href.match(/:(.*)\(/)[1] == 'viewAccessory'){
        $.post('http://heroesrpg.com/misc.php', {mod:'viewaccessory', id:array[i].href.match(/\((.*)\)/)[1]}, function(data) {
          var array = $.map($('td',data.v),function(data){return data.textContent;});
          gem = array[array.length - 1].slice(5);
          if(gem != 'Unequip To Socket'){
            var words = gem.split(' ');
            if(gemTypes.indexOf(words[1]) + 1 == id){
              var bonus = array[array.length - 2];
              bonus = bonus.removeLast(1);
              var current = parseFloat($('#' + name.underscorify()).text());
              current += parseFloat(gemRarityBoosts[gemRarities.indexOf(words[0])])/10 * (1 + parseFloat(bonus)/100);
              $('#' + name.underscorify()).text(current);
            }
          }
        }, 'json');
      }
    }
  }, 'json');
}

window.refreshBoosts = function(){
  var option = $('#boost_select').val();
  var boostHtml = '';
  for(var id = 0; id < boosts.length - 1; id++){
    var name = boosts[id];
    $('#' + name.underscorify()).html('0');
    if(option == 2 || option == 1) addCreditBoost(parseInt(id)+1,name);
    if(option == 3 || option == 1) addClanBoost(parseInt(id)+1,name);
    if(option == 4 || option == 1) addGemBoost(parseInt(id)+1,name);
  }
  $('#' + boosts[boosts.length-1].underscorify()).html('0');
  if(option == 3 || option == 1) addClanBoost(boosts.length,boosts[boosts.length-1]);
}

/*window.maxAutos = function(credits) {
  //return credits = 10*Math.floor(autos/10)*(Math.floor(autos/10)-1) + 10*((autos/10)%1)*(Math.floor(autos/10))- 30
}*/

window.chatLine = function(msg,$class){
  $('#chat_table1').prepend('<tr class="'+$class+'" id="ct1_tr'+(chatid1)+'"><td>'+msg+'</td></tr>');
  window.chatid1++;
}

window.send_chat = function(){
  //autoDo = true;
  var msg = chatInputElem.val().trim();
  var command = '';
  if(msg.startsWith('/')) { command = msg.toLowerCase().slice(1); }
  if(['stats','skills','ref'].indexOf(command) != -1){ changeTab(command); }
  if(!msg.startsWith('/') && $('#chat_channel').val() != 1){
    if($('#chat_channel').val() == 2) { msg = '/c ' + msg; }
    else if($('#chat_channel').val() == 3) { msg = '/t ' + msg; }
  }
  if(command.startsWith(' ')){ msg = msg.slice(2); }
  if(command.startsWith('M ')){ msg = msg.slice(3); }
  if(command == 'commands'){
    chatLine('<font color="BBFFBB">/c &lt;message&gt;, /t &lt;message&gt;, /double, /haste /commands, /command &lt;commandname&gt;</font>');//TODO: profile, misc, gathering, crafting, who
    chatInputElem.val('');
    return;
  }
  if(command.startsWith('command ')){
    var commandName=msg.slice(9);
    chatInputElem.val('');
    chatLine(`<font color="BBFFBB">/${commandName}: ${command[commandName].replace('<','&lt;').replace('>','&gt')}</font>`);
    return;
  }
/*  if(command.startsWith('buyboost ')){
    vars = msg.slice(10).split(' ');
    chatInputElem.val('');
    id = boosts[vars[0]];
    amount = Math.min(vars[1],$('#s_credits')[0].textContent/50);
    while (autoDo && amount > 0){
      amount--;
      spendCredits(id,'boost');
    }
    return;
  }
  if(command.startsWith('buyauto ')){
    amount = Math.min(msg.slice(9),$('#s_credits')[0].textContent);
    chatInputElem.val('');
    while (autoDo && amount > 0){
      amount--;
      spendCredits(id,'boost');
    }
    return;
  }
  if(command.startsWith('pick ')){
    var vars = msg.slice(6).split(' ');
    var rarity = rarityNum[vars[0]];
    chatInputElem.val('');
    if (rarity == undefined) return;
    $('#center_select').val(5);
    centerSelect();
    $('#craft_select')[0].selectedIndex = 4;
    craftSelect();
    console.log(rarity);
    amount = Math.min($('tr','#lockpicking-table')[parseInt(rarity)].childNodes[1].textContent,vars[1]);
    while (autoDo && amount > 9){
      amount -= 10;
      craftPickLock(rarity,2);
    }
    while (autoDo && amount > 0){
      amount--;
      craftPickLock(rarity,1);
    }
    return;
  }
  if(command.startsWith('pickall ')){
    var rarity = rarityNum[msg.slice(9)];
    chatInputElem.val('');
    if (rarity == undefined) return;
    $('select#center_select')[0].selectedIndex = 3;
    centerSelect();
    $('select#craft_select')[0].selectedIndex = 4;
    craftSelect();
    while (autoDo && $('tr','#lockpicking-table')[parseInt(rarity)].childNodes[1].textContent > 9) craftPickLock(rarity,2);
    while (autoDo && $('tr','#lockpicking-table')[parseInt(rarity)].childNodes[1].textContent > 0) craftPickLock(rarity,1);
    return;
  }*/
  if(command.startsWith('profile ')){
    viewPlayer(msg.slice(9));
    chatInputElem.val('');
    return;
  }
  if(command.startsWith('who ')){
    $.post('misc.php', {mod:'viewplayer', id:msg.slice(5)}, function(data) {
      array = $.map($('td',$.parseJSON(data).v),function(n){return n.textContent;});
      name = array.after('Name:');
      online = false;
      line1 = `<font color="BBFFBB"><a href="javascript:m('${name}');">${name}</a> - ${$('a',$.parseJSON(data).v)[0].outerHTML} - Level ${array.after('Level:')} - ${array.after('Nobility Rank:')} - `;
      line2 = ` - <a href="javascript:viewPlayer('${name}')">Profile</a></font>`;
      $.post('misc.php', {mod:'playersonlinelist'}, function(data) { 
        if($.map($('td',$.parseJSON(data).v),function(n){return n.textContent;}).indexOf(name) != -1) {
          chatLine(line1.concat('[ONLINE]').concat(line2));
        } else {
          chatLine(line1.concat('<font color="#FFBBBB">[OFFLINE]</font>').concat(line2));
        }
      }, 'json');
    }, 'json');
    chatInputElem.val('');
    return;
  }
  if(command.startsWith('misc ')){
    $.post('misc.php', {mod:'viewplayer', id:msg.slice(6)}, function(data) {
      array = $.map($('td',$.parseJSON(data).v),function(n){return n.textContent;});
      name = array.after('Name:');
      chatLine(`<font color="BBFFBB"><a href="javascript:m('${name}');">${name}</a> - Battles: ${array.after('Battles:')} - Battle Quests: ${array.after('Battle Quests:')} - TS Quests ${array.after('TS Quests:')}</font>`);
    }, 'json');
    chatInputElem.val('');
    return;
  }
  if(command.startsWith('crafting ')){
    $.post('misc.php', {mod:'viewplayer', id:msg.slice(6)}, function(data) {
      array = $.map($('td',$.parseJSON(data).v),function(n){return n.textContent;});
      name = array.after('Name:');
      chatLine(`<font color="BBFFBB"><a href="javascript:m('${name}');">${name}</a> - Forging: ${array.after('Forging:')} - Leatherworking: ${array.after('Leatherworking:')} - Enchanting: ${array.after('Enchanting:')} - Lockpicking: ${array.after('Lockpicking:')} - Jewelcrafing: ${array.after('Jewelcrafting:')}</font>`);
    }, 'json');
    chatInputElem.val('');
    return;
  }
  if(command.toLowerCase().startsWith('gathering ')){
    $.post('misc.php', {mod:'viewplayer', id:msg.slice(6)}, function(data) {
      array = $.map($('td',$.parseJSON(data).v),function(n){return n.textContent;});
      name = array.after('Name:');
      chatLine(`<font color="BBFFBB"><a href="javascript:m('${name}');">${name}</a> - Hunting: ${array.after('Hunting:')} - Mining: ${array.after('Mining:')} - Woodcutting: ${array.after('Woodcutting:')} - Quarrying: ${array.after('Quarrying:')}</font>`);
    }, 'json');
    chatInputElem.val('');
    return;
  }
  if(command.startsWith('g ')){msg.replaceAt(2,'c');}
  $.post('chat.php', {mod:'send', msg:msg}, function(data) {
    if(!data.err) {
      if(data.addignore) {ignored.push(data.addignore);}
      if(data.remignore) {ignored.splice(ignored.indexOf(data.remignore, 1));}
      chatInputElem.val('');
      chatinactivity = 0;
      update_chat(0);
    } else { displayError(data.err); }
  }, 'json');
}

window.bRightSelect = function() {
  mod = $('#bright_select').val();
  if(mod == 100){
    $('#bright_content').html(`<table><tr><td align="center"><select id="boost_select" onchange="javascript:refreshBoosts();">
<option value="1">Total</option>
<option value="2">Credit</option>
<option value="3">Clan</option>
<option value="4">Equipment</option>
</select></td></tr></table><table id="boosts"></table>`);
    for(var i = 0; i < boosts.length; i++){
      $('#boosts').append(`<tr><td>${boosts[i]}:</td><td id="${boosts[i].underscorify()}"></td><td>%</td></tr>`);
    }
    refreshBoosts();
  }
  else if(mod == 101){ $('#bright_content').html(`<table id="info"></table>`); $('#chat_input').val('/stats'); send_chat(); }
  else if(mod == 102){ $('#bright_content').html(`<table id="info"></table>`); $('#chat_input').val('/skills'); send_chat(); }
  else if(mod == 103){ $('#bright_content').html(`<table id="info"></table>`); $('#chat_input').val('/ref'); send_chat(); }
  else { $.post('displayr.php', {mod:mod}, function(data) { $('#bright_content').html(data.html); }, 'json'); }
}

window.changeTab = function(name){
  if(name == 'stats') { $('#bright_select').val(101); $('#bright_content').html(`<table id="info"></table>`); }
  else if(name == 'skills') { $('#bright_select').val(102); $('#bright_content').html(`<table id="info"></table>`); }
  else if(name == 'ref') { $('#bright_select').val(103); $('#bright_content').html(`<table id="info"></table>`); }
}

window.possibleClanAttentionAlert = function(name, message, mode){
  $.post('clan.php', {mod:'members'}, function(data){
    var html = $.parseJSON(data).v;
    var coLeader = false;
    var indexOfCl = html.indexOf(name)+name.length+4;
    if(html.slice(indexOfCl,indexOfCl+4) == '[CL]') {coLeader = true};
    if(html.slice(indexOfCl,indexOfCl+3) == '[L]') {coLeader = true};
    if(coLeader && mode == 'audio'){playAudio('alert');}
    if(coLeader && mode == 'title'){document.title=`${name}: ${message}`;}
  }, 'json');
}

window.update_chat = function(initiate) {
  stopActivityTimer();
  startActivityTimer();
  $.post('chatupdate2.php', {initiate:initiate}, function(data) {
    if(data.c) {
      $.each(data.c, function(i, item) {
        if($.inArray(data.c[i].uid, ignored) < 0) {
          var c = data.c[i];
          var chat_table = 1;
          var $class = '';
          var msg = '';
          if(c.type == 1 || c.type == 20 || c.type == 30 || c.type == 55 || c.type == 1000) c.message = c.message.linkify().makeHtml();
            if(c.type == 1) { $class = 'main'; msg = '<span class="time">['+c.time+']</span> '+genrank(c.nrank, c.prank)+' '+genStatus(c.status)+'<a href="javascript:m(\''+c.cname+'\');">'+c.cname+'</a>: '+c.message+'</span>';
            if($('#pingAlerts').is(':checked') && c.message.contains(yourName)){playAudio('bell');}
            if($('#pingTabTitle').is(':checked') && c.message.contains(yourName)){ document.title = 'Your name has been mentioned.'; tabTitleChanged = true;}}
          else if(c.type == 0) { $class = 'chaterror'; msg = '<span class="time">['+c.time+']</span> <span style="color: #FF8888">'+c.message+'</span>'; }
          else if(c.type == 5) { $class = 'info'; msg = '<span class="time">['+c.time+']</span> <span style="color: #55AA55">'+c.message+'</span>';
            $('#info').html(`<tr><td>${c.message.replace(/(?!Battle:)(?!Gathering:): /g,':</td><td>').replace(/<br \/>/g,'</td></tr><tr><td>').replace(/\[/g,'<br/>[')}</td></tr>`); return; }
          else if(c.type == 10) { $class = 'global'; msg = '<span class="time">['+c.time+']</span> <span style="color: #88FF88">Global: '+c.message+'</span>';
            if($('#riftAlerts').is(':checked') && c.message == '<span style="color: #CC66CC">A Rift will open in 5 minutes!</span>') {playAudio('foghorn');}
            if($('#riftAlerts').is(':checked') && c.message == `<span style="color: #CC66CC">A Rift has opened! The Rift will close in 10 minutes!</span> [<a href="javascript:enterRift()">Enter Rift</a>]`) {playAudio('rumble');}
            if($('#riftTabTitle').is(':checked') && c.message == '<span style="color: #CC66CC">A Rift will open in 5 minutes!</span>') {document.title = 'A rift is opening.'; tabTitleChanged = true;}
            if($('#riftTabTitle').is(':checked') && c.message == `<span style="color: #CC66CC">A Rift has opened! The Rift will close in 10 minutes!</span> [<a href="javascript:enterRift()">Enter Rift</a>]`) {document.title = 'A Rift has opened.'; tabTitleChanged = true;}}
          else if(c.type == 1000) { $class = 'clan'; msg = '<span class="time">['+c.time+']</span> '+genrank(c.nrank, c.prank)+' <span style="color: #FFFF00">[Clan] <a href="javascript:m(\''+c.cname+'\');">'+c.cname+'</a>: '+c.message+'</span>';
            if($('#clanAttentionAlerts').is(':checked') && c.message.startsWith('ATTENTION: ')){possibleClanAttentionAlert(c.cname, c.message,'audio');}
            if($('#clanAttentionTabTitle').is(':checked') && c.message.startsWith('ATTENTION: ')){possibleClanAttentionAlert(c.cname, c.message,'title');}}
          else if(c.type == 1001) { $class = 'clanglobal'; msg = '<span class="time">['+c.time+']</span> <span style="color: #FFFF00">Clan Global: '+c.message+'</span>'; }
          else if(c.type == 20) { $class = 'newbie'; msg = '<span class="time">['+c.time+']</span> '+genrank(c.nrank, c.prank)+' <span style="color: #9999FF">[Newbie] <a href="javascript:m(\''+c.cname+'\');">'+c.cname+'</a>: '+c.message+'</span>'; }
          else if(c.type == 30) { $class = 'staff'; msg = '<span class="time">['+c.time+']</span> '+genrank(c.nrank, c.prank)+' <span style="color: #FF9933">[Staff] <a href="javascript:m(\''+c.cname+'\');">'+c.cname+'</a>: '+c.message+'</span>'; }
          else if(c.type == 55) { $class = 'trade'; msg = '<span class="time">['+c.time+']</span> '+genrank(c.nrank, c.prank)+' <span style="color: #00BB00">[Trade] <a href="javascript:m(\''+c.cname+'\');">'+c.cname+'</a>: '+c.message+'</span>'; }
          else if(c.type == 50) { $class = 'pmto'; msg = '<span class="time">['+c.time+']</span> <span style="color: #FF7171">Message Received: <a href="javascript:m(\''+c.cname+'\');">'+c.cname+'</a>: '+c.message+'</span>'; }
          else if(c.type == 51) { $class = 'pmfrom'; msg = '<span class="time">['+c.time+']</span> <span style="color: #F59292">Message Sent: <a href="javascript:m(\''+c.cname+'\');">'+c.cname+'</a>: '+c.message+'</span>'; }
          else if(c.type == 2) { $class = 'emote'; msg = '<span class="time">['+c.time+']</span> '+genrank(c.nrank, c.prank)+' <i>* '+genStatus(c.status)+'<a href="javascript:m(\''+c.cname+'\');">'+c.cname+'</a> '+c.message+'</span></i>'; }
          else if(c.type == 99) { $class = 'log'; msg = '<span class="time">['+c.time+']</span> '+c.message; chat_table = 10; }
          else if(c.type == 101) { msg = '<span class="time">['+c.time+']</span> '+genrank(c.nrank, c.prank)+' '+genStatus(c.status)+'<a href="javascript:m(\''+c.cname+'\');">'+c.cname+'</a>: '+c.message+'</span>'; chat_table = 50; }
          if(chat_table == 10) {
            $('#chat_table10').prepend('<tr id=\"ct10_tr'+(chatid10)+'\"><td>'+msg+'</td></tr>');
            chatid10++;
            if(chatview != 10) { chatcount10++; $('#chatcount10').html(' ('+chatcount10+')'); }
            if(initiate == 0 && $('#removeChatLines').is(':checked')) { $('#ct10_tr'+(chatid10-chatsize)).remove(); }
          }
          else if(chat_table == 50) {
            $('#chat_table50').prepend('<tr id=\"ct50_tr'+(chatid50)+'\"><td>'+msg+'</td></tr>');
            chatid50++;
            if(initiate == 0 && $('#removeChatLines').is(':checked')) { $('#ct50_tr'+(chatid50-chatsize)).remove(); }
          }
          else {
            chatLine(msg,$class);
            if(chatview != 1) { chatcount1++; $('#chatcount1').html(' ('+chatcount1+')'); }
            var filter = '';
            for(var i = 0; i < hideableMessageTypes.length; i++){if(messageTypesVisible[i]=='false') { filter += `.${hideableMessageTypes[i]}, `;}}
            if(filter.contains($class)) { $(`#ct1_tr${chatid1-1}`).hide(); }     
            if(initiate == 0 && $('#removeChatLines').is(':checked')) { $('#ct1_tr'+(chatid1-chatsize)).remove(); }
          }
        }
        if(data.fl) {window.location = 'http://www.heroesrpg.com';}
      });
    }
    stopActivityTimer();
    clearTimeout(chattimer);
    if(chatinactivity < 20) {
      chatinactivity++;
      chattimer = setTimeout(function() {update_chat(0);}, 5000);
    } else {
      chattimer = setTimeout(function() {update_chat(0);}, 9000);
    }
  }, 'json');
}