Nayru

libN

Oct 9th, 2018
108
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 113.54 KB | None | 0 0
  1. // ==UserScript==
  2. // @name LibC
  3. // @description Lib's Conglomerated Scripts
  4. // @include *nexusclash.com/modules.php?name=Game*
  5. // @include *www.nexusclash.com/modules.php?name=Game*
  6. // @exclude *nexusclash.com/modules.php?name=Game&op=disconnect
  7. // @exclude *www.nexusclash.com/modules.php?name=Game&op=disconnect
  8. // @grant GM_getValue
  9. // @grant GM_setValue
  10. // @version 3.0.1-X
  11. // ==/UserScript==
  12.  
  13. (function () {
  14. versionStr = '3.0.1'; // version updates go here too!
  15.  
  16. libCLogging = false; // logs to console; can disable if you want
  17. libCLoggingVerbose = false; // enable for dev-work
  18.  
  19.  
  20. //#############################################################################
  21. // boilerplate functions:
  22.  
  23. // takes list of css to inject into the global style sheet
  24. // uses list to batch the operation, instead of multiple read/write operations to DOM
  25. function addGlobalStyle(list) {
  26. var head, style, i, len, css= '';
  27. head = document.getElementsByTagName('head')[0];
  28. if (!head) { return; }
  29. style = document.createElement('style');
  30. style.type = 'text/css';
  31. len = list.length;
  32. for (i = 0; i < len; i++) { css += list[i]; }
  33. style.innerHTML = css;
  34. head.appendChild(style);
  35. }
  36.  
  37. // generic functions
  38. function timesCharExist(x, c){ var t=0,l=0;c=c+''; while(l=x.indexOf(c,l)+1)++t; return t; }
  39. function ucfirstletter(str){ return str.replace(/\b[A-Za-z]/,function($0) { return $0.toUpperCase(); }); }
  40. function isNormalInteger(str) { var n = ~~Number(str); return String(n) === str && n >= 0; }
  41.  
  42. // forces ints to be two digits long for displaying as string
  43. function fluffDigit(x) { if (x<10) { x = '0'+x; } return x; }
  44.  
  45. // platform support: GM is provided by greasemonkey, if not assume chrome and use localStorage
  46. try {
  47. if (!this.GM_getValue || (this.GM_getValue.toString && this.GM_getValue.toString().indexOf('not supported') > -1)) {
  48. this.GM_getValue = function (key, def) { return localStorage[key] || def; };
  49. this.GM_setValue = function (key, value) { localStorage[key] = value; return true; };
  50. this.GM_deleteValue = function (key) { return delete localStorage[key]; };
  51. }
  52. } catch (e) { logLibC('GM_set/get error:\n' + e.message); }
  53.  
  54. // global info: used to determine if script can safely run without errors (and also character info)
  55. var charinfodiv = null, levelclass = null, levelclassname = '', charinfoid = null;
  56. if (document.getElementById('CharacterInfo')) { //get general data from the page
  57. charinfodiv = document.getElementById('CharacterInfo');
  58. levelclass = charinfodiv.getElementsByTagName('td')[1];
  59. levelclassname = /Level [0-9]+ (.+)/.exec(levelclass.innerHTML)[1];
  60. charinfoid = charinfodiv.getElementsByTagName('a')[0].href.match(/id=(\d+)$/)[1];
  61. }
  62.  
  63. // custom CSS for script; injected into page
  64. var injectedcss = [
  65. 'span.hptext { font-size: xx-small; color: #ff0099; }',
  66. 'span.hptext2 { font-size: xx-small; color: black; }',
  67. 'tr.petstatus-aplow { background-color: #999999; }',
  68. 'tr.petstatus-apcritical { background-color: #999933; }',
  69. 'tr.petstatus-mpsurplus { background-color: #cc6677; color:black; }',
  70. 'tr.petstatus-nextpet td { border-top: 2px solid black; border-bottom: 2px solid black; }',
  71. 'tr.petstatus-nextpet2 td { border-top: 1px solid black; border-bottom: 1px solid black; }',
  72. 'tr.recipe-complete { background-color: #dddddd; }',
  73. 'tr.recipe-partial { background-color: #bbbbbb; }',
  74. 'tr.recipe-empty { background-color: #999999; color: #444444; }',
  75. 'span.component-rare { color: #882255; }',
  76. 'span.component-uncommon { color: #117733; }',
  77. 'span.component-common { }',
  78. 'td.component-rare { color: #882255; font-weight: bold; }',
  79. 'td.component-uncommon { color: #117733; font-weight: bold; }',
  80. 'td.component-common { font-weight: bold; }',
  81. 'span.component-undefined { font-style: italic; }',
  82. 'span.component-fixed { font-style: italic; }',
  83. 'span.immutable { font-weight: bold; }',
  84. 'span.match-safe { background-color: #ddcc77; }',
  85. 'span.match-inventory { background-color: #88ccee; }',
  86. 'span.safeEmpty { color: #000000; font-weight: bold; }',
  87. 'span.safeLow { background-color: #cc6677; }',
  88. 'span.safeMid { background-color: #ddcc77; }',
  89. 'span.safeHigh { background-color: #88ccee; }',
  90. 'input.retrieveSafe { background: none; border: none; color: blue; text-decoration: underline; cursor: pointer; margin: 0; padding: 0; display: inline; }',
  91. 'tr.recipe-complete.completionlevel-inventory { background-color: #44aa99; }',
  92. 'tr.recipe-complete.completionlevel-safe { background-color: #999933; }',
  93. 'option.safeitem-rare { background-color: #882255; color: #ffffff; }',
  94. 'option.safeitem-uncommon { background-color: #117733; color: #ffffff; }',
  95. 'option.safeitem-common { background-color: #999999; color: #ffffff; }',
  96. 'tr.recipe-partial form { display: none; }',
  97. 'td.recipename { width: 99px; }',
  98. 'td.recipelist { width: 170px; }',
  99. 'td.summarycell { width: 26px; }',
  100. 'td.summarycell.summary-empty { background-color: #777777; }',
  101. 'td.match-safe { background-color: #ddcc77; }',
  102. 'td.match-inventory { background-color: #88ccee; }',
  103. 'td.MageHealthBar { background-repeat: no-repeat; background-position: left bottom; margin-bottom: 0px; position: relative; top: -10px; background-image: url(data:image/gif;base64,R0lGODlhAQAFAIABAACZAP%2F%2F%2FywAAAAAAQAFAAACAoRdADs%3D); }',
  104. 'td.MageHealthBar2 { background-repeat: no-repeat; background-position: left bottom; margin-bottom:0px; background-image: url(data:image/gif;base64,R0lGODdhAQAFAIACAAAAAP8AACwAAAAAAQAFAEACAoxdADs=); }',
  105. '.bar{ line-height=: 1px; height: 5px; display: inline-block; margin: 0 0 0 0; padding: 0 0 0 0; position: absolute; top: 20px; #bottom: 1px; background-color: #ff0000; left: 0px; }',
  106. '.bar2{ line-height=: 1px; height: 5px; display: inline-block; margin: 0 0 0 0; padding: 0 0 0 0; position: absolute; top: 20px; #bottom: 1px; background-color: #00ff00; left: 0px; }',
  107. '.numberdiv{ display: inline-block; padding: 0 0 0 0; margin: 0 0 0 0; width: 20px; position: relative; }',
  108. 'td.MageNoWrap { white-space: nowrap ! important; }',
  109. 'a.MageHide { display: none ! important; }',
  110. 'img.MageBarBck { position: absolute; left: 1; top: 18; display: inline; z-index: 0 }',
  111. 'img.MageBar { position: absolute; left: 1; top: 18; display: inline; z-index: 1 }',
  112. 'div.MagePetHit { font-size: smaller; color: lightcoral ! important; padding-left: 4em; }',
  113. 'div.MagePetHitMe { font-size: smaller; color: red ! important; padding-left: 4em; }',
  114. 'div.MagePetKill { font-size: smaller; color: crimson; padding-left: 4em; }',
  115. 'div.MagePetMiss { font-size: smaller; color: #CAA083; padding-left: 4em; }',
  116. 'div.MagePetHealOthers { font-size: smaller; color: #5050aa; padding-left: 4em; }',
  117. 'div.MagePetHealMe { font-size: smaller; color: #0808aa; padding-left: 4em; }',
  118. 'div.MagePetRejuv { font-size: smaller; color: #aa50aa; padding-left: 4em; }',
  119. 'div.MagePetDespawn { font-size: smaller; color: #ff8000; padding-left: 4em;}',
  120. 'div.MageAttackHit { color: red ! important; }',
  121. 'div.MageAttackMiss { color: deeppink; }',
  122. 'div.MageAttacked { color: red; font-weight: 600; }',
  123. 'div.MageAttackedbyEnvironment { color: red; font-weight: 100; }',
  124. 'div.MageHealed { color: #0808aa; }',
  125. 'div.MageAchievement { font-size: smaller; padding-left: 4em; }',
  126. 'span.MageAchievementColour { color: #aa0000; }',
  127. 'div.MageSpeech { color: dodgerblue; }',
  128. 'div.MageAction { color: #aaaaff; }',
  129. 'div.MageWhisper{ color: MediumOrchid; }',
  130. 'span.MageMe{ color: darkblue; }',
  131. 'div.MageReceivedSomething{ color: #ff8040; }',
  132. 'div.MageCraft{ color: #8d4f9d; }',
  133. 'div.MageSearchNothing{ color: #8c8c55; }',
  134. 'div.MageSearchYay{ color: #8c8c00; }',
  135. 'span.libshadows{ color: #dd0101; font-weight: bold; }',
  136. 'span.liblights{ color: dodgerblue; }',
  137. 'span.liblightsoff{ color: #bf4020; }',
  138. 'div.libfaded { color: red; }',
  139. 'div.libkill { color: red; font-weight: 600; }',
  140. 'div.libgave { color: #bf4020; }',
  141. 'div.libsummon { color: red; ! important; }',
  142. 'div.libfort { color: #9900ff; font-size: smaller; }',
  143. 'span.libgood { color: #11dd11; }',
  144. 'span.libbad { color: #dd1111; }',
  145. 'table.libc-settingtable { width: 100%; }',
  146. 'tr.libc-settingrow { background-color: #dddddd; }',
  147. 'td.libc-settingname { width: 20px; }',
  148. 'td.libc-settinglist { width: 90px; }',
  149. 'span.libc-settingspan { background-color: #bbbbbb; border: 1px dotted black; }',
  150. 'input.liblink { background: none; border: none; color: white; text-decoration: underline; cursor: pointer; margin: 0; padding: 0; display: inline; }',
  151. 'span.char { white-space: nowrap; }'
  152. ];
  153. // now inject CSS
  154. addGlobalStyle(injectedcss);
  155.  
  156.  
  157. //#############################################################################
  158. // tweak 0: highlight shadows from outside buildings
  159. function showhilights() {
  160. var locSnapShot, desc, descString, descdiv, descMatch, puforms, targetdesc, pucount;
  161. locSnapShot = document.evaluate("//td[@valign='top']/b/u", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  162.  
  163. if (locSnapShot.snapshotLength === 0) { return; } // sentinel exit condition; no location description to find
  164.  
  165. desc = locSnapShot.snapshotItem(0).parentElement.nextElementSibling.nextElementSibling.nextSibling; //please don't cringe
  166.  
  167. // lights and shadows
  168. descString = desc.textContent;
  169. descdiv = document.createElement('div');
  170. descdiv.id = 'libdesc';
  171. descMatch = descString.match(/(([\s\S]+)?(The lights are on inside the building|The building lights illuminate the area|The building windows are dark|The building lights are off|The lights inside the building appear to be off|The lights seem to be off throughout the neighorhood|The building is dark\. In fact, the lights seem to be off all throughout the neighorhood|The lights seem to be off throughout the neighorhood))?(([\s\S]+)?(There are several shadows moving in the windows|The occasional shadow can be glimpsed moving in the windows))?([\s\S]+)/);
  172. if (descMatch) { desctextmatches(descdiv, descMatch); }
  173. else { descdiv.appendChild(document.createTextNode(descString)); } // if no match, just put the string back where it was
  174.  
  175. // targets/items set up in location
  176. if (getSetting('hilights-extra-targets') == 'true') { //try to add number of targets
  177. puforms = document.evaluate("//form[@name='pickup']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  178. targetdesc = document.createElement('span');
  179. if (puforms.snapshotLength == 1) {
  180. pucount = puforms.snapshotItem(0).getElementsByTagName('select')[0].length;
  181. targetdesc.className = 'liblights'; //reusing dodgerblue css
  182. if (pucount == 1) { targetdesc.appendChild(document.createTextNode(' There is an item on the floor.'));
  183. } else { targetdesc.appendChild(document.createTextNode(' There are '+pucount+' items on the floor.')); }
  184. }
  185. descdiv.appendChild(targetdesc);
  186. desc.parentNode.insertBefore(descdiv, desc);
  187. desc.remove(); // we copied things, remove (redundant) original
  188. }
  189. }
  190.  
  191. function desctextmatches(descdiv, descMatch) {
  192. // boilerplate code for lights/shadows
  193. var lights, shadows;
  194.  
  195. //descMatch group elements:
  196. //2: firsttext 3: lightstatus 4:(toss) 5: middletext 6: shadowstatus 7: lasttext
  197.  
  198. descdiv.appendChild(document.createTextNode(descMatch[2])); // first text as node
  199.  
  200. // lights
  201. if (descMatch[3]) {
  202. lights = document.createElement('span');
  203. // create span: if lights enabled, set light class to on/off; else just make it text
  204. if (getSetting('hilights-extra-lights') == 'true') {
  205. if (descMatch[3].match(/(The lights are on inside the building|The building lights illuminate the area)/)) {
  206. lights.className = 'liblights';
  207. }
  208. else if (descMatch[3].match(/(The building windows are dark|The building lights are off|The lights inside the building appear to be off|The lights seem to be off throughout the neighorhood|The building is dark\. In fact, the lights seem to be off all throughout the neighorhood|The lights seem to be off throughout the neighorhood)/)) {
  209. lights.className = 'liblightsoff';
  210. }
  211. }
  212. lights.appendChild(document.createTextNode(descMatch[3]));
  213. descdiv.appendChild(lights);
  214. }
  215.  
  216. if (descMatch[5]) { descdiv.appendChild(document.createTextNode(descMatch[5])); } // middle text
  217.  
  218. // shadows
  219. if (descMatch[6]) {
  220. shadows = document.createElement('span');
  221. if (getSetting('hilights-extra-shadow') == 'true') { shadows.className = 'libshadows'; }
  222. shadows.appendChild(document.createTextNode(descMatch[6]));
  223. descdiv.appendChild(shadows);
  224. }
  225.  
  226. descdiv.appendChild(document.createTextNode(descMatch[7]));
  227. }
  228.  
  229.  
  230. //#############################################################################
  231. // tweak 1: sort people by alliances and health, print health
  232. function sortpeople() {
  233. var peoplematch = /There (is|are) (\d+) other (person|people) here, (.*?>)\./.exec(document.documentElement.getElementsByTagName('body')[0].innerHTML);
  234. var ppl, person, i, len, count, h;
  235. var sorts = getSortTypes();
  236. var sort1 = sorts[0], sort2 = sorts[1];
  237. var sortRev1 = (getSetting('sortpeople-extra-reverse1') == 'true');
  238. var sortRev2 = (getSetting('sortpeople-extra-reverse2') == 'true');
  239. var showhp = (getSetting('sortpeople-extra-showhp') == 'true');
  240. var allyneutral = (getSetting('sortpeople-extra-neutrals') == 'true');
  241. var showpetmaster = (getSetting('sortpeople-extra-petmaster') == 'true');
  242. var sortfield = {'total':'hp', 'percent':'hp_percent', 'downtotal':'hp_down', 'level':'level'};
  243. var people = [[],[]];
  244. if (!peoplematch) { return; }
  245. logLibC('sortpeople runtime: '+peoplematch[2], verbose=true);
  246. if (peoplematch[2] === 0) { return; }
  247. ppl = peoplematch[4].substring(1, peoplematch[4].length - 1).split('>, <');
  248. len = ppl.length;
  249. if (len != parseInt(peoplematch[2])) { logLibC('Count fails to match peoplematch count'); return; }
  250. for (i = 0; i < len; i++) {
  251. person = createSortPerson(ppl[i], allyneutral);
  252. if (person['sorttype'] === 0) { people[0].push(person); }
  253. else { people[1].push(person); }
  254. }
  255.  
  256. // sort people here
  257. if ( sortfield.hasOwnProperty(sort1) ) {
  258. people[0].sort( sort_by( sortfield[sort1], sortRev1) );
  259. }
  260. // implicit else: don't sort, already in alphabetical order
  261. if ( sortfield.hasOwnProperty(sort2) ) {
  262. people[1].sort( sort_by( sortfield[sort2], sortRev2) );
  263. } // again implied else --> don't sort
  264.  
  265. // now format for display
  266. count = (people[0].length + people[1].length);
  267. if (count != parseInt(peoplematch[2])) { logLibC('Count fails to match peoplematch count'); return; } // just in case
  268. if (count == 1) {
  269. h = '<p id="chars_desc">There is 1 other person here.</p>\n';
  270. } else {
  271. h = '<p id="chars_desc">There are ' + count + ' other people here.</p>\n';
  272. }
  273.  
  274. h += createSortedPeopleHTML(people[0], 'victims', showhp);
  275. h += createSortedPeopleHTML(people[1], 'friends', showhp);
  276.  
  277. h = '<div id="other_chars">' + h + '</div>';
  278. document.documentElement.innerHTML = document.documentElement.innerHTML.replace(peoplematch[0], h);
  279.  
  280. // Optional showpetmaster trigger
  281. if (showpetmaster) { petmaster(); }
  282. }
  283.  
  284. function createSortedPeopleHTML(people, id, showhp) {
  285. var retHTML = '<p id="'+id+'">';
  286. var len = people.length, i;
  287. if (len === 0) { return ''; } // catch for no people
  288. for (i = 0; i < len; i++) {
  289. retHTML += createSortedPersonHTML(people[i],showhp);
  290. }
  291. return retHTML.substring(0, retHTML.length - 2) + '.</p>'; // remove the trailing joiner and replace with close of par
  292. }
  293.  
  294. function createSortedPersonHTML(person, showhp) {
  295. var hptext = '';
  296. if (showhp && person['hp_visible']) {
  297. hptext = (person['hp_down'] === 0) ? '<span class=hptext2>' : '<span class=hptext>';
  298. hptext += '+' + person['hp'];
  299. if (person['hp_down'] > 0) { hptext += '-' + person['hp_down']; }
  300. }
  301. return '<span class="char" id="char_' + person['id'] + '"><' + person['html'] + '>' + hptext + '</span></span>, ';
  302. }
  303.  
  304. function getSortTypes() {
  305. var sort1 = getSortSingle( getSetting('sortpeople-extra-sort1') ),
  306. sort2 = getSortSingle( getSetting('sortpeople-extra-sort2') );
  307. setSetting('sortpeople-extra-sort1', sort1);
  308. setSetting('sortpeople-extra-sort2', sort2);
  309. return [sort1,sort2];
  310. }
  311.  
  312. function getSortSingle(sortStr) {
  313. var sorts = ['normal', 'percent', 'total', 'downtotal', 'level']; // valid types of sorts; normal is alphabetical
  314. if (sorts.indexOf(sortStr) == -1) { return 'normal'; }
  315. return sortStr
  316. }
  317.  
  318. function createSortPerson(ppl, allyneutral) {
  319. // creates an object of the character from the html
  320. var retPerson = { 'hp':0,'hp_down':0 }; // defaults
  321. var p = /a class="(faction|ally|friendly|neutral|enemy|hostile)" href="javascript:SelectItem\('target_id','(\d+)'\)">(.+)<\/a> \(<a href="modules.php\?name=Game&amp;op=character&amp;id=\d+">(\d*)<\/a>\)(<img title="Hidden" (?:height="12" width="12" src="images\/g\/status\/Hiding.^ png"|src="images\/g\/status\/Hiding.png" height="12" width="12")>)?<img( title="(\d+)\/(\d+) hit points")?.+?src="images\/g\/HealthBar_([1-4]).gif"/.exec(ppl);
  322. // ^ this is the magic to match a person ^
  323.  
  324. if (p[1] == 'enemy' || p[1] == 'hostile') {
  325. retPerson['sorttype'] = 0;
  326. }
  327. else if (p[1] == 'neutral' && allyneutral === false) {
  328. retPerson['sorttype'] = 0;
  329. }
  330. else {
  331. retPerson['sorttype'] = 1;
  332. }
  333. retPerson['politics'] = p[1]; // specific info for later scripting expansion
  334. retPerson['html'] = ppl;
  335. retPerson['id'] = p[2];
  336. retPerson['level'] = p[4];
  337.  
  338. if (p[6]) {
  339. // if char has first aid and can see hp vals
  340. retPerson['hp_visible'] = true;
  341. retPerson['hp'] = parseInt(p[7]);
  342. retPerson['hp_down'] = (parseInt(p[8])-parseInt(p[7]));
  343. retPerson['hp_percent'] = (parseInt(p[7])/parseInt(p[8])) * 100;
  344. } else {
  345. // char doesn't have first aid; only sees 10,11-50,51-99,100% hp totals
  346. retPerson['hp_visible'] = false;
  347. switch (parseInt(p[9])) {
  348. case 1:
  349. retPerson['hp_percent'] = 100; break;
  350. case 2:
  351. retPerson['hp_percent'] = 99; break;
  352. case 3:
  353. retPerson['hp_percent'] = 50; break;
  354. case 4:
  355. retPerson['hp_percent'] = 10; break;
  356. }
  357. }
  358. return retPerson;
  359. }
  360.  
  361. var sort_by = function(field, reverse=false) {
  362. var key = function (obj) { return obj[field] };
  363. return function(a, b) {
  364. var A = key(a), B = key(b);
  365. return ( (A < B) ? -1 : ((A > B) ? 1 : 0) ) * [1,-1][+!!reverse];
  366. }
  367. }
  368.  
  369. function petmaster() {
  370. var characters = document.evaluate("//span[@class='char']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  371. if (characters.snapshotLength === 0) { return; }
  372. var eachchar, i, len;
  373. len = characters.snapshotLength;
  374. for (i = 0; i < len; i++) {
  375. eachchar = characters.snapshotItem(i).firstElementChild;
  376. eachchar.addEventListener('mouseover', ehighlightpet);
  377. eachchar.addEventListener('mouseout', eunhighlightpet);
  378. }
  379. }
  380.  
  381. function ehighlightpet(e) {
  382. var charname = e.target.textContent.replace(/\s$/g, ''); //rtrim
  383. var searchstring = "Master: " + charname;
  384. searchstring = "//a[@title='" + searchstring + "']";
  385. var theirpets = document.evaluate(searchstring, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  386. var i, len;
  387. len = theirpets.snapshotLength;
  388. if (len >= 1) { e.target.title = String(len) + " Pets"; }
  389. for (i = 0; i < len; i++) { theirpets.snapshotItem(i).style.color = 'blue'; }
  390. }
  391.  
  392. function eunhighlightpet(e) {
  393. var charname = e.target.textContent.replace(/\s$/g, '');
  394. var searchstring = "Master: " + charname;
  395. searchstring = "//a[@title='" + searchstring + "']";
  396. var theirpets = document.evaluate(searchstring, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  397. var i, len;
  398. len = theirpets.snapshotLength;
  399. for (i = 0; i < len; i++) { theirpets.snapshotItem(i).style.color = ''; }
  400. }
  401.  
  402.  
  403. //#############################################################################
  404. // tweak 2: Button Safeties
  405. function hiddentoggle(e) {
  406. var targetbutton = e.target.nextElementSibling;
  407. if (e.target.checked) { targetbutton.style.visibility = 'visible'; }
  408. else { targetbutton.style.visibility = 'hidden'; }
  409. }
  410.  
  411. function disabletoggle(e) {
  412. var targetbutton = e.target.nextElementSibling;
  413. if (e.target.checked) { targetbutton.disabled = false; }
  414. else { targetbutton.disabled = true; }
  415. }
  416.  
  417. function createDisableButton(btn) {
  418. if (!btn.hasAttribute('confirmflag')) {
  419. btn.setAttribute('confirmflag', 1);
  420. var box = document.createElement('input');
  421. box.type = 'checkbox'; box.checked = false;
  422. box.addEventListener('click', disabletoggle, false);
  423. var acell = btn.parentNode;
  424. acell.insertBefore(box,btn);
  425. btn.disabled = true;
  426. }
  427. }
  428.  
  429. function createHiddenButton(btn) {
  430. if (!btn.hasAttribute('confirmflag')) {
  431. btn.setAttribute('confirmflag', 1);
  432. var box = document.createElement('input');
  433. box.type = 'checkbox'; box.checked = false;
  434. box.addEventListener('click', hiddentoggle, false);
  435. btn.textContent = btn.textContent.charAt(0);
  436. var acell = btn.parentNode;
  437. acell.className = 'MageNoWrap'; acell.align = 'left';
  438. acell.insertBefore(box,btn);
  439. btn.style.visibility = 'hidden';
  440. }
  441. }
  442.  
  443. function createDoubleClickButton(btn) {
  444. var newbutton = document.createElement('a');
  445. var doubleClick = (function () {
  446. var count = 1;
  447. return function(e) {
  448. if (count > 1) {
  449. e.target.nextElementSibling.click();
  450. logLibC('clicking '+e.target.nextElementSibling.href, verbose=true);
  451. }
  452. count += 1;
  453. if (e.target.textContent.slice(-1) === '?') {
  454. // cut off trailing '?''
  455. e.target.textContent = e.target.textContent.slice(0,-1);
  456. }
  457. }
  458. }());
  459. newbutton.addEventListener('click', doubleClick, false); // [next].click
  460. if (btn.textContent == 'Load Spellwand') { newbutton.textContent = 'Load'; } // make it short and sweet
  461. else { newbutton.textContent = btn.textContent; } // portability
  462. newbutton.textContent += '?';
  463. newbutton.className = 'item_use'; // hoping this works
  464. btn.parentNode.insertBefore(newbutton, btn);
  465. btn.style.visibility = 'hidden';
  466. }
  467.  
  468. function safebuttons() {
  469. var loc = location + '';
  470. if (!charinfoid && getGlobalSetting('safebuttons') == 'true') {
  471. if (loc.match(/buyskills|executepurchase|faction&do=view|character/)) { safetyButtons("//input[@type='submit']", 'disable'); }
  472. }
  473. if (charinfoid) {
  474. if (getSetting('safety-extra-drop') == 'true') { safetyButtons("//a[@class='item_drop']", 'hide'); }
  475. if (getSetting('safety-extra-learn') == 'true') { safetyButtons("//a[@class='item_use' and starts-with(text(), 'Learn')]", 'hide'); }
  476. if (getSetting('safety-extra-craft') == 'true') { safetyButtons("//form[@name='craft']/input[@type='submit' and @value='Craft']", 'disable'); safetyButtons("//form[@name='skill_craft']/input[@type='submit']", 'disable'); }
  477. if (getSetting('safety-extra-repair') == 'true') { safetyButtons("//form[@name='repair']/input[@type='submit' and @value='Repair']", 'disable'); }
  478. if (getSetting('safety-extra-revoke') == 'true') { safetyButtons("//form[@name='stronghold']/input[@name='action' and @value='revoke']/../input[@type='submit']", 'disable'); }
  479. if (getSetting('safety-extra-loadwand') == 'true') { safetyButtons("//a[@class='item_use' and starts-with(text(), 'Load')]", 'wand'); }
  480. if (getSetting('safety-extra-speech') == 'true') { safebuttons_speech(); }
  481. if (getSetting('safety-extra-blessing') == 'true') { safetyButtons("//form[@name='skilluse']/input[@type='submit' and @value='Use Blessing of Inspiration (5 AP, 10 MP)']", 'disable'); }
  482. if (getSetting('safety-extra-wisp') == 'true') { safetyButtons("//form[@name='skilluse']/input[@type='submit' and @value='Deactivate Wisp Form (0 AP)']", 'disable'); }
  483. if (getSetting('safety-extra-well') == 'true') { safetyButtons("//form[@name='skilluse']/input[@type='submit' and @value='Open Arcane Well (8 AP, 15 MP)']", 'disable'); }
  484. if (getSetting('safety-extra-well') == 'true') { safetyButtons("//form[@name='skilluse']/input[@type='submit' and @value='Open Arcane Well (10 AP, 20 MP)']", 'disable'); }
  485. if (getSetting('safety-extra-mark') == 'true') { safetyButtons("//form[@name='skilluse']/input[@type='submit' and @value='Create Nexal Mark (1 AP, 10 MP)']", 'disable'); }
  486. if (getSetting('safety-extra-mark') == 'true') { safetyButtons("//form[@name='skilluse']/input[@type='submit' and @value='Create Nexal Mark (1 AP, 5 MP)']", 'disable'); }
  487. if (getSetting('safety-extra-hself') == 'true') { safetyButtons("//form[@name='skilluse']/input[@type='submit' and @value='Heal Self (1 AP, 6 MP)']", 'disable'); }
  488. }
  489. }
  490.  
  491. function safetyButtons(xPathStr, operation) {
  492. var buttons, elementButton, len, i;
  493. buttons = document.evaluate(xPathStr, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  494. if (buttons.snapshotLength === 0) { return; }
  495. len = buttons.snapshotLength;
  496. for (i = 0; i < len; i++) {
  497. elementButton = buttons.snapshotItem(i);
  498. if (operation == 'disable') { createDisableButton(elementButton); }
  499. else if (operation == 'hide') { createHiddenButton(elementButton); }
  500. else if (operation == 'wand') { createDoubleClickButton(elementButton); }
  501. }
  502. }
  503.  
  504. function enableSpeechForm(e) {
  505. var button = e.target.previousElementSibling;
  506. if (e.target.value !== '') { button.disabled = false; }
  507. else { button.disabled = true; }
  508. }
  509.  
  510. function safebuttons_speech() {
  511. var form, temp, len, i;
  512. form = document.evaluate("//form[@name='speak' or @name='bullhorn']/input[@type='submit']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  513. len = form.snapshotLength;
  514. if (len === 0) { return; }
  515. for (i = 0; i < len; i++) {
  516. temp = form.snapshotItem(i);
  517. temp.disabled = true;
  518. temp = document.evaluate("input[@type='text']", temp.parentNode, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  519. temp.snapshotItem(0).addEventListener('input', enableSpeechForm, false);
  520. }
  521. }
  522.  
  523.  
  524. //#############################################################################
  525. // tweak 3: Thin Bars for Full Health and Mana
  526. function tweakbars() {
  527. var i, len, healthbarimages, manabarimages;
  528. healthbarimages = document.evaluate("//img[@src='images/g/HealthBar_1.gif']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  529. len = healthbarimages.snapshotLength;
  530. for (i = 0; i < len; i++) { healthbarimages.snapshotItem(i).width = '2'; }
  531. manabarimages = document.evaluate("//img[@src='images/g/MagicBar_1.gif']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  532. len = manabarimages.snapshotLength;
  533. for (i = 0; i < len; i++) { manabarimages.snapshotItem(i).width = '2'; }
  534. }
  535.  
  536.  
  537. //#############################################################################
  538. // tweak 4: Color Message History (and make message box bigger and resizable)
  539. function messagehistory() {
  540. var messages = document.getElementById('Messages');
  541. if (!messages) { return; }
  542. var loc = location + '', i, len, mm, j, lenm, ret_val;
  543. var mhistory = messages.previousElementSibling;
  544. if (mhistory && !(mhistory.innerHTML.match(/This Week/))) {
  545. if ((loc.match(/name=Game(&op=connect)?$/)) && (timesCharExist(messages.innerHTML, '\n') > 13)) { messages.style.height = '250px'; }
  546. messages.style.resize = 'vertical';
  547. }
  548. var alonglist = messages.innerHTML.split('\n');
  549. mm = messagematchers();
  550. len = alonglist.length;
  551. for (i = 0; i < len; i++) {
  552. alonglist[i] = alonglist[i].replace(/( a)(\(?(n)\)?( [AEIOUaeiou])|\(?n\)?( [^AEIOUaeiou]))/g,'$1$3$4$5');
  553. lenm = mm.length;
  554. for (j = 0; j < lenm; j++) {
  555. ret_val = messagereplacer(alonglist[i], mm[j].m, mm[j].o, mm[j].e);
  556. if (ret_val) { alonglist[i] = ret_val; break; }
  557. }
  558. alonglist[i] = alonglist[i].replace(/(Your weapon was damaged during the attack\. It is now less effective!)/, "<b><u>$1</u></b>"); //yes this is a hack to always emphasise even when another matcher catches the line
  559. alonglist[i] = alonglist[i].replace(/(\'\')/g, "'");//replace '' with '
  560. }
  561. messages.innerHTML = alonglist.join('');
  562. }
  563.  
  564. function messagematchers() {
  565. // generates a list of message matchers and returns it
  566. // list of objects of trace {m:MATCH EXPRESSION, o:OPERATION, e:EXTRA(padding/other)}
  567. var mm = [
  568. {m:/(- (\(\d+ times\) )?You attack .* with your .* and hit for .* damage\..*)<br>/, o:'p', e:'MageAttackHit'},
  569. {m:/(- (\(\d+ times\) )?You attack the (door|ward|fortifications) with .+)<br>/, o:'p', e:'libfort'},
  570. {m:/(- (\(\d+ times\) )?You attack .* with your .* and miss\..*)<br>/, o:'p', e:'MageAttackMiss'},
  571. {m:/(- (\(\d+ times\) )?You summon (dark forces and attempt to steal magic points from (.+)\. You meet with success and drain|the Curse of Blood and touch (.+), inflicting the curse|your inner hatred to inflict the Agony Curse and touch (.+), inflicting the curse).+)<br>/, o:'p', e:'MageAttackHit'},
  572. {m:/-( (\(\d+ times\) )?.* attacked you with .*)<br>/, o:'p', e:'MageAttacked'},
  573. {m:/-( (\(\d+ times\) )?.*( Your action causes you to| You| you|The Agony Curse causes you to) take( an additional)? \d+ (point(s)? of( \b[a-z]+\b)? damage|damage)(.|!)?.*)<br>/, o:'p', e:'MageAttackedbyEnvironment'},
  574. {m:/(- (\(\d+ times\) )?Your pet, .* has been rejuvenated. You spent \d+ Magic Point.*)<br>/, o:'p', e:'MagePetRejuv'},
  575. {m:/(- (\(\d+ times\) )?.* belonging to .*, (healed you|has funneled life energy).*)<br>/, o:'p', e:'MagePetHealMe'},
  576. {m:/(- (\(\d+ times\) )?.*, belonging to .*, healed .* for \d+ hit point.*)<br>/, o:'p', e:'MagePetHealOthers'},
  577. {m:/(- (\(\d+ times\) )?Your pet .* and hit for .*)<br>/, o:'p', e:'MagePetHit'},
  578. {m:/(- (\(\d+ times\) )?((Shambling|Infectious|Rotting) Zombie|.*, belonging to .*,) attacked you and hit for .*)<br>/, o:'p', e:'MagePetHitMe'},
  579. {m:/(- (\(\d+ times\) )?(Your pet |[^,].*, belonging to).*, killing them!.*)<br>/, o:'p', e:'MagePetKill'},
  580. {m:/(- (\(\d+ times\) )?(Your pet |[^,].*, belonging to|(Shambling|Infectious|Rotting) Zombie).* and missed.*)<br>/, o:'p', e:'MagePetMiss'},
  581. {m:/-( (\(\d+ times\) )?.* attacked your pet,.*and hit for .*)<br>/, o:'p', e:'MagePetHit'},
  582. {m:/(- (\(\d+ times\) )?.* attacked your pet,.* killing it!.*)<br>/, o:'p', e:'MagePetKill'},
  583. {m:/(- (\(\d+ times\) )?.* attacked .* killing it!.*)<br>/, o:'p', e:'MagePetKill'},
  584. {m:/(- (\(\d+ times\) )?.* attacked your pet.* and missed.*)<br>/, o:'p', e:'MagePetMiss'},
  585. {m:/(- (\(\d+ times\) )?.*, belonging to .*, was killed by a defensive aura projected by .*)<br>/, o:'p', e:'MagePetKill'},
  586. {m:/(- (\(\d+ times\) )?(Your pet .*|.*, belonging to .*,|.*, a .*|\b\w+\b|Will-O-Wisp) has despawned.*)<br>/, o:'p', e:'MagePetDespawn'},
  587. {m:/((- (\(\d+ times\) )?)<font color="#DD0000">(<b>.*<\/b>)<\/font>(.*))<br>/, o:'r', e:'<div class="MageAchievement">$2<span class="MageAchievementColour">$4</span>$5</div>'},
  588. {m:/(- (\(\d+ times\) )?)([^,].*) (whispered to you, saying).(\".*)<br>/, o:'r', e:"<div class='MageSpeech'>$1 $3<span class='MageMe'> $4, </span>$5</div>"},
  589. {m:/(- (\(\d+ times\) )?).*(Someone used a bullhorn to say: )(\'.*\')(.*)<br>/, o:'p', e:'MageMe'},
  590. {m:/(- (\(\d+ times\) )?)(You say, )(\".*)<br>/, o:'r', e:"<div class='MageSpeech'>$1<span class='MageMe'>$3</span>$4</div>"},
  591. {m:/(- (\(\d+ times\) )?)(You whisper, )(\".*)<br>/, o:'r', e:"<div class='MageSpeech'>$1<span class='MageMe'>$3</span>$4</div>"},
  592. {m:/(- (\(\d+ times\) )?[^,].* (said|say), \".*)<br>/, o:'p', e:'MageSpeech'},
  593. {m:/(- (\(\d+ times\) )?[^,].* (whispered to you|whisper), saying \".*)<br>/, o:'p', e:'MageSpeech'},
  594. {m:/(- (\(\d+ times\) )?.+ attacked .+ with .+, killing (him|her).*)<br>/, o:'p', e:'libkill'},
  595. {m:/-( (\(\d+ times\) )?[^,].* gave you a.*)<br>/, o:'p', e:'MageReceivedSomething'},
  596. {m:/-( (\(\d+ times\) )?You give your .*)<br>/, o:'p', e:'libgave'},
  597. {m:/(- (\(\d+ times\) )?You call upon your crafting skills.*)<br>/, o:'p', e:'MageCraft'},
  598. {m:/(- (\(\d+ times\) )?You search and find nothing.*)<br>/, o:'p', e:'MageSearchNothing'},
  599. {m:/(- (\(\d+ times\) )?You search and find a.*)<br>/, o:'p', e:'MageSearchYay'},
  600. {m:/(- (\(\d+ times\) )?You step (inside |outside of ).*)<br>/, o:'p', e:'libgave'},
  601. {m:/(- (\(\d+ times\) )?.*(You heal yourself and|healed you. You) gain \d+ hit point(s)?.*)<br>/, o:'p', e:'MageHealed'},
  602. {m:/(- (\(\d+ times\) )?.*(heal|healed) you for \d+ point(s)? of damage.*)<br>/, o:'p', e:'MageHealed'},
  603. {m:/(- (\(\d+ times\) )?.*(You|You use the .* to) heal .* for \d+ point(s)? of damage.*)<br>/, o:'p', e:'MageHealed'},
  604. {m:/(- (\(\d+ times\) )?.*You use your surgeon skills to tend to .* and heal them for \d+ point(s)? of damage.*)<br>/, o:'p', e:'MageHealed'},
  605. {m:/(- (\(\d+ times\) )?.*You place a Stygian Bone Leech on the skin of .* \d+ point(s)? of damage.*)<br>/, o:'p', e:'MageHealed'},
  606. {m:/(- (\(\d+ times\) )?.*You feel the effects of .+ fade.*)<br>/, o:'p', e:'libfaded'},
  607. {m:/(- (\(\d+ times\) )?.* summoned a .*)<br>/, o:'p', e:'libsummon'},
  608. {m:/(- (\(\d+ times\) )?.* (suddenly appeared out of thin air\.|disappeared from view\.).*)<br>/, o:'p', e:'libsummon'},
  609. {m:/(- (\(\d+ times\) )?.* spoke words of mystic power and traced eldritch shapes into the air. A burst of warmth rushed through the area as they finished the incantation.*)<br>/, o:'p', e:'libsummon'},
  610. {m:/(- (\(\d+ times\) )?)([^<>]*?)( \u201C.+\u201D)(.*)<br>/, o:'r', e:"<div class='MageSpeech'>$1<span class='MageMe'>$3</span>$4<span class='MageMe'>$5</span></div>"},
  611. {m:/(- (\(\d+ times\) )?)(.*?)( \u0022.+\u0022)(.*)<br>/, o:'r', e:"<div class='MageSpeech'>$1<span class='MageMe'>$3</span>$4<span class='MageMe'>$5</span></div>"},
  612. {m:/(- (\(\d+ times\) )?)([^<>]*?)( \u2018.+\u2019)(.*)<br>/, o:'r', e:"<div class='MageSpeech'>$1<span class='MageMe'>$3</span>$4<span class='MageMe'>$5</span></div>"}
  613. ];
  614. return mm;
  615. }
  616.  
  617. function messagereplacer(liststring, match, operation, extra) {
  618. if (liststring.match(match)) { //operation 'p' for 'padding' the message with a div of class $extra, operation 'r' for 'replacing' a string with $extra
  619. if (operation == 'p') { liststring = "<div class='"+extra+"'>"+liststring+"</div>"; }
  620. else if (operation == 'r') { liststring = liststring.replace(match, extra); }
  621. return liststring;
  622. }
  623. return false;
  624. }
  625.  
  626.  
  627. //#############################################################################
  628. // tweak 5: Tweak the weapon selection to print Raw DPA and shorten details
  629.  
  630. // display damage per action
  631. function wpSDPA (option) {
  632. var test = option.innerHTML.match(/(\d+) dmg[^0-9]*(-?\d+)% to hit$/);
  633. if (test) { option.innerHTML += '(dpa:'+test[1]*Math.min(Math.max(test[2],1),99)/100+')'; }
  634. }
  635.  
  636. // display shorter damage/to-hit chance
  637. function wpSDMG (option) {
  638. if (option.innerHTML.match(/ - (\d+) dmg.?, (\d+)% to hit/)) { option.innerHTML = option.innerHTML.replace(/ - (\d+) dmg.?, (\d+)% to hit/, '-$1/$2%'); }
  639. }
  640.  
  641. // display shortened shot amounts
  642. function wpSSHOTS (option) {
  643. if (option.innerHTML.match(/\((\d+) shots\)/)) { option.innerHTML = option.innerHTML.replace(/\((\d+) shots\)/, '\($1s\)'); }
  644. }
  645.  
  646. // display shortened spellgem names (and special touch attacks?)
  647. function wpSGEM (option) {
  648. if (option.innerHTML.match(/^Spellgem/)) { option.innerHTML = option.innerHTML.replace(/^Spellgem/, 'Gem'); }
  649. if (option.innerHTML.match(/(-( 0 dmg| ), -?(\d+)% to hit$)/)) { option.innerHTML = option.innerHTML.replace(/(-( [0-5] dmg| ), -?(\d+)% to hit$)/, ''); }
  650. if (option.innerHTML.match(/(Glyph of )/)) { option.innerHTML = option.innerHTML.replace(/(Glyph of )/, ''); }
  651. }
  652.  
  653. // display shortened weapon quality
  654. function wpSQUAL (option) {
  655. var qualityLevel = {'pristine':'+Q5+', 'good':'+Q4+', 'average':'=Q3=', 'worn':'-Q2-', 'broken':'-Q1-', 'destroyed':'-Q0-'};
  656. var test = option.innerHTML.match(/ \((pristine|good|average|worn|broken|destroyed)\) /);
  657. if (test) { option.innerHTML = option.innerHTML.replace(/ \((pristine|good|average|worn|broken|destroyed)\) /, qualityLevel[test[1]]); }
  658. }
  659.  
  660. // display shortened enchant/magical status
  661. function wpSMAG (option) {
  662. if (option.innerHTML.match(/\((magical|enchanted)\)/)) { option.innerHTML = option.innerHTML.replace(/\((magical|enchanted)\)/, '(mag)'); }
  663. }
  664.  
  665. function weaponpane() {
  666. var weaponboxes = document.evaluate("//select[@name='attacking_with_item_id']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  667. if (weaponboxes.snapshotLength < 1) { return; }
  668. var item, weaponboxoptions, i, j, jlen, ilen;
  669. var sDPA = (getSetting('weaponpane-extra-dpa') == 'true');
  670. var sDMG = (getSetting('weaponpane-extra-dmg') == 'true');
  671. var sSHOTS = (getSetting('weaponpane-extra-shots') == 'true');
  672. var sGEM = (getSetting('weaponpane-extra-gem') == 'true');
  673. var sQUAL = (getSetting('weaponpane-extra-quality') == 'true');
  674. var sMAG = (getSetting('weaponpane-extra-magic') == 'true');
  675. jlen = weaponboxes.snapshotLength;
  676. for (j = 0 ; j < jlen; j++) {
  677. item = weaponboxes.snapshotItem(j);
  678. weaponboxoptions = item.getElementsByTagName('option');
  679. ilen = weaponboxoptions.length;
  680. for (i = 0; i < ilen; i++ ) {
  681. if (sDPA) { wpSDPA(weaponboxoptions[i]); }
  682. if (sDMG) { wpSDMG(weaponboxoptions[i]); }
  683. if (sSHOTS) { wpSSHOTS(weaponboxoptions[i]); }
  684. if (sGEM) { wpSGEM(weaponboxoptions[i]); }
  685. if (sQUAL) { wpSQUAL(weaponboxoptions[i]); }
  686. if (sMAG) { wpSMAG(weaponboxoptions[i]); }
  687. }
  688. }
  689. }
  690.  
  691.  
  692. //#############################################################################
  693. // tweak 6: Default Item Pickup to Weapons
  694. function pickupdefaults() {
  695. var i, len, temp, puforms, puform, pubox, puboxopt, pnum, indexArray = [], matchers = ['drink','food','rock','knife','hatchet','misc','null'], priorities = [];
  696. var drinkmatch = /(.+, a(n)? )?(Bottle of .+|Absinthe|Vial of .+)/;
  697. var foodmatch = /(.+, a(n)? )?(Can of .+|Cup of .+|Apple)/;
  698. var rockmatch = /(.+, a(n)? )?Rock/;
  699. var knifematch = /(.+, a(n)? )?Throwing Knife/;
  700. var hatchetmatch = /(.+, a(n)? )?Hatchet/;
  701. puforms = document.evaluate("//form[@name='pickup']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  702. if (puforms.snapshotLength != 1) { return; }
  703. for (i = 0; i < 6; i++) { //currently checks six priorities
  704. temp = getSetting('pickup-extra-priority'+i);
  705. if (matchers.indexOf(temp) == -1) { temp = 'null'; }
  706. setSetting('pickup-extra-priority'+i, temp);
  707. priorities.push(temp);
  708. indexArray.push(-1);
  709. }
  710. puform = puforms.snapshotItem(0);
  711. pubox = puform.lastElementChild;
  712. puboxopt = pubox.getElementsByTagName('option');
  713. len = puboxopt.length;
  714. for (i = 0; i < len; i++) {
  715. temp = puboxopt[i].textContent;
  716. if (temp.match(drinkmatch)) { pnum = priorities.indexOf('drink'); }
  717. else if (temp.match(foodmatch)) { pnum = priorities.indexOf('food'); }
  718. else if (temp.match(rockmatch)) { pnum = priorities.indexOf('rock'); }
  719. else if (temp.match(knifematch)) { pnum = priorities.indexOf('knife'); }
  720. else if (temp.match(hatchetmatch)) { pnum = priorities.indexOf('hatchet'); }
  721. else { pnum = priorities.indexOf('misc'); } //catches all non-matches as misc!
  722. if (pnum != -1 && indexArray[pnum] == -1) {
  723. indexArray[pnum] = i; //set the priority option index to the current setting
  724. }
  725. }
  726. len = indexArray.length;
  727. for (i = 0; i < len; i++) { //now set the selected option to the first index we find
  728. if (indexArray[i] != -1) {
  729. pubox.selectedIndex = indexArray[i];
  730. break;
  731. }
  732. }
  733. }
  734.  
  735.  
  736. //#############################################################################
  737. // tweak 7: Warning Headers
  738. function warningheaders() {
  739. if (!charinfodiv) { return; } // need char info, else quit
  740. var firstfont = charinfodiv.getElementsByTagName('font')[0], secondfont = charinfodiv.getElementsByTagName('font')[1], thirdfont = charinfodiv.getElementsByTagName('font')[2], panetitles = document.getElementsByClassName('panetitle');
  741. var headercolor = '', headertitle = '';
  742. var i, len, temp, moves, lowAP, lowHP;
  743. lowAP = 13; //defaults
  744. if (isNormalInteger(getSetting('warnheaders-extra-ap'))) { lowAP = parseInt(getSetting('warnheaders-extra-ap')); }
  745. setSetting('warnheaders-extra-ap', lowAP);
  746. lowHP = 30; //defaults
  747. if (isNormalInteger(getSetting('warnheaders-extra-hp'))) { lowHP = parseInt(getSetting('warnheaders-extra-hp')); }
  748. setSetting('warnheaders-extra-hp', lowHP);
  749.  
  750. // character/login pane: charinfodiv
  751. if (Number(secondfont.innerHTML.match(/\d+/)) < lowHP) {
  752. secondfont.parentNode.style.border = '3px solid crimson';
  753. secondfont.parentNode.parentNode.parentNode.parentNode.style.border = '2px solid crimson';
  754. secondfont.parentNode.parentNode.title = 'LOW HEALTH';
  755. headercolor = 'crimson'; headertitle = 'LOW HP';
  756. } else if (Number(firstfont.innerHTML.match(/\d+/)) < lowAP) {
  757. firstfont.parentNode.parentNode.style.border = '1px solid #fa8000';
  758. firstfont.parentNode.parentNode.style.borderTop = '3px solid #fa8000';
  759. firstfont.parentNode.parentNode.style.borderBottom = '3px solid #fa8000';
  760. firstfont.parentNode.parentNode.title = 'LOW AP';
  761. headercolor = 'gold'; headertitle = 'LOW AP';
  762. }
  763.  
  764. // the headers/spacers between different game sections
  765. len = panetitles.length;
  766. for (i = 0; i < len; i++) {
  767. temp = panetitles[i];
  768. temp.style.color = headercolor; temp.title = headertitle;
  769. }
  770.  
  771. // move buttons
  772. if (headertitle && getSetting('warnheaders-extra-move') == 'true') {
  773. moves = document.getElementsByName('move');
  774. len = moves.length;
  775. for (i = 0; i < len; i++) {
  776. moves[i].children[1].style.borderColor = 'black';
  777. moves[i].children[1].style.borderStyle = 'dotted';
  778. }
  779. }
  780. }
  781.  
  782.  
  783. //#############################################################################
  784. // tweak 8: Save Forms
  785. function safestore(name, path) {
  786. var selects = document.evaluate(path, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null), select;
  787. if (selects.snapshotLength === 0) { return; }
  788. select = selects.snapshotItem(0);
  789. var value = select.options[select.selectedIndex].value;
  790. if (value) { setSetting('store-'+name, value); }
  791. }
  792.  
  793. function rememberForm(name, path, selname) {
  794. var select = document.evaluate(path, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  795. var len = select.snapshotLength;
  796. var value, i, sel, button, j, jlen, options;
  797. value = getSetting('store-'+name);
  798. for (i = 0; i < len; i++) {
  799. sel = select.snapshotItem(i);
  800. button = document.evaluate("input[@type='submit']", sel.parentNode, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(0);
  801. button.addEventListener('click', function(e) { var sele = e.target.parentNode[selname]; setSetting('store-'+name, sele.options[sele.selectedIndex].value); }, true);
  802. if (value === null) { continue; } // fall through: no vals defined
  803. options = sel.options;
  804. jlen = options.length;
  805. for (j = 0; j < jlen; j++) { //only if we have a value to search for
  806. if (options[j].value === value) { sel.selectedIndex = j; break; }
  807. }
  808. }
  809. }
  810.  
  811. function saveForms() {
  812. var refresh = document.evaluate("//li[@class='topmenu']/a[text()='Game Map']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  813. var i, len, name, path;
  814. var forms = [ //internal storage name, xpath string, select tag name
  815. ['c1', "//select[@name='powerup']", 'powerup'],
  816. ['c2', "//select[@name='powerup2']", 'powerup2'],
  817. ['precision', "//select[@name='clockwork_precision']", 'clockwork_precision'],
  818. ['prayer', "//select[@name='prayertype']", 'prayertype'],
  819. ['repair', "//form[@name='repair']/select[@name='item']", 'item']
  820. ];
  821. len = forms.length;
  822. for (i = 0; i < len; i++) {
  823. if (getSetting('saveform-extra-'+forms[i][0]) != 'true') { continue; } // skip if disabled
  824. name = forms[i][0]; path = forms[i][1];
  825. rememberForm(name, path, forms[i][2]);
  826. if (refresh.snapshotLength !== 0) {
  827. refresh.snapshotItem(0).addEventListener('click', function(n,p) { return function() { safestore(n, p); }; }(name,path), true);
  828. }
  829. }
  830. }
  831.  
  832.  
  833. //#############################################################################
  834. // tweak 9: Pet Interface Overhaul
  835. function processPetTable() {
  836. var tick = getTick(), minPet = null, minPet2 = null, len,
  837. petRows = document.evaluate("//tr[td[@title='Rename Pet']]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null),
  838. retPets; //defaults
  839.  
  840. // GLOBALS
  841. petCountSurplus = (getSetting('pettweak-extra-surplus') == 'true'), petAPLow = 8, petAPMid = 20;
  842.  
  843. // hack to set default if unset
  844. if (isNormalInteger(getSetting('pettweak-extra-ap-low'))) { petAPLow = parseInt(getSetting('pettweak-extra-ap-low')); }
  845. setSetting('pettweak-extra-ap-low', petAPLow);
  846. if (isNormalInteger(getSetting('pettweak-extra-ap-mid'))) { petAPMid = parseInt(getSetting('pettweak-extra-ap-mid')); }
  847. setSetting('pettweak-extra-ap-mid', petAPMid);
  848. if (petRows.snapshotLength === 0) { return; }
  849.  
  850. len = petRows.snapshotLength;
  851. for (var i = 0; i < len; i++) {
  852. var row = petRows.snapshotItem(i);
  853. if (i === 0) { modifyTable(row); }
  854. retPets = processRow(row, tick, minPet, minPet2, petCountSurplus);
  855. minPet = retPets[0]; minPet2 = retPets[1];
  856. }
  857. minPet.Row.setAttribute('class', minPet.Row.getAttribute('class') + ' petstatus-nextpet');
  858. if (minPet2 !== null) { minPet2.Row.setAttribute('class', minPet2.Row.getAttribute('class') + ' petstatus-nextpet2'); }
  859. }
  860.  
  861. function processRow(row, tick, minPet, minPet2) {
  862. var ap = parseInt(row.cells[2].innerHTML), mp = parseInt(row.cells[3].innerHTML), hp = parseInt(row.cells[4].innerHTML);
  863. if (minPet === null || ap < minPet.AP || (ap == minPet.AP && mp < minPet.MP) || (ap == minPet.AP && mp == minPet.MP && hp < minPet.HP)) { minPet2 = minPet; minPet = { AP:ap, MP:mp, HP:hp, Row:row }; } //stomp through, finding pet with lowest ap, with tie breakers mp and finally hp
  864. else if (minPet2 === null || ap < minPet2.AP || (ap == minPet2.AP && mp < minPet2.MP) || (ap == minPet2.AP && mp == minPet2.MP && hp < minPet2.HP)) { minPet2 = { AP:ap, MP:mp, HP:hp, Row:row }; }
  865. displayDecayTime(row, ap, mp, tick);
  866. setRowClass(row, ap, mp);
  867. modifyStanceForm(row);
  868. return [minPet, minPet2];
  869. }
  870.  
  871. function displayDecayTime(row, ap, mp, tick) {
  872. var timeEmpty = new Date(tick), temp = ap;
  873. if (petCountSurplus && ap > mp) { temp = (ap - mp); }
  874. timeEmpty.setMinutes(tick.getMinutes() + (temp * 15));
  875. row.insertCell(7);
  876. row.cells[7].innerHTML = String(temp / 4)+'h';
  877. row.cells[7].title = 'Local: ' + timeEmpty.toTimeString().substring(0,5);
  878. }
  879.  
  880. function modifyTable(row) {
  881. var table = row.parentNode.parentNode;
  882. table.style.width = table.offsetWidth - 4;
  883. table.rows[1].insertCell(7);
  884. table.rows[1].cells[7].innerHTML = 'Decay';
  885. }
  886.  
  887. function setRowClass(row, ap, mp) {
  888. var rowClass = '', temp = ap;
  889. if (petCountSurplus) { temp = (ap - mp); }
  890. if (ap < mp) { rowClass += ' petstatus-mpsurplus'; }
  891. else if (temp <= petAPLow) { rowClass += ' petstatus-apcritical'; }
  892. else if (temp <= petAPMid) { rowClass += ' petstatus-aplow'; }
  893. row.setAttribute('class', rowClass);
  894. }
  895.  
  896. function modifyStanceForm(row) {
  897. var stanceSubmit = document.evaluate(".//input[@type='submit']", row.cells[5], null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(0);
  898. stanceSubmit.style.display = 'none';
  899. var stanceSelect = document.evaluate('.//select',row.cells[5],null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0);
  900. stanceSelect.onchange = function() { this.form.submit(); };
  901. }
  902.  
  903. function getTick() {
  904. var tick = new Date();
  905. tick.setMinutes(tick.getMinutes() - (tick.getMinutes() % 15));
  906. tick.setSeconds(0);
  907. return tick;
  908. }
  909.  
  910.  
  911. //#############################################################################
  912. // tweak 10: Alchemy Interface Overhaul
  913. function alchemytweak() {
  914. character = parseCharacterInfo();
  915. if (character) {
  916. var panes = document.evaluate("//tbody[tr/td/div[@class='panetitle']='Recipe Tracker']/tr[last()]/td",document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);
  917. components = getComponentDictionary();
  918. if (getSetting('alchemytweak-extra-alwayshilight') == 'true' || panes.snapshotLength == 1) { tempSI = parseSafeItems(); inventoryItems = parseInventoryItems(); }
  919. if (panes.snapshotLength != 1) { return; }
  920. alchemyShowCount = (getSetting('alchemytweak-extra-count-show') == 'true');
  921. alchemySafeButton = (getSetting('alchemytweak-extra-safebutton') == 'true');
  922. alchemyLowCount = 6;
  923. if (isNormalInteger(getSetting('alchemytweak-extra-count-low'))) { alchemyLowCount = parseInt(getSetting('alchemytweak-extra-count-low')); }
  924. setSetting('alchemytweak-extra-count-low', alchemyLowCount); //hack to set default if unset
  925. alchemyMidCount = 12;
  926. if (isNormalInteger(getSetting('alchemytweak-extra-count-mid'))) { alchemyMidCount = parseInt(getSetting('alchemytweak-extra-count-mid')); }
  927. setSetting('alchemytweak-extra-count-mid', alchemyMidCount);
  928. alchemySuppressHilight = (getSetting('alchemytweak-extra-suppress') == 'true');
  929. alchemySuppressLW = (getSetting('alchemytweak-extra-suppresslw') == 'true');
  930. var panetitle = document.evaluate("//tbody[tr/td/div[@class='panetitle']='Recipe Tracker']/tr/td/div[@class='panetitle']",document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0);
  931. recipePane = panes.snapshotItem(0);
  932. shortNames = getShortNames();
  933. fixedComponents = getFixedComponents();
  934. //tempSI = parseSafeItems(); //moved to start
  935. safeItems = tempSI[0]; safeStatus = tempSI[1];
  936. //inventoryItems = parseInventoryItems();
  937. parseRecipes(character, recipePane);
  938. setToggleAll(panetitle);
  939. setToggleListeners();
  940. }
  941. }
  942.  
  943. function parseRecipes(character, recipePane) {
  944. var complete = [], partial = [], empty = [], i, htmltable;
  945. var recipes = recipePane.innerHTML.split('<br>');
  946. for (i = 0; i < recipes.length; i++) {
  947. if (recipes[i] === '') { continue; }
  948. if (recipes[i].match(/,/)) {
  949. if (recipes[i].match(/incomplete$/)) { partial.push(formatRecipe(recipes[i], 'recipe-partial')); }
  950. else { complete.push(formatRecipe(recipes[i], 'recipe-complete')); }
  951. }
  952. else { empty.push(formatRecipe(recipes[i], 'recipe-empty')); }
  953. }
  954. htmltable = '<table>';
  955. for (i = 0; i < complete.length; i++) { htmltable += complete[i]; }
  956. for (i = 0; i < partial.length; i++) { htmltable += partial[i]; }
  957. for (i = 0; i < empty.length; i++) { htmltable += empty[i]; }
  958. htmltable += createComponentHelper();
  959. htmltable += createHelpRow('assistant', 'Alchemy Assistant', '- Reformats recipes into collapsable/expandable tabs, and sorts by completion<br>- Hilights available components: brown for safe/footlocker, blue for inventory<br>- Uses friendly colours for colour-blind individuals<br>- Hilights entire recipes if all components are available; brown for safe/footlocker, blue for inventory. Does not handle multiples of components in inventory<br>- Adds a brew button next to recipe name if able to brew, and warns if there is a stygian bone-leech in inventory<br>- Colours components according to rarity:<br>-- Common - Black<br>-- Uncommon - Green<br>-- Rare - Red<br>- Bolds non-transmutable components (soul and blood ice)<br>- Adds colours to safe and footlocker according to component rarity, if recipe pane is open<br>- Indicates which component (if any) is preserved, or what factor is preventing it<br>- Displays quantity of potions in safe, colour coded depending on amounts<br>- Adds an "s" after an available component to retrieve from safe, and "f" to retrieve from footlocker<br>- Adds buttons underneath a full recipe name to place or retrieve that potion to or from the faction safe.');
  960. htmltable += createHelpRow('saved', 'Saved Components','- The item that is preserved will be the last one listed alphabetically for that recipe<br>- The recipe cannot require more than one of any specific component. No component in the recipe can be (x2) or (x3)<br>- A Stygian Bone Leech cannot be in the player\'s inventory, unless that it is the component that would be preserved<br>-Code of Efficiency never preserves an already saved component. Code of Efficiency also does not trigger as often on saving recipes.<br>-Please note that these rules are based on experimentation and are not wholly accurate. Sometimes recipes with Bone Leeches save components, sometimes they do not.');
  961. htmltable += createHelpRow('quality', 'Research and Recipe Quality', "- Never research into 'Any' recipe for fear of sudden death. Always research into a specific potion recipe.<br>- Do not research a recipe with a component that you already know is in it for fear of sudden death.<br>-- In example: If research reveals a chunk of steel is required in a recipe, do not use chunks of steel to research that same recipe. Doing so often results in explosive failure.<br>- Recipes that include Soul or Blood Ice that are not Cold or Unholy respectively should be reset as soon as possible, as a general rule. Demonic alchemists may reconsider this.<br>- Any recipe that does not save a rare (or rarest possible component) can be reset at the alchemist's leisure.<br>- Sprigs of Nightshade are the most easily saved rare component.");
  962. htmltable += createHelpRow('fixed', 'Fixed Components', "- <a href='http://nexusclash.windrunner.mx/wiki/index.php/Scraps_of_paper'>Complete List of Fixed Components</a><br>- Fundamentally Inferior Recipes:<br>- Blood Ice, Unholy<br>- Soul Ice, Cold<br>- Stygian Bone Leech, Regeneration<br>- If a recipe otherwise has Blood or Soul Ice, or a Bone Leech, it is best to reset it<br>- Blood Ice never saved. Best saves for Cold and Regen are Soul and Leech respectively");
  963. htmltable += '</table>';
  964. recipePane.innerHTML = htmltable;
  965. }
  966.  
  967. function createHelpRow(name, title, helpString) {
  968. var rowClass, helpRow, fullDisplay = 'none', summaryDisplay = 'table-row';
  969. if (getSetting('alchemy-toggle-' + name + 'help') == 'full') { fullDisplay = 'table-row'; summaryDisplay = 'none'; }
  970. rowClass = 'recipe-partial completionlevel-short';
  971. helpRow = "<tr id='recipe-"+name+"help-full' class='" + rowClass + "' style='display:" + fullDisplay + "'><td valign='top' class='recipename'><a class='toggleLink' id='toggle-"+name+"help-full'><img src='/images/g/inf/close.gif'/></a>Help: "+title+"</td><td colspan='6' class='recipelist'>" + helpString + "</td>";
  972. helpRow += "<tr id='recipe-"+name+"help-summary' class='" + rowClass + "' style='display:" + summaryDisplay + "'><td valign='top' class='recipename'><a class='toggleLink' id='toggle-"+name+"help-summary'><img src='http://nexusclash.com/images/g/inf/open.gif'/></a>H:"+title+"</td></tr>";
  973. return helpRow;
  974. }
  975.  
  976. function createComponentHelper() {
  977. var cRow, rowClass, fullDisplay = 'none', summaryDisplay = 'table-row', comp, cString, cssClass, safeRetrieve, count;
  978. if (getSetting('alchemy-toggle-componentshelp') == 'full') { fullDisplay = 'table-row'; summaryDisplay = 'none'; }
  979. rowClass = 'recipe-partial completionlevel-short'; cString = '';
  980. for (comp in components[character.Class]) {
  981. if (!components[character.Class].hasOwnProperty(comp)) { continue; }
  982. safeRetrieve = null, count = '';
  983. cssClass = 'component-' + components[character.Class][comp];
  984. if (safeItems[comp]) {
  985. cssClass += ' match-safe';
  986. safeRetrieve = getSafeItem(comp);
  987. count = safeItems[comp].count;
  988. cString += "<form name='footlockergrab' action='modules.php?name=Game&amp;op=" + safeRetrieve[1] + "' method='POST' style='display:block'><input type='hidden' name='action' value='retrieve'><input type='hidden' name='item' value='" + safeRetrieve[0] + "'><span class='" + cssClass + "'>" + comp + "</span> (" + count + ") <input type='submit' class='retrieveSafe' title='From "+safeRetrieve[1]+"' value='" + safeRetrieve[1].charAt(0) + "'></form>";
  989. } else { cString += "<span class='" + cssClass + "'>" + comp + '</span><br/>'; }
  990. }
  991. cRow = "<tr id='recipe-componentshelp-full' class='" + rowClass + "' style='display:" + fullDisplay + "'><td valign='top' class='recipename'><a class='toggleLink' id='toggle-componentshelp-full'><img src='/images/g/inf/close.gif'/></a>Component Dictionary</td><td colspan='6' class='recipelist'>" + cString + "</td>";
  992. cRow += "<tr id='recipe-componentshelp-summary' class='" + rowClass + "' style='display:" + summaryDisplay + "'><td valign='top' class='recipename'><a class='toggleLink' id='toggle-componentshelp-summary'><img src='http://nexusclash.com/images/g/inf/open.gif'/></a>Comp Dict</td></tr>";
  993. return cRow;
  994. }
  995.  
  996. function formatRecipe(recipe, rowClass) {
  997. var i, len, completionLevel = 'inventory', componentString = '', buttonHtml = '', potionName = '', componentList, recipeComponents, componentCount = 0, inventoryCount = 0, safeCount = 0, preserved = 'saved', safeRetrieve = '', safeRetrieveType = '', safeRetrieveForm = '', safePotionCountSpan = '', safePotionCountShort = '', safePotionCount, retform = '<br>', placeform = '', fullDisplay = 'table-row', summaryDisplay = 'none', shortName, cssClass, component, count, potRetVal, potRetType;
  998. var empty = (rowClass == 'recipe-empty'), partial = (rowClass == 'recipe-partial');
  999. recipe = recipe.replace(/,? *(in)?complete$/, '');
  1000. var recipeMatch = recipe.match(/^.*<b>(Potion of .+)<\/b> *(.*)$/);
  1001. if (!recipeMatch) { return; }
  1002. potionName = recipeMatch[1]; componentList = recipeMatch[2];
  1003. recipeComponents = componentList.split(', ');
  1004. if (!componentList) { recipeComponents = ''; }
  1005. len = recipeComponents.length;
  1006. for (i = 0; i < len; i++) {
  1007. safeRetrieve = '', safeRetrieveForm = '', safeRetrieveType = '';
  1008. count = parseInt(recipeComponents[i].match(/\(x(\d+)\)/)[1]);
  1009. if (count > 1) { preserved = '-count'; }
  1010. component = recipeComponents[i].replace(/ \(x\d+\)$/, '');
  1011. cssClass = 'component-' + components[character.Class][component];
  1012. componentCount += count;
  1013. if (inventoryItems[component]) {
  1014. inventoryCount += count;
  1015. if (!alchemySuppressHilight) { cssClass += ' match-inventory'; } //if suppress is false, then add the css class for matching
  1016. } else if (safeItems[component] && safeItems[component].count >= count) {
  1017. if (!alchemySuppressHilight) {cssClass += ' match-safe'; } //likewise
  1018. safeCount += count; safeRetrieve = getSafeItem(component);
  1019. if (completionLevel == 'inventory') { completionLevel = 'safe'; }
  1020. } else {
  1021. if (safeItems[component]) { safeCount += safeItems[component].count; }
  1022. safeRetrieve = getSafeItem(component); completionLevel = 'short';
  1023. }
  1024. safeRetrieveType = safeRetrieve[1]; safeRetrieve = safeRetrieve[0];
  1025. recipeComponents[i] = recipeComponents[i].replace(/ \(x1\)$/, '');
  1026. recipeComponents[i] = recipeComponents[i].replace(/ /g, '&nbsp;');
  1027. if ( (recipeComponents[i] == 'Stygian Bone Leech') && (i != recipeComponents.length - 1) ) { preserved = '-leech'; }
  1028. if (i == (recipeComponents.length - 1)) { recipeComponents[i] += '('+preserved+')'; }
  1029. if (safeRetrieve && !partial && !empty) {
  1030. componentString += "<form name='footlockergrab' action='modules.php?name=Game&amp;op=" + safeRetrieveType + "' method='POST'><input type='hidden' name='action' value='retrieve'><input type='hidden' name='item' value='" + safeRetrieve + "'><span class='" + cssClass + "'>" + recipeComponents[i] + "</span> <input type='submit' class='retrieveSafe' title='From "+safeRetrieveType+"' value='"+safeRetrieveType.charAt(0)+"'></form>";
  1031. } else {
  1032. componentString += "<span class='" + cssClass + "'>" + recipeComponents[i] + '</span><br/>';
  1033. }
  1034. }
  1035. if (recipeComponents && completionLevel == 'inventory' && preserved == 'saved' && getInvItem('Stygian Bone Leech') && !alchemySuppressLW) { buttonHtml = '<form name="alchemyknown" action="modules.php?name=Game&amp;op=alchemy" method="POST"><input type="hidden" name="potion" value="' + potionName + '"/><input type="submit" title="Leech Warning - Brew Batch" value="w!B!w"/></form>'; }
  1036. else if (recipeComponents && completionLevel == 'inventory') { buttonHtml = '<form name="alchemyknown" action="modules.php?name=Game&amp;op=alchemy" method="POST"><input type="hidden" name="potion" value="' + potionName + '"/><input type="submit" title="Brew Batch" value="-B-"/></form>'; }
  1037. //show safe-stock
  1038. if (alchemyShowCount && safeStatus > 0) {
  1039. if (safeItems[potionName]) { safePotionCount = safeItems[potionName].count; }
  1040. else { safePotionCount = 0; }
  1041. if (safePotionCount === 0) { safePotionCountSpan = "<span class='safeEmpty'>"; }
  1042. else if (safePotionCount < alchemyLowCount) { safePotionCountSpan = "<span class='safeLow'>"; }
  1043. else if (safePotionCount < alchemyMidCount) { safePotionCountSpan = "<span class='safeMid'>"; }
  1044. else { safePotionCountSpan = "<span class='safeHigh'>"; }
  1045. safePotionCountShort = '-' + safePotionCountSpan + safePotionCount + '</span>';
  1046. safePotionCount = '<br>'+ safePotionCountSpan + 'Safe: ' + safePotionCount + '</span>';
  1047. } else { safePotionCountShort = ''; safePotionCount = ''; }
  1048. //add quick place/retrieve buttons
  1049. if (alchemySafeButton && safeStatus > 0) {
  1050. potRetrieve = getSafeItem(potionName);
  1051. invPlace = getInvItem(potionName);
  1052. if (potRetrieve[1] !== '') {
  1053. potRetVal = potRetrieve[0]; potRetType = potRetrieve[1];
  1054. retform = "<form name='footlockergrab' action='modules.php?name=Game&amp;op="+potRetType+"' method='POST' style='display:block'><input type='hidden' name='action' value='retrieve'><input type='hidden' name='item' value='"+potRetVal+"'><input type='submit' class='retrieveSafe' value='Retrieve "+potRetType+"'></form>";
  1055. }
  1056. if (invPlace) { placeform = "<form name='footlockergrab' action='modules.php?name=Game&amp;op=safe' method='POST' style='display:block'><input type='hidden' name='action' value='deposit'><input type='hidden' name='item' value='"+invPlace+"'><input type='submit' class='retrieveSafe' value='Place safe'></form>"; }
  1057. }
  1058. potionName = potionName.replace(/^Potion of (.+)$/, '$1');
  1059. if (getSetting('alchemy-toggle-' + potionName) == 'summary') { fullDisplay = 'none'; summaryDisplay = 'table-row'; }
  1060. shortName = potionName;
  1061. if (shortNames[potionName]) { shortName = shortNames[potionName]; }
  1062. if (empty) {
  1063. componentString = "[<span class='component-fixed'>" + fixedComponents[potionName] + "</span>]";
  1064. }
  1065. if (partial && !componentString.match(fixedComponents[potionName].replace(/ /g, '&nbsp;'))) {
  1066. cssClass = 'component-' + components[character.Class][fixedComponents[potionName]];
  1067. componentString = "[<span class='" + cssClass + " component-fixed'>" + fixedComponents[potionName] + "</span>]<br/>" + componentString;
  1068. }
  1069. rowClass += ' completionlevel-' + completionLevel;
  1070. recipe = recipe.replace(/^.*<b>Potion of (.+)<\/b>.*$/, "<tr id='recipe-$1-full' class='" + rowClass + "' style='display:" + fullDisplay + "'><td valign='top' class='recipename'><a class='toggleLink' id='toggle-" + potionName + "-full'><img src='/images/g/inf/close.gif'/></a> $1" + safePotionCount + "<br>" + buttonHtml + retform + placeform + "</td><td colspan='6' class='recipelist'>" + componentString + "</td></tr>");
  1071. recipe += "<tr id='recipe-" + potionName + "-summary' class='" + rowClass + "' style='display:" + summaryDisplay + "'>";
  1072. recipe += "<td valign='top' class='recipename'><a class='toggleLink' id='toggle-" + potionName + "-summary'><img src='http://nexusclash.com/images/g/inf/open.gif'/></a> " + shortName + safePotionCountShort + "</td>";
  1073. if (partial) {
  1074. for (i = 0; i < componentCount; i++) { recipe += "<td class='summarycell'></td>"; }
  1075. for (i = 0; i < 6 - componentCount; i++) { recipe += "<td class='summarycell summary-empty'></td>"; }
  1076. } else if (empty) { recipe += "<td colspan='6' class='recipelist'></td>"; }
  1077. else {
  1078. for (i = 0; i < inventoryCount; i++) { recipe += "<td class='summarycell match-inventory'></td>"; }
  1079. for (i = 0; i < safeCount; i++) { recipe += "<td class='summarycell match-safe'></td>"; }
  1080. for (i = 0; i < 6 - inventoryCount - safeCount; i++) { recipe += "<td class='summarycell'></td>"; }
  1081. }
  1082. recipe += '</tr>';
  1083. return recipe;
  1084. }
  1085.  
  1086. function getSafeItem(item) {
  1087. var ret_id = '', ret_type = '';
  1088. if (safeItems[item]) {
  1089. if (safeItems[item].safe) { ret_id = safeItems[item].safe; ret_type = 'safe'; }
  1090. else if (safeItems[item].footlocker) { ret_id = safeItems[item].footlocker; ret_type = 'footlocker'; }
  1091. }
  1092. return [ret_id, ret_type];
  1093. }
  1094.  
  1095. function getInvItem(item) {
  1096. if (inventoryItems[item]) { return inventoryItems[item].value; }
  1097. else { return ''; }
  1098. }
  1099.  
  1100. function parseSafeItems() {
  1101. var items = [], len, i, j, safestatus, safeType, safeOptions, componentMatch, componentId, component, count, alchemyItems;
  1102. var safe = document.evaluate("//form[@name='footlockergrab']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1103. safestatus = safe.snapshotLength;
  1104. for (j = 0; j < safestatus; j++) {
  1105. safeType = safe.snapshotItem(j).getAttribute('action').match(/op=([^"]*)/)[1];
  1106. safeOptions = document.evaluate('.//option', safe.snapshotItem(j), null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1107. len = safeOptions.snapshotLength;
  1108. for (i = 0; i < len; i++) {
  1109. //match components
  1110. componentMatch = safeOptions.snapshotItem(i).innerHTML.match(/(.+) \((\d+)\)$/);
  1111. componentId = safeOptions.snapshotItem(i).value;
  1112. component = componentMatch[1]; count = componentMatch[2];
  1113. if (components[character.Class][component]) {
  1114. safeOptions.snapshotItem(i).className = 'safeitem-' + components[character.Class][component];
  1115. }
  1116. if (!items[component]) { items[component] = {}; }
  1117. if (!items[component].count) { items[component].count = parseInt(count); }
  1118. items[component][safeType] = componentId;
  1119. }
  1120. }
  1121. alchemyItems = document.evaluate("//form[@name='alchemyresearch' or @name='alchemytransmute']/select[@name='itemid']/option", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );
  1122. len = alchemyItems.snapshotLength;
  1123. for (i = 0; i < len; i++) {
  1124. if (components[character.Class][alchemyItems.snapshotItem(i).innerHTML]) { alchemyItems.snapshotItem(i).className = 'safeitem-' + components[character.Class][alchemyItems.snapshotItem(i).innerHTML]; }
  1125. }
  1126. return [items, safestatus];
  1127. }
  1128.  
  1129. function parseInventoryItems() {
  1130. var items = [], len, i, component, value;
  1131. var safeOptions = document.evaluate("//form[@name='safestock' or @name='alchemyresearch']/select[@name='item' or @name='itemid']/option",document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);
  1132. len = safeOptions.snapshotLength;
  1133. for (i = 0; i < len; i++) {
  1134. component = safeOptions.snapshotItem(i).innerHTML;
  1135. value = safeOptions.snapshotItem(i).value;
  1136. if (components[character.Class][component]) { safeOptions.snapshotItem(i).className = 'safeitem-' + components[character.Class][component]; }
  1137. if (!items[component]) { items[component] = {}; }
  1138. items[component].count = 1; items[component].value = value;
  1139. }
  1140. return items;
  1141. }
  1142.  
  1143. function parseCharacterInfo() {
  1144. var character = {};
  1145. character.Class = 'Sorcerer'; // = levelclassname; //bugged so that all classes have same corpus
  1146. character.Id = charinfoid;
  1147. return character;
  1148. }
  1149.  
  1150. function setToggle(characterId, recipe, toggleState) {
  1151. setSetting('alchemy-toggle-' + recipe, toggleState);
  1152. var summary = document.getElementById('recipe-' + recipe + '-summary');
  1153. var full = document.getElementById('recipe-' + recipe + '-full');
  1154. if (toggleState == 'summary') { full.style.display = 'none'; summary.style.display = 'table-row'; }
  1155. else { full.style.display = 'table-row'; summary.style.display = 'none'; }
  1156. }
  1157.  
  1158. function setToggleListeners() {
  1159. var len, i, link;
  1160. var toggleLinks = document.evaluate("//a[@class='toggleLink']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1161. len = toggleLinks.snapshotLength;
  1162. for (i = 0; i < len; i++) {
  1163. link = toggleLinks.snapshotItem(i);
  1164. setToggleListener(link);
  1165. }
  1166. }
  1167.  
  1168. function setToggleListener(link) {
  1169. var linkMatch = link.id.match(/toggle-(.+)-(full|summary)/);
  1170. var potion = linkMatch[1];
  1171. var toggleType = linkMatch[2];
  1172. link.addEventListener('click', function() { setToggle(character.Id, potion, (toggleType == 'full') ? 'summary' : 'full'); }, false);
  1173. }
  1174.  
  1175. function toggleAll(toggleState) {
  1176. var len, i, link, linkMatch, potion;
  1177. var toggleLinks = document.evaluate("//a[@class='toggleLink']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1178. len = toggleLinks.snapshotLength;
  1179. for (i = 0; i < len; i++) {
  1180. link = toggleLinks.snapshotItem(i);
  1181. linkMatch = link.id.match(/toggle-(.+)-(full|summary)/);
  1182. potion = linkMatch[1];
  1183. setToggle(character.Id, potion, toggleState);
  1184. }
  1185. }
  1186.  
  1187. function setToggleAll(panetitle) {
  1188. var open, close;
  1189. open = document.createElement('input');
  1190. open.type = 'submit'; open.value = '(Open All)'; open.className = 'liblink';
  1191. close = document.createElement('input');
  1192. close.type = 'submit'; close.value = '(Close All)'; close.className = 'liblink';
  1193. open.addEventListener('click', function() { toggleAll('full'); }, false);
  1194. close.addEventListener('click', function() { toggleAll('summary'); }, false);
  1195. panetitle.appendChild(open);
  1196. panetitle.appendChild(close);
  1197. }
  1198.  
  1199. function getComponentDictionary() {
  1200. var components = {};
  1201. components.Sorcerer = {}; //only sorceror components used in breath3
  1202. components.Sorcerer['Bag of Industrial Plastic'] = 'rare';
  1203. components.Sorcerer['Batch of Leather'] = 'rare';
  1204. components.Sorcerer['Batch of Mushrooms'] = 'uncommon';
  1205. components.Sorcerer['Blood Ice'] = 'uncommon immutable';
  1206. components.Sorcerer['Bottle of Holy Water'] = 'common';
  1207. components.Sorcerer['Bottle of Paradise Water'] = 'common';
  1208. components.Sorcerer['Bunch of Daisies'] = 'uncommon';
  1209. components.Sorcerer['Bunch of Lilies'] = 'rare';
  1210. components.Sorcerer['Bunch of Paradise Lilies'] = 'uncommon';
  1211. components.Sorcerer['Chunk of Brass'] = 'uncommon';
  1212. components.Sorcerer['Chunk of Iron'] = 'rare';
  1213. components.Sorcerer['Chunk of Ivory'] = 'uncommon';
  1214. components.Sorcerer['Chunk of Onyx'] = 'rare';
  1215. components.Sorcerer['Chunk of Steel'] = 'common';
  1216. components.Sorcerer['Chunk of Stygian Iron'] = 'common';
  1217. components.Sorcerer['Femur'] = 'common';
  1218. components.Sorcerer['Gold Ingot'] = 'uncommon'; //not rare, in practice
  1219. components.Sorcerer['Handful of Grave Dirt'] = 'common';
  1220. components.Sorcerer['Healing Herb'] = 'uncommon';
  1221. components.Sorcerer['Humerus'] = 'common';
  1222. components.Sorcerer['Lead Brick'] = 'uncommon';
  1223. components.Sorcerer['Patch of Lichen'] = 'uncommon';
  1224. components.Sorcerer['Patch of Moss'] = 'uncommon';
  1225. components.Sorcerer['Piece of Stygian Coal'] = 'common';
  1226. components.Sorcerer['Piece of Wood'] = 'common';
  1227. components.Sorcerer['Rose'] = 'common';
  1228. components.Sorcerer['Silver Ingot'] = 'uncommon';
  1229. components.Sorcerer['Skull'] = 'common';
  1230. components.Sorcerer['Small Bottle of Gunpowder'] = 'rare';
  1231. components.Sorcerer['Soul Ice'] = 'uncommon immutable';
  1232. components.Sorcerer['Spool of Copper Wire'] = 'rare';
  1233. components.Sorcerer['Sprig of Nightshade'] = 'rare';
  1234. components.Sorcerer['Stygian Bone Leech'] = 'common';
  1235. return components;
  1236. }
  1237.  
  1238. function getShortNames() {
  1239. var shortNames = {};
  1240. shortNames['Acid Affinity'] = 'Acid';
  1241. shortNames['Cold Affinity'] = 'Cold';
  1242. shortNames['Combat Clarity'] = 'CC';
  1243. shortNames['Death Affinity'] = 'Death';
  1244. shortNames['Electricity Affinity'] = 'Electric';
  1245. shortNames['Fire Affinity'] = 'Fire';
  1246. shortNames['Extended Invisibility'] = 'XI';
  1247. shortNames['Greater Invulnerability'] = 'GI';
  1248. shortNames['Holy Affinity'] = 'Holy';
  1249. shortNames['Invulnerability'] = 'I';
  1250. shortNames['Lesser Invulnerability'] = 'LI';
  1251. shortNames['Magic Recovery'] = 'MR';
  1252. shortNames['Planar Protection'] = 'PP';
  1253. shortNames['Regeneration'] = 'Regen';
  1254. shortNames['Unholy Affinity'] = 'Unholy';
  1255. shortNames['Water-Breathing'] = 'Wtr Brth';
  1256. return shortNames;
  1257. }
  1258.  
  1259. function getFixedComponents() {
  1260. var fixedComponents = {};
  1261. fixedComponents['Extended Invisibility'] = 'Small Bottle of Gunpowder';
  1262. fixedComponents['Magic Recovery'] = 'Chunk of Onyx';
  1263. fixedComponents['Greater Invulnerability'] = 'Chunk of Iron';
  1264. fixedComponents['Combat Clarity'] = 'Gold Ingot';
  1265. fixedComponents['Death Affinity'] = 'Sprig of Nightshade';
  1266. fixedComponents['Strength'] = 'Bag of Industrial Plastic';
  1267. fixedComponents['Electricity Affinity'] = 'Spool of Copper Wire';
  1268. fixedComponents['Flying'] = 'Silver Ingot';
  1269. fixedComponents['Regeneration'] = 'Stygian Bone Leech';
  1270. fixedComponents['Lesser Invulnerability'] = 'Batch of Leather';
  1271. fixedComponents['Water-Breathing'] = 'Bunch of Lilies';
  1272. fixedComponents['Acid Affinity'] = 'Patch of Lichen';
  1273. fixedComponents['Holy Affinity'] = 'Bunch of Paradise Lilies';
  1274. fixedComponents['Invisibility'] = 'Batch of Mushrooms';
  1275. fixedComponents['Unholy Affinity'] = 'Blood Ice';
  1276. fixedComponents['Invulnerability'] = 'Lead Brick';
  1277. fixedComponents['Cold Affinity'] = 'Soul Ice';
  1278. fixedComponents['Healing'] = 'Skull';
  1279. fixedComponents['Planar Protection'] = 'Handful of Grave Dirt';
  1280. fixedComponents['Fire Affinity'] = 'Chunk of Brass';
  1281. return fixedComponents;
  1282. }
  1283.  
  1284.  
  1285. //#############################################################################
  1286. // tweak 11: Access Keys
  1287. function addAccessKey(extra, evalstr) {
  1288. var form = document.evaluate(evalstr, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1289. var keys = ['null','B','C','E','F','G','J','K','L','N','O','Q','R','T','U','V','W','X','Y','Z','!','"','£','@','#','$','%','^','&','*','(',')'];
  1290. var aKey = getSetting('accesskeys-extra-'+extra);
  1291. if (keys.indexOf(aKey) == -1) { aKey = 'null'; }
  1292. setSetting('accesskeys-extra-'+extra, aKey);
  1293. if (form.snapshotLength > 0) { form.snapshotItem(0).accessKey = aKey; }
  1294. }
  1295.  
  1296. function accesskeys() {
  1297. if (getSetting('accesskeys-extra-heal') != 'null') { addAccessKey('heal', "//form/input[@name='heal_type']/../input[@type='submit']"); }
  1298. if (getSetting('accesskeys-extra-fort') != 'null') { addAccessKey('fort', "//form[@name='fortificationattack']/input[@type='submit']"); }
  1299. if (getSetting('accesskeys-extra-pickup') != 'null') { addAccessKey('pickup', "//form[@name='pickup']/input[@type='submit']"); }
  1300. if (getSetting('accesskeys-extra-door') != 'null') { addAccessKey('door', "//form[@name='doorenter']/input[@type='submit']"); }
  1301. if (getSetting('accesskeys-extra-recap') != 'null') { addAccessKey('recap', "//form[@name='flag_retrieval']/input[@type='submit']"); }
  1302. }
  1303.  
  1304.  
  1305. //#############################################################################
  1306. // tweak 12: Pet Targetting
  1307. function pettarget() {
  1308. var len, i, local, idnum;
  1309. var petlinks = document.evaluate("//a[starts-with(@href,'modules.php?name=Game&op=view_pet&id=')]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1310. len = petlinks.snapshotLength;
  1311. for (i = 0; i < len; i++) {
  1312. local = petlinks.snapshotItem(i);
  1313. idnum = local.href.match('.+id=([0-9]+)')[1];
  1314. local.href = "javascript:SelectItem('target_id'," + idnum + ")";
  1315. }
  1316. }
  1317.  
  1318.  
  1319. //#############################################################################
  1320. // tweak 13: Remove Gem Colours
  1321. function removecolours() {
  1322. var factionsafe = document.evaluate("//form[@name='footlockergrab']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1323. if (factionsafe.snapshotLength === 0) { return; }
  1324. var selElem = factionsafe.snapshotItem(0).lastElementChild,
  1325. tmpAry = [], len = selElem.options.length, i;
  1326. for (i = 0; i < len; i++) {
  1327. tmpAry[i] = [];
  1328. tmpAry[i][0] = selElem.options[i].text.replace(/Small [A-Za-z]+ Gem -/,'Spellgem -');
  1329. tmpAry[i][1] = selElem.options[i].value;
  1330. tmpAry[i][2] = selElem.options[i].selected;
  1331. tmpAry[i][3] = selElem.options[i].className;
  1332. }
  1333. tmpAry.sort(function (a,b) {//this needed to ignore case and leading numbers
  1334. var a=a[0].match(/([A-Za-z-,0-9 ]+)/)[1];
  1335. var b=b[0].match(/([A-Za-z-,0-9 ]+)/)[1];
  1336. return a<b?-1:b<a?1:0;
  1337. });
  1338. len = tmpAry.length;
  1339. for (i = 0; i < len; i++) {
  1340. selElem.options[i].text = tmpAry[i][0];
  1341. selElem.options[i].value = tmpAry[i][1];
  1342. selElem.options[i].selected = tmpAry[i][2];
  1343. selElem.options[i].className = tmpAry[i][3];
  1344. }
  1345. }
  1346.  
  1347.  
  1348. //#############################################################################
  1349. // tweak 14: Faction Census
  1350. function factioncensus() {
  1351. var loc = location + '';
  1352. var ranks, census, ranksrow, rcell, rdiv;
  1353. if (!loc.match(/faction&do=roster/)) { return; }
  1354. ranks = document.evaluate("//table/tbody/tr[th='Character']/..", document, null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1355. if (ranks.snapshotLength != 1) { logLibC('census failed to find ranks'); return; }
  1356. census = (ranks.snapshotItem(0).childElementCount - 1);
  1357. if (census === 0) { return; }
  1358. ranksrow = document.evaluate("//div/table/tbody/tr[td='Renown']", document, null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1359. rcell = ranksrow.snapshotItem(0).children[1];
  1360. rdiv = document.createElement('div');
  1361. rdiv.appendChild(document.createTextNode(census + ' Persons'));
  1362. rcell.appendChild(rdiv);
  1363. }
  1364.  
  1365.  
  1366. //#############################################################################
  1367. // tweak 15: Inventory Tweaks
  1368. function invFastReload(invTBody) {
  1369. var invReload, len, i, item;
  1370. invReload = document.evaluate("//tr[td/a/text()='Reload' or td/a[starts-with(.,'Charge')]]", invTBody, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1371. len = invReload.snapshotLength;
  1372. for (i = 0; i < len; i++) {
  1373. item = invReload.snapshotItem(i);
  1374. invTBody.insertBefore(item, invTBody.firstElementChild.nextElementSibling.nextElementSibling.nextElementSibling);
  1375. }
  1376. }
  1377.  
  1378. function invHideItems(invTBody) {
  1379. var invHead, hidestate='table-row', len, i, hidebutton;
  1380. invHead = document.evaluate("//th[starts-with(.,'Item')]", invTBody, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1381. if (invHead.snapshotLength === 0) { return; }
  1382. if (getSetting('inventory-toggle-hide') != 'table-row') { hidestate = 'none'; }
  1383. setSetting('inventory-toggle-hide', hidestate);
  1384. hidebutton = document.createElement('a');
  1385. hidebutton.className = 'item_use';
  1386. if (hidestate == 'none') { hidebutton.textContent = 'Show'; }
  1387. else { hidebutton.textContent = 'Hide'; }
  1388. hidebutton.addEventListener('click', function(e) { inventory_toggle(e); }, false);
  1389. invHead.snapshotItem(0).nextElementSibling.appendChild(hidebutton);
  1390. len = invTBody.children.length;
  1391. for (i = 0; i < len; i++) {
  1392. if (invTBody.children[i].children[3] && invTBody.children[i].children[3].textContent == '0' && document.evaluate("a[text()='Manabite']", invTBody.children[i].children[1], null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength === 0) {
  1393. invTBody.children[i].className = 'libhideclothes';
  1394. invTBody.children[i].style.display = hidestate;
  1395. }
  1396. }
  1397. }
  1398.  
  1399. function invShortItems(invTBody) {
  1400. var invHead, len, i, temp, test;
  1401. var qualityLevel = {'pristine':'+Q5', 'good':'+Q4', 'average':'=Q3', 'worn':'-Q2', 'broken':'-Q1', 'destroyed':'-Q0'};
  1402. invHead = document.evaluate("//tr[@bgcolor='#eeeeee' or @bgcolor='#ffffff']", invTBody, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1403. len = invHead.snapshotLength;
  1404. if (len === 0) { return; }
  1405. for (i = 0; i < len; i++) {
  1406. temp = invHead.snapshotItem(i).children[0];
  1407. // shorter item names for classifications
  1408. if (temp.innerHTML.match(/^(Bottle of|Bunch of|Can of|Chunk of|Dose of|Pair of|Piece of|Potion of|Set of|Slice of|Suit of) /)) { temp.innerHTML = temp.innerHTML.replace(/^(Bottle of|Bunch of|Can of|Chunk of|Dose of|Pair of|Piece of|Potion of|Set of|Slice of|Suit of) /, ''); }
  1409.  
  1410. // enchanted/magical shortening
  1411. if (temp.innerHTML.match(/\((enchanted|magical)\)/)) { temp.innerHTML = temp.innerHTML.replace(/\((enchanted|magical)\)/, '(mag)'); }
  1412.  
  1413. // shorten spellgems
  1414. if (temp.innerHTML.match(/( Spellgem,)/)) { temp.innerHTML = temp.innerHTML.replace(/( Spellgem,)/, ','); }
  1415.  
  1416. // remove glyph extra start
  1417. if (temp.innerHTML.match(/(Glyph of )/)) { temp.innerHTML = temp.innerHTML.replace(/(Glyph of )/, ''); }
  1418.  
  1419. // Q5 system and (#s) for shots
  1420. if (getSetting('inventory-extra-shorter') == 'true') {
  1421. if (temp.innerHTML.match(/\((\d+) (shots|charges)\)/)) { temp.innerHTML = temp.innerHTML.replace(/\((\d+) (shots|charges)\)/, '\($1s\)'); }
  1422.  
  1423. test = temp.innerHTML.match(/\((pristine|good|average|worn|broken|destroyed)\)/);
  1424. if (test) { temp.innerHTML = temp.innerHTML.replace(/\((pristine|good|average|worn|broken|destroyed)\)/, '('+qualityLevel[test[1]]+')'); }
  1425. }
  1426. }
  1427. }
  1428.  
  1429. function invContextBtns(invTBody) {
  1430. var invHead, invRows, len, i, temp, iid, contextbtn, option, setting, sidx = 0;
  1431. var contextopts = [['give','Give'],['safe','Safe'],['foot','Locker'],['null','None']];
  1432. setting = getSetting('inventory-extra-contextselect');
  1433. invRows = document.evaluate("//tr[@bgcolor='#eeeeee' or @bgcolor='#ffffff']", invTBody, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1434. invHead = document.evaluate("//th[starts-with(.,'Item')]", invTBody, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1435. len = invRows.snapshotLength;
  1436. if (len === 0 || invHead.snapshotLength === 0) { return; }
  1437. for (i = 0; i < len; i++) {
  1438. temp = invRows.snapshotItem(i);
  1439. if (!temp.children[4].innerHTML.match('.+item=([0-9]+)')) { continue; }
  1440. iid = temp.children[4].innerHTML.match('.+item=([0-9]+)')[1];
  1441. contextbtn = document.createElement('a'); contextbtn.className = 'liblink';
  1442. contextbtn.textContent = '(-) '; contextbtn.id = 'context-'+iid;
  1443. contextbtn.title = 'Context Use Button';
  1444. if (setting == 'safe' || setting == 'give' || setting == 'foot') {
  1445. contextbtn.style.display = 'inline';
  1446. } else { contextbtn.style.display = 'none'; }
  1447. temp.children[0].insertBefore(contextbtn, temp.children[0].childNodes[0]);
  1448. contextbtn.addEventListener('click', function(e) { inventory_context_use(e); }, false);
  1449. }
  1450. invHead = invHead.snapshotItem(0);
  1451. temp = document.createElement('select');
  1452. temp.id = 'context-select'; temp.title = 'Select Context Button Action';
  1453. len = contextopts.length;
  1454. for (i = 0; i < len; i++) {
  1455. if (contextopts[i][0] == setting) { sidx = i; }
  1456. option = document.createElement('option');
  1457. option.value = contextopts[i][0]; option.text = contextopts[i][1];
  1458. temp.add(option);
  1459. }
  1460. temp.selectedIndex = sidx;
  1461. temp.addEventListener('change', function(e) { inventory_context_setting(e); }, false);
  1462. invHead.appendChild(document.createTextNode('-Context: '));
  1463. invHead.appendChild(temp);
  1464. }
  1465.  
  1466. function inventory_context_setting(e) {
  1467. var len, i, setting;
  1468. setting = e.target.options[e.target.selectedIndex].value;
  1469. setSetting('inventory-extra-contextselect', setting);
  1470. var contextbtns = document.evaluate("//a[starts-with(@id,'context-')]", e.target.parentNode, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1471. len = contextbtns.snapshotLength; if (len === 0) { return; }
  1472. for (i = 0; i < len; i++) {
  1473. if (setting == 'safe' || setting == 'give' || setting == 'foot') {
  1474. contextbtns.snapshotItem(i).style.display = 'inline';
  1475. } else { contextbtns.snapshotItem(i).style.display = 'none'; }
  1476. }
  1477. }
  1478.  
  1479. function inventory_context_use(e) {
  1480. var iid = e.target.id.match(/[0-9]+/)[0];
  1481. var setting = getSetting('inventory-extra-contextselect');
  1482. var form, temp, i, len, flag=false;
  1483. if (setting == 'give') {
  1484. temp = document.evaluate("//form[@name='give']/select[@name='give_item_id']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1485. } else if (setting == 'safe') {
  1486. temp = document.evaluate("//form[@name='safestock' and contains(@action, 'op=safe')]/select[@name='item']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1487. } else if (setting == 'foot') {
  1488. temp = document.evaluate("//form[@name='safestock' and contains(@action, 'op=footlocker')]/select[@name='item']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1489. } else if (setting == 'null') { return; }
  1490. else { logLibC('skipping invalid inventory context select'); return; }
  1491. if (temp.snapshotLength === 0) { return; }
  1492. temp = temp.snapshotItem(0);
  1493. form = document.evaluate("input[@type='submit']", temp.parentNode, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(0);
  1494. len = temp.options.length;
  1495. for (i = 0; i < len; i++) {
  1496. if (temp.options[i].value == iid) { temp.selectedIndex = i; flag = true; break; }
  1497. }
  1498. if (flag) { form.click(); } //with all luck this should fake a click with properly selected item
  1499. }
  1500.  
  1501. function invColourComponents(invTBody) {
  1502. var invHead, len, i, temp;
  1503. var cdict = getComponentDictionary();
  1504. invHead = document.evaluate("//tr[@bgcolor='#eeeeee' or @bgcolor='#ffffff']", invTBody, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1505. len = invHead.snapshotLength;
  1506. if (len === 0) { return; }
  1507. for (i = 0; i < len; i++) {
  1508. temp = invHead.snapshotItem(i).children[0];
  1509. if (cdict['Sorcerer'][temp.textContent]) { temp.className = 'component-'+cdict['Sorcerer'][temp.textContent]; }
  1510. }
  1511. }
  1512.  
  1513. function inventory() {
  1514. var invTBody = document.evaluate("//b[starts-with(.,'INVENTORY')]/../../../..", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1515. if (invTBody.snapshotLength === 0) { return; }
  1516. invTBody = invTBody.snapshotItem(0);
  1517. if (getSetting('inventory-extra-colourcomponents') == 'true') { invColourComponents(invTBody); } //this must be before shorten
  1518. if (getSetting('inventory-extra-reload') == 'true') { invFastReload(invTBody); }
  1519. if (getSetting('inventory-extra-hide') == 'true') { invHideItems(invTBody); }
  1520. if (getSetting('inventory-extra-short') == 'true') { invShortItems(invTBody); }
  1521. if (getSetting('inventory-extra-context') == 'true') { invContextBtns(invTBody); }
  1522. }
  1523.  
  1524. function inventory_toggle(e) {
  1525. var button, elements, action, len, i;
  1526. button = e.target;
  1527. elements = document.getElementsByClassName('libhideclothes');
  1528. if (button.textContent == 'Show') {
  1529. button.textContent = 'Hide';
  1530. action = 'table-row';
  1531. } else if (button.textContent == 'Hide') {
  1532. button.textContent = 'Show';
  1533. action = 'none';
  1534. }
  1535. setSetting('inventory-toggle-hide', action);
  1536. len = elements.length;
  1537. for (i = 0; i < len; i++) { elements[i].style.display = action; }
  1538. }
  1539.  
  1540.  
  1541. //#############################################################################
  1542. // tweak 16: Default Select Options
  1543. function selectlastopt(evalstr) {
  1544. var setselect, len;
  1545. setselect = document.evaluate(evalstr, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1546. if (setselect.snapshotLength != 1) { return; }
  1547. setselect = setselect.snapshotItem(0);
  1548. len = setselect.length;
  1549. setselect.selectedIndex = len - 1;
  1550. }
  1551.  
  1552. function targetsetupdefaults() { selectlastopt("//form[@name='targetsetup']/select[@name='item']"); }
  1553.  
  1554. function recapdefaults() { selectlastopt("//form[@name='flag_retrieval']/select[@name='standard_id']"); }
  1555.  
  1556. function speakdefaults() {
  1557. var setselect = document.evaluate("//form[@name='speak']/select[@id='speech_target_id']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1558. if (setselect.snapshotLength != 1) { return; }
  1559. setselect = setselect.snapshotItem(0).selectedIndex = 0;
  1560. }
  1561.  
  1562.  
  1563.  
  1564. //#############################################################################
  1565. // Settings, configuration, and variables
  1566. function logLibC(message, verbose=false) {
  1567. if (!libCLogging) { return; } // logging disabled in userscript (top of the file)
  1568. if (verbose && !libCLoggingVerbose) { return; } // verbose logging not enabled
  1569. console.log('[LibC] [ver:'+versionStr+']: '+message);
  1570. }
  1571.  
  1572. function getSetting(settingname) {
  1573. if (charinfoid) { settingname = 'libc-' + charinfoid + '-' + settingname; }
  1574. else { logLibC('Error getSetting for '+settingname); return null; }
  1575. return String(GM_getValue(settingname, null));
  1576. }
  1577.  
  1578. function setSetting(settingname, val) {
  1579. if (charinfoid) { settingname = 'libc-' + charinfoid + '-' + settingname; }
  1580. else { logLibC('Error setSetting for '+settingname+' to val: '+val); return null; }
  1581. return GM_setValue(settingname, String(val));
  1582. }
  1583.  
  1584. function getGlobalSetting(settingname) { return String(GM_getValue('libc-global'+settingname, null)); }
  1585.  
  1586. function setGlobalSetting(settingname, val) { return GM_setValue('libc-global'+settingname, String(val)); }
  1587.  
  1588. function togglecheckbox(e) { logLibC('LibC: toggled '+e.target.id); setSetting(e.target.id, e.target.checked); }
  1589.  
  1590. function libCreateCheckbox(name, hovertext) {
  1591. var checkbox;
  1592. checkbox = document.createElement('input');
  1593. checkbox.type = 'checkbox';
  1594. if (getSetting(name) == 'true') { checkbox.checked = true; }
  1595. else { checkbox.checked = false; }
  1596. checkbox.title = hovertext;
  1597. checkbox.id = name;
  1598. checkbox.addEventListener('click', togglecheckbox, false);
  1599. return checkbox;
  1600. }
  1601.  
  1602. function updatetextfield(e) { logLibC('LibC: set '+e.target.id+' to '+e.target.value); setSetting(e.target.id, e.target.value); }
  1603.  
  1604. function libCreateTextfield(name, hovertext) {
  1605. var textfield;
  1606. textfield = document.createElement('input');
  1607. textfield.type = 'text';
  1608. textfield.setAttribute('maxlength', 3);
  1609. textfield.setAttribute('size', 3);
  1610. if (getSetting(name)) { textfield.value = getSetting(name); }
  1611. textfield.title = hovertext;
  1612. textfield.id = name;
  1613. textfield.addEventListener('input', updatetextfield, false);
  1614. return textfield;
  1615. }
  1616.  
  1617. function updateselect(e) { logLibC('LibC: set '+e.target.id+' to '+e.target.options[e.target.selectedIndex].value); setSetting(e.target.id, e.target.options[e.target.selectedIndex].value); }
  1618.  
  1619. function libCreateSelect(name, hovertext, values) {
  1620. var select, setting, sidx, len, i, temp, option;
  1621. select = document.createElement('select');
  1622. select.title = hovertext; select.id = name;
  1623. setting = getSetting(name);
  1624. sidx = 0; len = values.length;
  1625. for (i = 0; i < len; i++) {
  1626. temp = values[i];
  1627. if (temp[0] == setting) { sidx = i; }
  1628. option = document.createElement('option');
  1629. option.value = temp[0]; option.text = temp[1];
  1630. select.add(option);
  1631. }
  1632. select.selectedIndex = sidx;
  1633. select.addEventListener('change', updateselect, false);
  1634. return select;
  1635. }
  1636.  
  1637. function libSettings() {
  1638. var scratchpad, table, temptable, temptablerow, link, verspan, i, len, s, t;
  1639.  
  1640. // modules: tied to general tweaks. [<functionmap>,"display name","helptext/hovertext"]
  1641. var settingrows = [
  1642. ['hilights', 'Description Hilights', 'Highlights shadows moving in windows and the building lights.'],
  1643. ['sortpeople', 'Sort Characters', 'Sorts characters in a location based on allegiance, and allows further sorting styles and display of informaiton.'],
  1644. ['safety', 'Safety Buttons', 'Adds many options as to what buttons to add safeties to, preventing misclicks.'],
  1645. ['thinbar', 'Thin Character Bars', 'Full MP or HP bars are made thinner, to take less space and to stand out.'],
  1646. ['weaponpane', 'Weaponpane Tweak', 'Offers many quick tweaks to the weapon pane, including minimising lengthy options and displaying the DPA directly in the drop-down.'],
  1647. ['pickup', 'Default Pick-Up', 'Defaults hatchets, throwing knives, then rocks to pick up in the target-shooting pane.'],
  1648. ['warnheaders', 'Warning Headers', 'Colours headers orange or red when you have low AP or low HP.'],
  1649. ['saveform', 'Save Forms', 'Saves the charged attack(s) or any other drop-downs that you use, so that you don\'t have to reselect them each time. Click the "Game Map" button to store your settings safely.'],
  1650. ['pettweak', 'Pet Interface', 'Vastly improves upon the pet interface with colours, countdowns, hover information, and indicators for the lowest pets.'],
  1651. ['alchemytweak', 'Alchemy Interface', 'Vastly improves upon the alchemy interface with colours, tabs, many easy-access buttons, and notes.'],
  1652. ['accesskeys', 'Access Keys', 'Adds access keys to heal or to bash forts or to pickup items.'],
  1653. ['pettarget', 'Pet Target Bug-Fix', 'Fixes it so that clicking on a pet\'s name will target that pet. Does not affect the pet target resetting after an attack.'],
  1654. ['removecolour', 'Remove Gem Colour', 'Removes the colour of a gem and sorts them, in the faction safe. Only applies to spellcraft characters viewing a faction safe.'],
  1655. ['inventory', 'Inventory Tweaks', 'For fast inventory management.'],
  1656. ['targetsetup', 'Target Set-Up Default', 'Changes the default to the last option for setting up targets (usually bottles) and avoiding putting up precious potions.'],
  1657. ['recapdefaults', 'Recapture Standard Default', 'Changes the default to the last option for reclaiming standards. (For ease of recapture)'],
  1658. ['speakdefaults', 'Speech Defaults to Everyone', 'Changes the default speech target to be "everyone" to prevent accidentally whispering /me.'],
  1659. ['global', 'GLOBAL SETTINGS', 'These settings are stored independent of your characters, due to technical limitations.']
  1660. ];
  1661.  
  1662. // settings to display under modules
  1663. // b = checkbox, s = select(dropdown), f = textfield, g = global
  1664. var settings = [
  1665. ['hilights', 'b', 'Hilight Shadows', 'shadow', 'Highlights shadows moving in windows.'],
  1666. ['hilights', 'b', 'Hilight Lights', 'lights', 'Highlights the power status of the tile.'],
  1667. ['hilights', 'b', 'Display Pick-Up Item Count', 'targets', 'Adds a count of items that can be picked up to the end of the tile description. Dodgerblue if there are any, and no text if there are none.'],
  1668. ['sortpeople', 's', 'Enemy Sort', 'sort1', 'What style of sorting is utilised: alphabetical(default), percentage HP, total HP.', [['normal','Alphabetical'],['percent', 'HP Percentage'], ['total', 'HP Total'], ['downtotal', 'HP Total Missing'], ['level', 'Level']]],
  1669. ['sortpeople', 'b', 'Reverse Enemy Sort', 'reverse1', 'Reverses the order of characters.'],
  1670. ['sortpeople', 's', 'Ally Sort', 'sort2', 'What style of sorting is utilised: alphabetical(default), percentage HP, total HP.', [['normal','Alphabetical'],['percent', 'HP Percentage'], ['total', 'HP Total'], ['downtotal', 'HP Total Missing'], ['level', 'Level']]],
  1671. ['sortpeople', 'b', 'Reverse Ally Sort', 'reverse2', 'Reverses the order of characters.'],
  1672. ['sortpeople', 'b', 'Sort Neutrals as Allies', 'neutrals', 'Treat unfactioned and neutral factioned characters as allies in the sorted list.'],
  1673. ['sortpeople', 'b', 'Display HP', 'showhp', 'Prints the HP values after the character\'s name. Requires first-aid.'],
  1674. ['sortpeople', 'b', 'Hilight Master\'s Pets', 'petmaster', 'Will hilight all the pets belonging to a master when hovering over their name. Adds a count of pets when you hover over their name.'],
  1675. ['safety', 'b', 'Safe Drop Buttons', 'drop', 'Adds safeties to Drop Item buttons.'],
  1676. ['safety', 'b', 'Safe Craft Button', 'craft', 'Adds a safety to the Craft Item button.'],
  1677. ['safety', 'b', 'Safe Repair Button', 'repair', 'Adds a safety to the Repair Item button.'],
  1678. ['safety', 'b', 'Safe Learn Buttons', 'learn', 'Adds safeties to Learn Spell buttons.'],
  1679. ['safety', 'b', 'Safe Revoke Button', 'revoke', 'Adds a safety to the Revoke Stronghold button.'],
  1680. ['safety', 'b', 'Safe Speech Buttons', 'speech', 'Adds a safety to Speech/Bullhorn buttons, so that you must enter something before sending.'],
  1681. ['safety', 'b', 'Safe Load Wand', 'loadwand', 'Adds double-click safeties to (re)load spellwand buttons.'],
  1682. ['safety', 'b', 'Safe Blessing', 'blessing', 'Adds a safety to Advocate Blessing.'],
  1683. ['safety', 'b', 'Safe Wisp', 'wisp', 'Adds a safety to deactivating Wisp Form on Conduit.'],
  1684. ['safety', 'b', 'Safe Well', 'well', 'Adds a safety to creating an Arcane Well on Conduit.'],
  1685. ['safety', 'b', 'Safe Mark', 'mark', 'Adds a safety to creating a Nexal Mark on Conduit.'],
  1686. ['safety', 'b', 'Safe Heal Self', 'hself', 'Adds a safety to Heal Self on Conduit.'],
  1687. ['weaponpane', 'b', 'Print DPA', 'dpa', 'Prints the raw DPA for each attack in drop-downs.'],
  1688. ['weaponpane', 'b', 'Shorten Damage', 'dmg', 'Shortens the damage and accuracy counts in drop-downs.'],
  1689. ['weaponpane', 'b', 'Shorten Shots', 'shots', 'Shortens the shots remaining in drop-downs.'],
  1690. ['weaponpane', 'b', 'Shorten Gems/Touch Attacks', 'gem', 'Shortens spellgems and non-damaging attacks in drop-downs.'],
  1691. ['weaponpane', 'b', 'Shorten Quality', 'quality', 'Shortens quality levels in drop-downs.'],
  1692. ['weaponpane', 'b', 'Shorten Enchant', 'magic', 'Shortens enchanted and magical items in the drop-downs.'],
  1693. ['pickup', 's', 'Highest Priority', 'priority0', 'Always selects these items for pickup. Suggested either Hatchet or Misc.', [['null', 'None'],['hatchet', 'Hatchet'],['misc','Unknown/Misc.'],['drink', 'Bottle/Potion'],['food', 'Cans/Food'],['knife','Throwing Knife'],['rock','Rock']]],
  1694. ['pickup', 's', 'High Priority', 'priority1', 'Selects these items for pickup if there are no higher priorities.', [['null', 'None'],['hatchet', 'Hatchet'],['misc','Unknown/Misc.'],['drink', 'Bottle/Potion'],['food', 'Cans/Food'],['knife','Throwing Knife'],['rock','Rock']]],
  1695. ['pickup', 's', 'Normal Priority', 'priority2', 'Selects these items for pickup if there are no higher priorities.', [['null', 'None'],['hatchet', 'Hatchet'],['misc','Unknown/Misc.'],['drink', 'Bottle/Potion'],['food', 'Cans/Food'],['knife','Throwing Knife'],['rock','Rock']]],
  1696. ['pickup', 's', 'Low Priority', 'priority3', 'Selects these items for pickup if there are no higher priorities.', [['null', 'None'],['hatchet', 'Hatchet'],['misc','Unknown/Misc.'],['drink', 'Bottle/Potion'],['food', 'Cans/Food'],['knife','Throwing Knife'],['rock','Rock']]],
  1697. ['pickup', 's', 'Lower Priority', 'priority4', 'Selects these items for pickup if there are no higher priorities.', [['null', 'None'],['hatchet', 'Hatchet'],['misc','Unknown/Misc.'],['drink', 'Bottle/Potion'],['food', 'Cans/Food'],['knife','Throwing Knife'],['rock','Rock']]],
  1698. ['pickup', 's', 'Lowest Priority', 'priority5', 'Selects these items for pickup if there are no higher priorities.', [['null', 'None'],['hatchet', 'Hatchet'],['misc','Unknown/Misc.'],['drink', 'Bottle/Potion'],['food', 'Cans/Food'],['knife','Throwing Knife'],['rock','Rock']]],
  1699. ['warnheaders', 'f', 'Low AP', 'ap', 'Displays warning headers when AP is less than this.'],
  1700. ['warnheaders', 'f', 'Low HP', 'hp', 'Displays warning headers when HP is less than this.'],
  1701. ['warnheaders', 'b', 'Warning Move Buttons', 'move', 'Changes the border of move buttons when you are at risk.'],
  1702. ['saveform', 'b', 'Charge-Type 1', 'c1', 'Remembers charged attacks of the first kind. (such as arcane shot and most charged attacks)'],
  1703. ['saveform', 'b', 'Charge-Type 2', 'c2', 'Remembers charged attacks of the second kind. (such as mystic seeker)'],
  1704. ['saveform', 'b', 'Clockwork Precision', 'precision', 'Remembers the amount for Seraphim\'s Eye of Clockwork Precision.'],
  1705. ['saveform', 'b', 'Prayer', 'prayer', 'Remembers the last prayer type and maintains it.'],
  1706. ['saveform', 'b', 'Repair Item', 'repair', 'Remembers the last item repaired and maintains it.'],
  1707. ['pettweak', 'b', 'Count to MP Surplus', 'surplus', 'If checked, will display decay times and hilight based on time until AP equals MP, rather than just AP counts.'],
  1708. ['pettweak', 'f', 'AP Critical', 'ap-low', 'Hilights the pet row when their AP (or AP surplus) is low.'],
  1709. ['pettweak', 'f', 'AP Low', 'ap-mid', 'Hilights the pet row when their AP (or AP surplus) is nearing low.'],
  1710. ['alchemytweak', 'b', 'Quick Inventory Potions', 'safebutton', 'Adds buttons for placing and retrieving a potion to/from the safe.'],
  1711. ['alchemytweak', 'b', 'Display Potion Counts', 'count-show', 'Displays a coloured number of potions stocked in the safe.'],
  1712. ['alchemytweak', 'f', 'Potions Critical', 'count-low', 'Everything under this amount is considered to be critically low.'],
  1713. ['alchemytweak', 'f', 'Potions Low', 'count-mid', 'Everything between this amount and the critical amount is considered to be slightly low.'],
  1714. ['alchemytweak', 'b', 'Always Hilight Safe', 'alwayshilight', 'Colours the inventory and safe drop-downs according to component rarity.'],
  1715. ['alchemytweak', 'b', 'Suppress Component Hilighting', 'suppress', 'NOT RECOMMENDED BY DEFAULT: Removes the hilighting from components for when they are in the safe or your inventory.'],
  1716. ['alchemytweak', 'b', 'Suppress Leech Warning', 'suppresslw', 'NOT RECOMMENDED BY DEFAULT: To disable the alternate button when leeches are in your inventory.'],
  1717. ['accesskeys', 's', 'Fort-bash Key', 'fort', 'Adds an accesskey for fort-bashing. Suggested default F.', [['null', 'Disable'],['B','B'],['C','C'],['E','E'],['F','(F)'],['G','G'],['J','J'],['K','K'],['L','L'],['N','N'],['O','O'],['Q','Q'],['R','R'],['T','T'],['U','U'],['V','V'],['W','W'],['X','X'],['Y','Y'],['Z','Z'],['!','!'],['"','"'],['£','£'],['@','@'],['#','#'],['$','$'],['%','%'],['^','^'],['&','&'],['*','*'],['(','('],[')',')']]],
  1718. ['accesskeys', 's', 'Heal Key', 'heal', 'Adds an accesskey for healing. Default order is FAKs, Bone Leeches, Herbs, then Surgery, depending on what is available. Suggested default X.', [['null', 'Disable'],['B','B'],['C','C'],['E','E'],['F','F'],['G','G'],['J','J'],['K','K'],['L','L'],['N','N'],['O','O'],['Q','Q'],['R','R'],['T','T'],['U','U'],['V','V'],['W','W'],['X','(X)'],['Y','Y'],['Z','Z'],['!','!'],['"','"'],['£','£'],['@','@'],['#','#'],['$','$'],['%','%'],['^','^'],['&','&'],['*','*'],['(','('],[')',')']]],
  1719. ['accesskeys', 's', 'Retrieve Item Key', 'pickup', 'Adds an accesskey for picking up targets and throwing weapons. Suggested default E.', [['null', 'Disable'],['B','B'],['C','C'],['E','(E)'],['F','F'],['G','G'],['J','J'],['K','K'],['L','L'],['N','N'],['O','O'],['Q','Q'],['R','R'],['T','T'],['U','U'],['V','V'],['W','W'],['X','X'],['Y','Y'],['Z','Z'],['!','!'],['"','"'],['£','£'],['@','@'],['#','#'],['$','$'],['%','%'],['^','^'],['&','&'],['*','*'],['(','('],[')',')']]],
  1720. ['accesskeys', 's', 'Enter/Exit Key', 'door', 'Adds an accesskey for entering and exiting a tile. Suggested default B.', [['null', 'Disable'],['B','(B)'],['C','C'],['E','E'],['F','F'],['G','G'],['J','J'],['K','K'],['L','L'],['N','N'],['O','O'],['Q','Q'],['R','R'],['T','T'],['U','U'],['V','V'],['W','W'],['X','X'],['Y','Y'],['Z','Z'],['!','!'],['"','"'],['£','£'],['@','@'],['#','#'],['$','$'],['%','%'],['^','^'],['&','&'],['*','*'],['(','('],[')',')']]],
  1721. ['accesskeys', 's', 'Recapture Key', 'recap', 'Adds an accesskey for recapturing a standard. Suggested default L.', [['null', 'Disable'],['B','B'],['C','C'],['E','E'],['F','F'],['G','G'],['J','J'],['K','K'],['L','(L)'],['N','N'],['O','O'],['Q','Q'],['R','R'],['T','T'],['U','U'],['V','V'],['W','W'],['X','X'],['Y','Y'],['Z','Z'],['!','!'],['"','"'],['£','£'],['@','@'],['#','#'],['$','$'],['%','%'],['^','^'],['&','&'],['*','*'],['(','('],[')',')']]],
  1722. ['inventory', 'b', 'Fast Charge/Reload', 'reload', 'Places gems able to be recharged and weapons able to be reloaded at the top of the list.'],
  1723. ['inventory', 'b', 'Hide Weightless Items', 'hide', 'Hides weightless items in inventory, with a toggle to display them.'],
  1724. ['inventory', 'b', 'Short Item Names', 'short', 'Shortens item names in the inventory to conserve space.'],
  1725. ['inventory', 'b', 'Short Item Extras', 'shorter', 'Shortens item names further and changes quality levels to Q-levels.'],
  1726. ['inventory', 'b', 'Context Buttons', 'context', 'Adds buttons before item names in the inventory to give, place in safe, or place in footlocker.'],
  1727. ['inventory', 'b', 'Colour Components', 'colourcomponents', 'Colours alchemy components with rarity, and emboldens them.'],
  1728. // ['craftcheck', 'b', 'Hilight Partial Options', 'hilight-partial', 'Much like alchemy pane, colours items you have some but not all ingredients to craft.'],
  1729. ['global', 'g', 'Colour Message History', 'messagehistory', 'Adds CSS styling to the message history to improve ease of reading. Includes combat actions, searches, speech, and more.'],
  1730. ['global', 'g', 'Safe Faction/Char Buttons', 'safebuttons', 'Adds safety buttons to character pages and faction pages and skill selection pages.'],
  1731. ['global', 'g', 'Faction Census', 'factioncensus', 'Adds a census feature to the faction roster page.']
  1732. ];
  1733. scratchpad = document.evaluate("//td/form/textarea[@name='Scratchpad']/../../../..", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  1734. if (scratchpad.snapshotLength != 1) { return; }
  1735. table = scratchpad.snapshotItem(0).parentElement;
  1736. table.appendChild(document.createElement('tr'));
  1737. table.lastElementChild.appendChild(document.createElement('td'));
  1738. temptable = document.createElement('table');
  1739. temptable.id = 'libc-settingtable';
  1740. temptable.className = 'libc-settingtable';
  1741. temptable.appendChild(document.createElement('tbody'));
  1742. link = document.createElement('a');
  1743. link.href = '/modules.php?name=Forums&file=viewtopic&t=7291'; link.textContent = 'libConglomerate';
  1744. verspan = document.createElement('span');
  1745. verspan.appendChild(document.createTextNode('Version '+versionStr));
  1746. temptablerow = document.createElement('tr');
  1747. temptablerow.className = 'libc-settingrow';
  1748. temptablerow.appendChild(document.createElement('td'));
  1749. temptablerow.lastElementChild.className = 'libc-settingname';
  1750. temptablerow.lastElementChild.appendChild(link);
  1751. temptablerow.appendChild(document.createElement('td'));
  1752. temptablerow.lastElementChild.className = 'libc-settinglist';
  1753. temptablerow.lastElementChild.appendChild(verspan);
  1754. temptable.lastElementChild.appendChild(temptablerow);
  1755. table.lastElementChild.lastElementChild.appendChild(temptable);
  1756. len = settingrows.length;
  1757. for (i = 0; i < len; i++) { s = settingrows[i]; createSettingsRow(s[0], s[1], s[2]); }
  1758. len = settings.length;
  1759. for (i = 0; i < len; i++) {
  1760. s = settings[i]; //setting
  1761. t = s[1]; //types: (b)ox (f)ield (s)elect (g)lobal
  1762. if (t == 'b') { addSettingBox(s[0], s[2], s[3], s[4]); }
  1763. if (t == 'f') { addSettingField(s[0], s[2], s[3], s[4]); }
  1764. if (t == 's') { addSettingSelect(s[0], s[2], s[3], s[4], s[5]); }
  1765. if (t == 'g') { addGlobalSetting(s[0], s[2], s[3], s[4]); }
  1766. }
  1767. }
  1768.  
  1769. function createSettingsRow(name, title, srdesc) {
  1770. var table, settingsRow, settingTitle, settingList;
  1771. table = document.getElementById('libc-settingtable').firstElementChild; //gets TBODY
  1772. if (!table) { logLibC('LibC: failed to find settingtable'); return; }
  1773. settingsRow = document.createElement('tr');
  1774. settingsRow.className = 'libc-settingrow';
  1775. settingTitle = document.createElement('td');
  1776. settingTitle.className = 'libc-settingname';
  1777. settingTitle.appendChild(document.createElement('span'));
  1778. settingTitle.lastElementChild.appendChild(document.createTextNode(title));
  1779. settingTitle.appendChild(libCreateCheckbox('run-'+name, srdesc));
  1780. settingList = document.createElement('td');
  1781. settingList.className = 'libc-settinglist';
  1782. settingList.id = 'libc-setting-' + name;
  1783. settingsRow.appendChild(settingTitle);
  1784. settingsRow.appendChild(settingList);
  1785. table.appendChild(settingsRow);
  1786. }
  1787.  
  1788. function addToRow(tdid, title, button) {
  1789. var td, tempspan;
  1790. td = document.getElementById('libc-setting-'+tdid);
  1791. if (!td) { logLibC('LibC: failed to find libc-setting-'+tdid); return; }
  1792. tempspan = document.createElement('span');
  1793. tempspan.className = 'libc-settingspan';
  1794. tempspan.appendChild(document.createTextNode(title));
  1795. tempspan.appendChild(button);
  1796. td.appendChild(tempspan);
  1797. td.appendChild(document.createElement('br'));
  1798. }
  1799.  
  1800. function addSettingBox(tdid, title, setting, hover) {
  1801. var box = libCreateCheckbox(tdid+'-extra-'+setting, hover);
  1802. addToRow(tdid, title, box);
  1803. }
  1804.  
  1805. function addSettingField(tdid, title, setting, hover) {
  1806. var field = libCreateTextfield(tdid+'-extra-'+setting, hover);
  1807. addToRow(tdid, title, field);
  1808. }
  1809.  
  1810. function addSettingSelect(tdid, title, setting, hover, vals) {
  1811. var select = libCreateSelect(tdid+'-extra-'+setting, hover, vals);
  1812. addToRow(tdid, title, select);
  1813. }
  1814.  
  1815. function toggleglobal(e) { logLibC('LibC: toggled '+e.target.id); setGlobalSetting(e.target.name, e.target.checked); }
  1816.  
  1817. function addGlobalSetting(tdid, title, setting, hover) {
  1818. var checkbox = document.createElement('input');
  1819. checkbox.type = 'checkbox';
  1820. if (getGlobalSetting(setting) == 'true') { checkbox.checked = true; }
  1821. else { checkbox.checked = false; }
  1822. checkbox.title = hover; checkbox.id = 'global-'+setting;
  1823. checkbox.name = setting;
  1824. checkbox.addEventListener('click', toggleglobal, false);
  1825. addToRow(tdid, title, checkbox);
  1826. }
  1827.  
  1828.  
  1829.  
  1830. function runLibC() {
  1831. var libCalls, i, len;
  1832. if (getSetting('run-sortpeople') == 'true') { sortpeople(); } //this breaks if not running first. innerHTML editing deletes dom elements
  1833. libGlobalCalls = [
  1834. ['factioncensus', factioncensus],
  1835. ['safebuttons', safebuttons],
  1836. ['messagehistory', messagehistory]
  1837. ];
  1838. len = libGlobalCalls.length;
  1839. for (i = 0; i < len; i++) {
  1840. if (getGlobalSetting(libGlobalCalls[i][0]) == 'true') { libGlobalCalls[i][1](); }
  1841. }
  1842. libSettings();
  1843. if (charinfoid) { //these run using settings checks
  1844. libCalls = [
  1845. ['removecolour', removecolours],
  1846. ['safety', safebuttons],
  1847. ['hilights', showhilights],
  1848. ['thinbar', tweakbars],
  1849. ['weaponpane', weaponpane],
  1850. ['pickup', pickupdefaults],
  1851. ['warnheaders', warningheaders],
  1852. ['saveform', saveForms],
  1853. ['pettweak', processPetTable],
  1854. ['alchemytweak', alchemytweak],
  1855. ['accesskeys', accesskeys],
  1856. ['pettarget', pettarget],
  1857. ['inventory', inventory],
  1858. ['targetsetup', targetsetupdefaults],
  1859. ['recapdefaults', recapdefaults],
  1860. ['speakdefaults', speakdefaults]
  1861. ];
  1862. len = libCalls.length;
  1863. for (i = 0; i < len; i++) {
  1864. if (getSetting('run-'+libCalls[i][0]) == 'true') {
  1865. try {
  1866. libCalls[i][1](); // safely try to call a function; catch if it throws exception
  1867. } catch(err) {
  1868. logLibC('Error running '+libCalls[i][0]+' with message ' + err.message );
  1869. }
  1870. }
  1871. }
  1872. }
  1873. }
  1874. runLibC();
  1875. })();
Add Comment
Please, Sign In to add comment