Battle Checker

To help monitor the hippy/frat war; adds a notice to the charpane in KOL of the current image numbers, updating after each charpane refresh.

  1. // ==UserScript==
  2. // @name Battle Checker
  3. // @namespace kol.interface.unfinished
  4. // @description To help monitor the hippy/frat war; adds a notice to the charpane in KOL of the current image numbers, updating after each charpane refresh.
  5. // @include http://*kingdomofloathing.com/charpane.php*
  6. // @include http://127.0.0.1:*/charpane.php*
  7. // @version 1.11
  8. // @grant GM_getValue
  9. // @grant GM_setValue
  10. // @grant GM_xmlhttpRequest
  11. // ==/UserScript==
  12.  
  13. // version 1.11
  14. // - add @grant, replace GM_log with console.log
  15. // version 1.1
  16. // - minor fix to make it show up more consistently below the character data
  17. // version 1.0
  18.  
  19. // id for font element
  20. var TPIDFONT='battlechecker_font';
  21. // id for number fields
  22. var TPIDNUMF='battlechecker_frat';
  23. var TPIDNUMH='battlechecker_hippy';
  24. // id for off/on toggle
  25. var TPIDOFFON='battlechecker_offon';
  26. // id for event handlers
  27. var TPIDEF='battlechecker_efrat';
  28. var TPIDEH='battlechecker_ehippy';
  29. // suffix (with player name_) of name of global variable for storing state
  30. var TPONOFF='onoff';
  31. // suffix (with player name_) of name of global variable for storing last value
  32. var TPLAST='last';
  33. // suffix (with player name_) of name of global variable for storing last displayed value
  34. var TPLASTDISPLAY='display';
  35. // url pathname to check
  36. var TPURL='/bigisland.php';
  37. // text to use when in the process of checking
  38. var TPCHECK='checking...';
  39. // text to use when in the process of not checking
  40. var TPNOTCHECK='(combat)';
  41. // disabled text
  42. var TPDISABLE='';
  43. // mouseover text for clickable frat/hippy text
  44. var TPMOSTR='Click to force a check now.';
  45. var TPMOBUSYSTR='Busy checking...';
  46.  
  47. // colours for different entries. p is a priority
  48. var colours={'31':{c:'green',p:1,s:1},'32':{c:'red',p:1,s:2},'last':{c:'orangered',p:2,s:1}};
  49. colours[TPNOTCHECK]={c:'gray',p:0,s:1};
  50. colours[TPCHECK]={c:'gray',p:0,s:1};
  51. colours[TPDISABLE]={c:'silver',p:1,s:1};
  52.  
  53. // main function to find the anchor point and create
  54. // the notification
  55. function createNotice(numf,numh) {
  56. if (updateActualNotice(numf,numh))
  57. return;
  58. var spot = document.getElementById('rollover');
  59. if (spot && spot.nextSibling) {
  60. var parent = spot.nextSibling.firstChild;
  61. if (parent && parent.tagName=='TABLE' && parent.firstChild && parent.firstChild.tagName=='TBODY')
  62. parent = parent.firstChild;
  63. if (parent)
  64. createActualNotice(parent,numf,numh);
  65. }
  66. }
  67.  
  68. // actually creates the notice assuming it's not there already
  69. function createActualNotice(parent,numf,numh) {
  70. // create a new row for a table with 2 columns
  71. var x = document.createElement('tr');
  72. var y = document.createElement('td');
  73. // we'll just span both rows
  74. y.setAttribute("colspan","2");
  75. y.setAttribute("align","center");
  76. x.appendChild(y);
  77. // surround it all with a font so it's small and we can change colour
  78. var v = document.createElement('font');
  79. v.setAttribute('id',TPIDFONT);
  80. v.setAttribute('size','1');
  81. y.appendChild(v);
  82.  
  83. // create the checkbox
  84. var offon=document.createElement('input');
  85. offon.setAttribute('style','vertical-align:middle;');
  86. offon.setAttribute('id',TPIDOFFON);
  87. offon.setAttribute('type','checkbox');
  88. offon.setAttribute('padding','0');
  89. var pn = GM_getValue("playername");
  90. if (pn && GM_getValue(pn+'_'+TPONOFF,'true')=='true')
  91. offon.setAttribute('checked','true');
  92. offon.addEventListener('click',offonhandler,true);
  93. v.appendChild(offon);
  94.  
  95. // next is a label with everything in it
  96. var s = document.createElement('label');
  97. s.setAttribute('style','vertical-align:middle;');
  98. v.appendChild(s);
  99.  
  100. var ts = document.createElement('span');
  101. ts.appendChild(document.createTextNode('Frat: '));
  102. ts.addEventListener('click',update,true);
  103. ts.setAttribute('id',TPIDEF);
  104. ts.setAttribute('title',TPMOSTR);
  105. s.appendChild(ts);
  106.  
  107. // text we intend to modify later is in a bold
  108. var w = document.createElement('span');
  109. w.setAttribute('id',TPIDNUMF);
  110. s.appendChild(w);
  111. // set colour
  112. var cf=colours[numf];
  113. if (cf) {
  114. v.setAttribute('color',cf.c);
  115. v.setAttribute('size',cf.s);
  116. }
  117. if (pn && numf==TPNOTCHECK) {
  118. var lastdisplay=GM_getValue(pn+'_'+TPLASTDISPLAY);
  119. if (lastdisplay) {
  120. var ld = lastdisplay.split(',');
  121. numf=ld[0];
  122. numh=ld[1];
  123. }
  124. }
  125. w.innerHTML=numf;
  126.  
  127. ts = document.createElement('span');
  128. ts.appendChild(document.createTextNode(' Hippy: '));
  129. ts.addEventListener('click',update,true);
  130. ts.setAttribute('id',TPIDEH);
  131. ts.setAttribute('title',TPMOSTR);
  132. s.appendChild(ts);
  133.  
  134. w = document.createElement('span');
  135. w.setAttribute('id',TPIDNUMH);
  136. s.appendChild(w);
  137. var ch=colours[numh];
  138. if (ch && (!cf || ch.s<cf.s)) {
  139. v.setAttribute('color',ch.c);
  140. v.setAttribute('size',ch.s);
  141. }
  142. w.innerHTML=numh;
  143.  
  144. updateColourIfLast(pn,x,numf,numh,cf,ch);
  145.  
  146. //parent.insertBefore(x,parent.firstChild);
  147. parent.appendChild(x);
  148. }
  149.  
  150. // update notice instead if it's there already for some reason
  151. function updateActualNotice(numf,numh) {
  152. var x = document.getElementById(TPIDFONT);
  153. var y = document.getElementById(TPIDNUMF);
  154. var z = document.getElementById(TPIDNUMH);
  155. if (!x || !y || !z)
  156. return false;
  157.  
  158. var cf=colours[numf];
  159. if (cf) {
  160. x.setAttribute('color',cf.c);
  161. x.setAttribute('size',cf.s);
  162. } else {
  163. x.removeAttribute('color');
  164. x.setAttribute('size','1');
  165. }
  166. if (numf!=TPNOTCHECK)
  167. y.innerHTML=numf;
  168.  
  169. var ch=colours[numh];
  170. if (ch && (!cf || ch.s<cf.s)) {
  171. x.setAttribute('color',ch.c);
  172. x.setAttribute('size',ch.s);
  173. }
  174. if (numf!=TPNOTCHECK)
  175. z.innerHTML=numh;
  176.  
  177. updateColourIfLast(GM_getValue("playername"),x,numf,numh,cf,ch);
  178.  
  179. var pn = GM_getValue("playername");
  180.  
  181. return true;
  182. }
  183.  
  184. // check if the current update is an incremental change from the previous
  185. // and if so colour it if it hasn't been coloured already
  186. function updateColourIfLast(pn,x,numf,numh,cf,ch) {
  187. if (pn) {
  188. var cur=numf+','+numh;
  189. if (cur.match(/[0-9]+,[0-9]+/)) {
  190. var last=GM_getValue(pn+'_'+TPLAST,cur);
  191. if (last.length>0 && !cf && !ch && last!=cur && cur!='0,0') {
  192. //console.log("will update. last: "+last+", cur: "+cur);
  193. x.setAttribute('color',colours.last.c);
  194. x.setAttribute('size',colours.last.s);
  195. }
  196. //else console.log("overwrite update. last: "+last+", cur: "+cur);
  197.  
  198. GM_setValue(pn+'_'+TPLAST,cur);
  199. }
  200. if (numf!=TPNOTCHECK)
  201. GM_setValue(pn+'_'+TPLASTDISPLAY,cur);
  202. //else console.log("will not update last: "+cur);
  203. }
  204. //else console.log("unknown player name");
  205. }
  206.  
  207. // handler for on/off checkbox
  208. function offonhandler(e) {
  209. var pn = GM_getValue("playername");
  210. if (!pn)
  211. return;
  212. var c = this.getAttribute('checked');
  213. if (c) {
  214. this.removeAttribute('checked');
  215. GM_setValue(pn+'_'+TPONOFF,'false');
  216. } else {
  217. this.setAttribute('checked','true');
  218. GM_setValue(pn+'_'+TPONOFF,'true');
  219. }
  220. update();
  221. }
  222.  
  223. // checks if player is likely in the middle of a fight
  224. function infight() {
  225. var somef=window.parent.frames;
  226. var goo = null;
  227. for(var j=0;j<somef.length;j++) {
  228. if (somef[j].name=="mainpane")
  229. goo=somef[j];
  230. }
  231. if (goo) {
  232. var doc = goo.document;
  233. if (!doc || !doc.body)
  234. return false;
  235. var mainframe=doc.body.innerHTML;
  236. if (mainframe && mainframe.indexOf('Combat!')>=0) {
  237. var x = doc.getElementsByTagName('a');
  238. for (var i=0;i<x.length;i++) {
  239. if (x[i].innerHTML && (x[i].innerHTML.indexOf('Adventure Again')==0 || x[i].innerHTML.indexOf('Go back to Your Inventory')==0))
  240. return false;
  241. }
  242. return true;
  243. }
  244. }
  245. return false;
  246. }
  247.  
  248. // utility function, stolen from other scripts
  249. function GM_get(dest, callback)
  250. { GM_xmlhttpRequest({
  251. method: 'GET',
  252. url: dest,
  253. //onerror:function(error) { console.log("GM_get Error: " + error); },
  254. onload:function(details) {
  255. if( typeof(callback)=='function' ){
  256. callback(details.responseText);
  257. } } }); }
  258.  
  259.  
  260. // main function to update state
  261. // creates a temporary notice, checks the bigisland, updates the notice
  262. function update() {
  263. var pn = GM_getValue("playername");
  264. if (!pn)
  265. return;
  266. if (GM_getValue(pn+'_'+TPONOFF,'true')!='true') {
  267. createNotice(TPDISABLE,TPDISABLE); // notice is turned off
  268. } else {
  269. // remove and restore event handlers to avoid concurrency problems
  270. // nb leave on/off---may cause weirdness if toggled in the middle of checking
  271. // but at least it still allows someone to always turn it off
  272. createNotice(TPCHECK,''); // intermediate notice while we load the page
  273. var ef,eh;
  274. ef = document.getElementById(TPIDEF);
  275. eh = document.getElementById(TPIDEH);
  276. if (ef) {
  277. ef.removeEventListener('click',update,true);
  278. ef.setAttribute('title',TPMOBUSYSTR);
  279. }
  280. if (eh) {
  281. eh.removeEventListener('click',update,true);
  282. eh.setAttribute('title',TPMOBUSYSTR);
  283. }
  284. GM_get('http://'+window.location.host+TPURL,function(response){
  285. if(response!=''){
  286. //console.log('response is '+response);
  287. var f = response.indexOf("bigisland/bfleft");
  288. var h = response.indexOf("bigisland/bfright");
  289. if (f>=0 && h>=0) {
  290. var ff = response.substr(f).indexOf('.');
  291. var hh = response.substr(h).indexOf('.');
  292. f = parseInt(response.substr(f+16,ff-16));
  293. h = parseInt(response.substr(h+17,hh-17));
  294. createNotice(f,h);
  295. } else {
  296. createNotice('?','?'); // can't find battlefield images
  297. }
  298. } else {
  299. createNotice('?','?'); // can't load bigisland
  300. }
  301. });
  302. if (ef) {
  303. ef.addEventListener('click',update,true);
  304. ef.setAttribute('title',TPMOSTR);
  305. }
  306. if (eh) {
  307. eh.addEventListener('click',update,true);
  308. eh.setAttribute('title',TPMOSTR);
  309. }
  310. }
  311. }
  312.  
  313. ////////////////////////////////////////////////////////////////////////////////
  314. // stolen and adapted from Anti-Marty's fortune cookie script
  315. ////////////////////////////////////////////////////////////////////////////////
  316. // parse the char pane for the player name
  317. // revised version! now taken directly from kolpreviousnadventures to handle compact mode
  318. function getPlayerNameFromCharpane() {
  319. var username = document.getElementsByTagName("b");
  320. if (!username || username.length < 1) return false;
  321. username = username[0];
  322. if (!username) return false;
  323. username = username.firstChild;
  324. if (!username) return false;
  325. // in full mode the link is <a><b>Name</b></a>
  326. // in compact mode it's <b><a>Name</a></b>
  327. // so have to handle this, and also can use it to tell
  328. // whether it's in compact mode or not.
  329. while (username && username.nodeType == 1) {
  330. username = username.firstChild;
  331. }
  332. if (!username) return false;
  333. username = username.nodeValue;
  334. if (!username) return false;
  335. username = username.toLowerCase();
  336. GM_setValue("playername",username);
  337. return username;
  338. }
  339.  
  340.  
  341. // what we do each time the charpane is loaded:
  342. var firstpn=getPlayerNameFromCharpane();
  343. if(firstpn) {
  344. if (!infight()) {
  345. update();
  346. } else {
  347. if (GM_getValue(firstpn+'_'+TPONOFF,'true')=='true') {
  348. createNotice(TPNOTCHECK,'');
  349. } else {
  350. createNotice(TPDISABLE,TPDISABLE);
  351. }
  352. }
  353. }