您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Counts known recipes and tracks missing recipes in your crafting discovery pages in Kingdom of Loathing.
// ==UserScript== // @name Recipe Counter // @namespace kol.interface.unfinished // @description Counts known recipes and tracks missing recipes in your crafting discovery pages in Kingdom of Loathing. // @include https://*kingdomofloathing.com/craft.php* // @include https://*.kingdomofloathing.com/account.php // @include http://kol.coldfront.net/thekolwiki/index.php/Cocktailcrafting_Discoveries* // @include http://kol.coldfront.net/thekolwiki/index.php/Cooking_Discoveries* // @include http://kol.coldfront.net/thekolwiki/index.php/Meat-Pasting_Discoveries* // @include http://kol.coldfront.net/thekolwiki/index.php/Meatsmithing_Discoveries* // @include http://kol.coldfront.net/thekolwiki/index.php/Miscellaneous_Discoveries* // @version 3.989 // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // ==/UserScript== //Version 3.989 // - Murderbots //Version 3.988 // - Robortender //Version 3.987 // - more eldritch essentials //Version 3.986 // - eldritch essentials //Version 3.985 // - fix thanksgetting //Version 3.984 // - thanksgetting //Version 3.983 // - change to data uri for images used //Version 3.982 // - fix overzealous use of https //Version 3.981 // - change to https //Version 3.98 // - spurious smithing, gunpasting, hi-yo silver //Version 3.97 // - patent medicines //Version 3.96 // - perfect cocktails //Version 3.95 // - guncraft //Version 3.94 // - heavy metallurgy //Version 3.93 // - velvetry //Version 3.92 // - retro-electrical //Version 3.91 // - add baking, and retire jewelry, moving recipes to meat-pasting //Version 3.90 // - cool winery //Version 3.89 // - add Crimbo stuff //Version 3.88 // - add Post-Apocalyptica //Version 3.87 // - add @grant, switch GM_log to console.log, remove auto-update //Version 3.86 // - spookyraven stuff, crash-site stuff, June/2014 familiar stuff //Version 3.85 // - sugar cubans //Version 3.84 // - spring break beach stuff //Version 3.83 // - V11 stuff //Version 3.82 // - added lynrd stuff //Version 3.81 // - add Sugar Scale Structures to miscellaneous //Version 3.80 // - add Smiths-ing to cocktails, cooking, meatpasting, meatsmithing // - add Weapons: Swords to meatpasting, Loathsome Smithery to meatsmithing //Version 3.79 // - added tin-kering to miscellaneous //Version 3.78 // - added cluster stuff to miscellanous, cooking, cocktails //Version 3.77 // - added Aquatic Jewelry // - added Sea Leatherworking //Version 3.76 // - added Cosmic Potions to miscellaneous // - added Papier-Mache to cooking //Version 3.75 // - added Oil Rigging to miscellaneous //Version 3.74 // - added 'tonstruction and Wax Wear to miscellaneous //Version 3.73 // - added Papier Mache to miscellaneous //Version 3.72 // - added Hot Daubery to miscellaneous //Version 3.71 // - added category Confectionery to meatsmithing and cocktailcrafting // - added Peppermints to meatpasting and miscellaneous //Version 3.70 // - added category Confectionery to cooking //Version 3.69 // - added categories: Confectionery to jewelry and meat-pasting, // and Festive Crimbo Cocktails to cocktailcrafting. //Version 3.68 // - added sticky paper and rough stuff category to meatpasting discoveries //Version 3.674 // - fix suddenly re-broken Humpy Dumplings //Version 3.673 // - added honey stuff //Version 3.672 // - added knob cake //Version 3.671 // - more Amazing Ideas //Version 3.67 // - added new recipe sections from April 2011 IOTM //Version 3.665 // - fix https/http issue in auto-update //Version 3.66 // - fix weirdness with vial of jus de larmes, due to it's italicization // - update shared account-menu tab code //Version 3.65 // - incorporate Charon the Hand's code for a shared account menu tab //Version 3.64 // - fix account menu so it works with the new account menu update //Version 3.63 // - added an account menu entry to update recipe lists manually. //Version 3.62 // - more robust when an auto-check fails or is incomplete //Version 3.61 // - added Paperclip Paraphernalia //Version 3.6 // - improved new discovery detection, based on md5 sums of the wiki table // text rather than last edit date of the page. //Version 3.5 // - fix to work around kol's fuzzy matching system which would sometimes // cause the script to wrongly report info in the mouse-over text and // miscolour the item text after clicking on a missing recipe. //Version 3.4 // - now checks and lets you know if wiki discovery pages (list of recipes) // has been updated so you can revisit it to refresh the recipes list. //Version 3.3 // - sped up missing ingredient checking considerably and // it also retrieves the item counts, but only if you have // (ever) enabled chat (you do not need to be in chat). // Slower route is used when chat commands cannot be used. //Version 3.2 // - added auto-update checking //Version 3.1.1 // - updated Cooking recipe sections with Popsicles. //Version 3.1 // - added ability to check inventory for ingredients of missing recipes. // Click on the item name and it looks through through your inventory, changing // the colour the item to either gray or black depending on whether you have // all the ingredients. Mouseover text shows which ingredient is missing if // just one. //Version 3.0.1 // - added Smoked Pottery to miscellaneous //Version 3.0 // - added crafting links for missing recipes, which take you to the appropriate // crafting page, with the selection boxes filled if you have the items. // - script state is now persistent, with counts and any displayed missing recipes // not disappearing if you actually craft something. // - The "show missing" button is now a toggle instead of a one-time button, and // so can be applied by default as you switch discovery pages. //Version 2.0 // - added gathering and display of missing recipes //Version 1.3 // - add sub-counts for sections //Version 1.2 // - add miscellaneous discoveries //Version 1.1 // current page title if at a kol discoveries page var knownPage=''; var pageLinks={'Meat-Pasting Discoveries:':'craft.php?mode=combine', 'Cocktailcrafting Discoveries:':'craft.php?mode=cocktail', 'Meatsmithing Discoveries:':'craft.php?mode=smith', 'Cooking Discoveries:':'craft.php?mode=cook', 'Miscellaneous Discoveries:':'craft.php?mode=discoveries'}; function doPage() { // find table root of area interested in var node,root; var listing = document.getElementsByTagName('b'); for (var i=0;i<listing.length;i++) { var node = listing[i]; if (node.firstChild && pageLinks[node.firstChild.data]) { root = node.parentNode; knownPage = node.firstChild.data; // ugh while (root && root.tagName!='TABLE') root = root.parentNode; break; } } if (root) { GM_setValue('missinga',''); GM_setValue('missingb',''); // count var count = document.evaluate('.//img[contains(@onclick,"descitem")]',root,null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotLength; node.firstChild.data = node.firstChild.data.substr(0,node.firstChild.data.length-1)+ ' ('+count+' known):'; addButton(node); addSubcounts(root); if (GM_getValue('showmissing','')) showMissing(); } else { // direct crafting page? var a = document.getElementById('a'); var b = document.getElementById('b'); if (a && b) { var ma = GM_getValue('missinga'); var mb = GM_getValue('missingb'); if (ma) { selectOption(a,ma); selectOption(b,mb); GM_setValue('missinga',''); GM_setValue('missingb',''); } } } } function selectOption(sbox,txt) { for (var i=0;i<sbox.options.length;i++) { if (sbox.options[i].text.indexOf(txt)==0 && sbox.options[i].text.replace(/\s*\([0-9]+\)\s*/,'')==txt) { sbox.selectedIndex = i; return; } } } function addButton(node) { var v = document.createElement('a'); v.setAttribute('href','#'); v.setAttribute('id','showmissingbutton'); v.setAttribute('style','font-size:x-small;color:white;vertical-align:middle;'); fixupButton(v); v.addEventListener('click',bHandler,false); var p = knownPage.replace(/:.*$/,'').replace(/ /g,'_'); v.setAttribute('discoveries_page',p); node.parentNode.appendChild(document.createTextNode('\u00a0\u00a0\u00a0')); node.parentNode.appendChild(v); if (GM_getValue(p+'_oldmd5',0)!=GM_getValue(p+'_newmd5',-1)) { node.parentNode.appendChild(document.createTextNode('\u00a0\u00a0\u00a0')); v = document.createElement('a'); v.setAttribute('href','http://kol.coldfront.net/thekolwiki/index.php/'+p); v.setAttribute('style','font-size:x-small;color:yellow;vertical-align:middle;'); v.setAttribute('title','Updated discoveries list detected!'); v.setAttribute('id','recipecountdisoveriesnotice'); v.setAttribute('target','_blank'); v.appendChild(document.createTextNode('Click to update discoveries list')); node.parentNode.appendChild(v); } else { v = document.getElementById('recipecountdiscoveriesnotice'); if (v) { v.parentNode.removeChild(v); } } } function fixupButton(v) { if (GM_getValue('showmissing','')) { v.setAttribute('title','Click to hide all missing recipes on this page.'); if (v.firstChild) v.replaceChild(document.createTextNode('[Hide Missing]'),v.firstChild); else v.appendChild(document.createTextNode('[Hide Missing]')); } else { v.setAttribute('title','Click to display all missing recipes on this page.'); if (v.firstChild) v.replaceChild(document.createTextNode('[Show Missing]'),v.firstChild); else v.appendChild(document.createTextNode('[Show Missing]')); } } function showMissing() { var v = document.getElementById('showmissingbutton'); if (GM_getValue('showmissing','')) { if (!missing()) { var page = v.getAttribute('discoveries_page'); var pages = page.replace(/_/g,' '); var goWiki = document.createElement('a'); goWiki.setAttribute('title','Click to go to the full list of '+pages+' recipes on the KoL wiki.'); goWiki.setAttribute('target','_blank'); goWiki.setAttribute('style','font-size:x-small;color:white;vertical-align:middle;'); goWiki.setAttribute('href','http://kol.coldfront.net/thekolwiki/index.php/'+page); goWiki.appendChild(document.createTextNode('[Load all '+pages+']')); v.parentNode.appendChild(goWiki); } } else { var xx = document.getElementsByClassName('showmissingaddition'); for (var i=xx.length-1;i>=0;i--) { var x = xx[i]; x.parentNode.removeChild(x); } } fixupButton(v); } function bHandler(e) { var b = GM_getValue('showmissing',''); GM_setValue('showmissing', (b ? '' : 'true')); showMissing(); } function addSubcounts(root) { var tbls = document.evaluate( './/table', root, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); for (var i=tbls.snapshotLength-1;i>=0;i--) { var tbl = tbls.snapshotItem(i); var id = tbl.getAttribute('id'); if (id && id.indexOf('table_')==0) { // found one var count=0; var listing = tbl.getElementsByTagName('img'); for (var j=0;j<listing.length;j++) { var imgnode = listing[j]; var click; if (click=imgnode.getAttribute('onclick')) { if (click.indexOf('descitem')==0) { count++; } } } // count the images if (tbl.previousSibling) { var hdr = tbl.previousSibling.previousSibling; if (hdr && hdr.tagName=='CENTER' && hdr.firstChild) { var f = document.createElement('font'); f.setAttribute('style','font-size:x-small;'); f.appendChild(document.createTextNode(' ('+count+' recipe'+((count==1)? '' : 's')+')')); hdr.firstChild.appendChild(f); } } } } } var rlists = [{title:'Cocktailcrafting Discoveries', sections:['Amazing Ideas','Confectionery','Clustercocktails','Cool Winery','Distillations','Eldritch Essentials','Evil Fruity Girl Drinks', 'Eww','Extra-Fruity Girl Drinks', 'Fancy Garnishes','Festive Crimbo Cocktails','Fruity Girl Drinks','Hilarious Jokes','Infused Wines', 'Miscellaneous','Miscellaneous Boozery','Mushroom Wines','Perfect Cocktails','Post-Apocalyptica', 'Premium Cocktails','Schnapps', 'Robortender Recipes','Simple Cocktails','Smiths-ing','Specialty Beers','Tiny Plastic Sword Drinks', 'Underwater Cocktails']}, {title:'Cooking Discoveries', sections:['Advanced Sauceror Potions','Amazing Ideas','Baking','Brownies','Casseroles','Clusterbaking','Confectionery', 'Confections','Dirty Exploits','Eldritch Essentials','Evil Noodle Dishes','Evil Sauceror Potions','Familiar', 'High-Pressure Potions','Kabobs','Key Limes','Miscellaneous','Miscellaneous Cookery', 'Miscellaneous Potions', 'Nemesis Quest Slimes','Noodle Dishes','Papier-Mache','Patent Medicines','Pies','Pizzas','Popsicles','Pork Gem Potions','Post-Apocalyptica', 'Quest Items','Sauceror Potions','Secret Sauces','Smiths-ing','Space Foods','Stir-Fries','Tempura','Tex-Mex', 'Tex-Mex-Italian','Thanksgarden Creations','Transmutations']}, {title:'Meat-Pasting Discoveries', sections:['Amazing Ideas','Aquatic Jewelry','Campground Items','Clusterbombs','Confectionery','Decoys','Elemental Jewelry','Expensive Pork Elf Jewelry', 'Familiars','Gear','Genetic Engineering','Guncraft','Gunpasting','Hi-Yo Silver','Hilarious Jokes','Horrifying Jewelry','Miscellaneous', 'Miscellaneous Jewelry','Murderbot Technology','Parts','Parts for Campground Items', 'Parts for Familiars','Peppermints','Pork Elf Jewelry','Post-Apocalyptica','Primordial Soup','Quest Items','Rainbow Pearl Jewelry','Retro-Electrical','Rough Stuff', 'Smiths-ing','Spacetime Bending','Usable Items','Vampire Pearl Jewelry','Weapons: Swords']}, {title:'Meatsmithing Discoveries', sections:['Armor: Accessories','Armor: Advanced Accessories','Armor: Advanced Hats', 'Armor: Advanced Pants','Armor: Advanced Shields', 'Armor: Advanced Shirts', 'Armor: Hats', 'Armor: Pants','Armor: Shields','Armor: Shirts','Campground Items', 'Confectionery','Depleted Grimacite', 'Gear','Ghast Irony', 'Ingredients','Loathsome Smithery','Miscellaneous Smithery','Post-Apocalyptica','Quest Weapons','Sea Leatherworking','Slimy Things', 'Smiths-ing','Spacetime Bending','Spurious Smithing','Weapons: Advanced Crossbows', 'Weapons: Advanced Staves','Weapons: Advanced Swords','Weapons: Clubs', 'Weapons: Crossbows','Weapons: Miscellaneous','Weapons: Staves', 'Weapons: Swords','Weapons: Utensils','Weapons: Whips']}, {title:'Miscellaneous Discoveries', sections:["'tonstruction",'BRICKO Beasts','BRICKO Bits','Balloon Bendings','Clingfilm Creations', 'Cold Comforts','Cosmic Potions','Duct Tape Designs','Eldritch Essentials','Heavy Metallurgy','Honey Stuff','Hot Daubery','Mummy Wrapping Manufacturings', 'Oil Rigging','Palm-Frond Preparations','Paperclip Paraphernalia','Papier-Mache','Peppermints','Plaiddery','Smoked Pottery', 'Snailmail Structures','Spacetime Bending','Spooky Bark Surprises','Sugar Cubans','Sugar Scale Structures','Tin-kering', 'Turtlemail Treasures','Velvetry','Wax Wear','Wumpus Hair Weavings']}]; // locate all missing recipes function missing() { var s = knownPage; //console.log('knownPage='+s); if (!s) { return; } for (var i=0;i<rlists.length;i++) { if (s.indexOf(rlists[i].title)>=0) { var r = missingInPage(retrieveCopy(rlists[i].title)); if (!r) return false; insertMissing(r); return true; } } } // set by missingInPage and used by insertMissing var secMap = {}; // uses the secMap and the given list of missing recipes to create fake versions function insertMissing(r) { for (var s in r) { var tbl = secMap[s]; var lastr = null; if (tbl && tbl.rows.length>0 && tbl.rows[tbl.rows.length-1].cells.length<3) { lastr = tbl.rows[tbl.rows.length-1]; } for (var e in r[s]) { if (r[s][e]) { for (var j=0;j<r[s][e].length;j++) { if (lastr) { createMissing(lastr,e,r[s][e][j]); lastr = null; } else { // TBD: what if tbl is null? if (!tbl) { if (secMap['last_table']) { tbl = insertMissingTable(secMap['last_table'].nextSibling,s); } else { var root = document.evaluate( '//td[contains(text(),"You haven\'t made any discoveries in this field yet")]/text()', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE,null); tbl = insertMissingTable(root.singleNodeValue.nextSibling,s); } secMap[s] = tbl; } lastr = tbl.insertRow(-1); lastr.setAttribute('class','showmissingaddition'); createMissing(lastr,e,r[s][e][j]); } // console.log('missing in '+s+': '+e+' = '+r[s][e][j]); } } } } } // creates a table for a section s function insertMissingTable(root,s) { var c = document.createElement('center'); var tbl = document.createElement('table'); var b = document.createElement('b'); var br1 = document.createElement('br'); var br2 = document.createElement('br'); c.setAttribute('class','showmissingaddition'); tbl.setAttribute('class','showmissingaddition'); br1.setAttribute('class','showmissingaddition'); br2.setAttribute('class','showmissingaddition'); b.innerHTML = s; b.setAttribute('style','color:red;'); c.appendChild(b); root.parentNode.insertBefore(br1,root); root.parentNode.insertBefore(c,root); root.parentNode.insertBefore(br2,root); root.parentNode.insertBefore(tbl,root); return tbl; } // locate missing recipes in the current kol discoveries page, given a list of recipes function missingInPage(r) { if (!r) { alert('You need to visit the KoL Wiki discoveries pages (http://kol.coldfront.net/thekolwiki/index.php/Discoveries) to initialize the recipe list. Visit each of the 6 pages of Recipes on the wiki, then re-open a recipe page in the game and try again.'); return; } secMap = {}; var tbls = document.evaluate( '//table', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); for (var i=0;i<tbls.snapshotLength;i++) { var tbl = tbls.snapshotItem(i); var id = (tbl) ? tbl.getAttribute('id') : null; if (id && id.indexOf('table_')==0) { // found one // figure out which section this represents var sec = tbl.previousSibling; while (sec && sec.tagName!='CENTER') sec = sec.previousSibling; if (sec) { sec = sec.firstChild.firstChild.innerHTML; } var es = document.evaluate( './/td', tbl, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); for (var j=0;j<es.snapshotLength;j+=2) { var e = es.snapshotItem(j); var f = es.snapshotItem(j+1); var item = (f.firstChild.firstChild.nodeType==3) ? f.firstChild.firstChild.data : f.firstChild.firstChild.innerHTML; if (!item) continue; var itemr = f.firstChild.nextSibling; if (itemr.tagName!='FONT') itemr = itemr.nextSibling; var components = ''; for (var k=0;k<itemr.childNodes.length;k++) { if (itemr.childNodes[k].nodeType==3) { components += itemr.childNodes[k].data; } else if (itemr.childNodes[k].tagName=='I') { components += '<i>'+itemr.childNodes[k].innerHTML+'</i>'; } } components = components.replace(/\([0-9]+\)/g,'').replace(/\+[\s]*$/,'').replace(/ /g,' ').replace(/\s\s+/,' ').replace(/ *$/,'').replace(/^ */,''); // check that we have a section if (sec) { if (r && r[sec] && r[sec][item]) { var hi = hasRecipe(r[sec][item],components); if (hi>=0) { r[sec][item].splice(hi,1); } } } else if (r) { for (var s in r) { if (r[s][item]) { var hi = hasRecipe(r[s][item],components); if (hi>=0) { r[s][item].splice(hi,1); sec = s; break; } } } } } secMap[sec] = tbl; // store for later secMap['last_table'] = tbl; } } return r; } // check the given list for a recipe combination, and return the index or -1 function hasRecipe(clist,c) { if (!clist) return -1; var c2 = c.match(/(^[^+]*)\+(.*$)/); if (c2) { c2 = c2[2] +' + '+c2[1]; c2 = c2.replace(/\+[\s]*$/,'').replace(/ /g,' ').replace(/ *$/,'').replace(/^ */,''); } for (var i=0;i<clist.length;i++) { if (clist[i] == c || (c2 && clist[i] == c2)) { return i; } } return -1; } // creates a new entry for a missing title+components, and // attaches the resulting td's to the given tr function createMissing(tr,title,components) { var td1 = tr.insertCell(-1); var td2 = tr.insertCell(-1); td1.setAttribute('class','showmissingaddition'); td2.setAttribute('class','showmissingaddition'); td1.setAttribute('valign','center'); td2.setAttribute('valign','top'); var i = document.createElement('img'); i.setAttribute('class','hand'); i.setAttribute('src','data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAABEklEQVRIie2WyxHDMAhE0xR10Q6NUAK1UALHzYl8haXIljOZyR5laR6flfAFX9LlJ8DuDhGBiMDMzgGLCIjoBiYiMPNacGb6ukZEcPd1YACIiO+AH5WlVtVmgMwMZm5+nwZnpqr6VgUAMLMnH1QmLMFmBmZuHnztdyURKQ3YBGe5VBVE1Mysp4go21GC82BloK1AIuLpulV7S3BlIGbeLHUGKyKbAZbgyhiVqVJmNnTNyh6v6u0meO/jMBJwWepeSdPxI9l9BO7J3eHuYGYQ0W09H5BlYOCe9aMJM5gpsLt3+5Qmmp3LTfDorF0ynXqZpPMPzXhUp8/j1Cx0N3iPpsGqOvVwHAIe/SE4FLxXf/BpugJUkH7bCBPJ3QAAAABJRU5ErkJggg=='); td1.appendChild(i); var b = document.createElement('b'); b.setAttribute('style','color:red;'); b.innerHTML = title; td2.appendChild(b); var f = document.createElement('font'); f.setAttribute('size','1'); f.setAttribute('color','red'); if (knownPage!='Miscellaneous Discoveries:') { var f2 = document.createElement('font'); f2.setAttribute('size','2'); f2.setAttribute('color','red'); var ia = document.createElement('a'); ia.appendChild(document.createTextNode('make?')); ia.setAttribute('title','Click to go the crafting page for this missing recipe'); ia.setAttribute('href','#'); ia.setAttribute('missinga',components.replace(/\s*\+.*/,'')); ia.setAttribute('missingb',((components.indexOf('+')>0) ? components.replace(/[^+]*\+\s*/,'') : '')); ia.addEventListener('click',missingButtonHandler,false); f2.appendChild(document.createTextNode('\u00A0[')); f2.appendChild(ia); f2.appendChild(document.createTextNode(']')); f.appendChild(f2); b.setAttribute('missinga',components.replace(/\s*\+.*/,'')); b.setAttribute('missingb',((components.indexOf('+')>0) ? components.replace(/[^+]*\+\s*/,'') : '')); b.setAttribute('title','click to check for ingredients'); b.addEventListener('click',checkIngredientsHandler,false); } f.appendChild(document.createElement('br')); f.appendChild(document.createTextNode(components)); td2.appendChild(f); } function missingButtonHandler() { GM_setValue('missinga',this.getAttribute('missinga').replace(/<[^>]+>/g,'')); GM_setValue('missingb',this.getAttribute('missingb').replace(/<[^>]+>/g,'')); window.location.href = pageLinks[knownPage]; } // return a new copy of the master recipes function retrieveCopy(page) { var r = JSON.parse(GM_getValue('recipes','{}')); return r[page]; } // scrape data from a kol wiki page function gather(m5) { var recipes = JSON.parse(GM_getValue('recipes','{}')); var s = window.location.pathname.replace(/_/g,' '); //console.log('Gathering...'+s); for (var i=0;i<rlists.length;i++) { if (s.indexOf(rlists[i].title)>=0) { gatherRecipes(rlists[i],recipes); var p = rlists[i].title.replace(/:.*$/,'').replace(/ /g,'_'); GM_setValue(p+'_oldmd5',m5); GM_setValue(p+'_newmd5',m5); } } GM_setValue('recipes',JSON.stringify(recipes)); } // scrape data from a specific kol wiki page function gatherRecipes(rlist,recipes) { var s = {}; for (var i=0;i<rlist.sections.length;i++) { var r = gatherRecipesSection(rlist.sections[i]); s[rlist.sections[i]] = r; } recipes[rlist.title] = s; // var p = rlist.title.replace(/:.*$/,'').replace(/ /g,'_')+'_last'; // GM_setValue(p,(new Date()).toUTCString()); //console.log('setting '+p+' to '+GM_getValue(p)); } // scrapte data for the given section of a kol wiki page function gatherRecipesSection(section) { var r = {}; var sec = document.evaluate( '//span[@class="mw-headline"]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); //var sec = document.evaluate( '//span[text()="'+section+'"]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); // console.log('gathering for section '+section); var rx = new RegExp('',''); for (var j=0;j<sec.snapshotLength;j++) { var sn = sec.snapshotItem(j).innerHTML; if (sn.replace(/^ */,'').replace(/ *$/,'')==section) { var hp = sec.snapshotItem(j).parentNode; if (hp && hp.tagName=='H2') { hp = hp.nextSibling.nextSibling; while (hp && hp.tagName!='H2') { var i; var tbls = document.evaluate( './/td', hp, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); for (i=0;i<tbls.snapshotLength-1;i+=2) { var e = tbls.snapshotItem(i); var f = tbls.snapshotItem(i+1); var n = f.firstChild.firstChild.innerHTML; var c = ''; for (var k=0;k<f.firstChild.nextSibling.nextSibling.childNodes.length;k++) { var s = f.firstChild.nextSibling.nextSibling.childNodes[k]; if (s.innerHTML) c += s.innerHTML; else if (s.nodeType==3) c += s.data; else if (c) c += ' + '; } c = c.replace(/\+[\s]*$/,'').replace(/ /g,' ').replace(/ *$/,'').replace(/^ */,''); if (c) { // console.log('found recipe for '+n+', consisting of: '+c); if (r[n]) r[n][r[n].length] = c; else r[n] = [c]; } } if (i>0) return r; hp = hp.nextSibling; } } } } return r; } // called when the confused image is clicked on. function checkIngredientsHandler(e) { this.removeEventListener('click',checkIngredientsHandler,false); checkIngredientsFast(this,this.getAttribute('missinga'),this.getAttribute('missingb')); } // utility function, stolen from other scripts function GM_get(dest, callback) { GM_xmlhttpRequest({ method: 'GET', url: dest, //onerror:function(error) { console.log("GM_get Error: " + error); }, onload:function(details) { if( typeof(callback)=='function' ){ callback(details.responseText); } } }); } // if chat not enabled use the slow route function checkIngredientsSlow(item,ing1,ing2) { //item.setAttribute('style','color:pink;'); //item.setAttribute('title','checking...'); var r1b = false; var r2b = false; GM_get('http://'+window.location.host+'/inventory.php?which=1',function(response){ if(response!=''){ var r1 = new RegExp('<b[^>]*>'+ing1+'</b>','gm'); var r2 = new RegExp('<b[^>]*>'+ing2+'</b>','gm'); if (!r1b) r1b = r1.test(response); if (!r2b) r2b = r2.test(response); if (r1b && r2b) { item.setAttribute('style','color:black;'); item.addEventListener('click',checkIngredientsHandler,false); item.setAttribute('title','Ingredients found in inventory at last check. Click to check again.'); } else { GM_get('http://'+window.location.host+'/inventory.php?which=2',function(response){ if(response!=''){ if (!r1b) r1b = r1.test(response); if (!r2b) r2b = r2.test(response); if (r1b && r2b) { item.setAttribute('style','color:black;'); item.addEventListener('click',checkIngredientsHandler,false); item.setAttribute('title','Ingredients found in inventory at last check. Click to check again.'); } else { GM_get('http://'+window.location.host+'/inventory.php?which=3',function(response){ if(response!=''){ if (!r1b) r1b = r1.test(response); if (!r2b) r2b = r2.test(response); if (r1b && r2b) { item.setAttribute('style','color:black;'); item.setAttribute('title','Ingredients found in inventory at last check. Click to check again.'); } else { item.setAttribute('style','color:gray;'); if (r1b) item.setAttribute('title','Ingredient '+ing2+' not found in inventory. Click to check again.'); else if (r2b) item.setAttribute('title','Ingredient '+ing1+' not found in inventory. Click to check again.'); else item.setAttribute('title','Ingredients not found in inventory. Click to check again.'); } item.addEventListener('click',checkIngredientsHandler,false); }}); } }}); } }}); } // faster checking but requires chat is enabled function checkIngredientsFast(item,ing1,ing2) { item.setAttribute('style','color:pink;'); item.setAttribute('title','checking...'); if (ing1.match(/<[^>]+>/) || ing2.match(/<[^>]+>/)) return checkIngredientsSlow(item,ing1,ing2); var pd = findPwdhash(); if (!pd) { console.log('cound not find pwd or playerid'); return; } //console.log('pwd='+pd.pwd); //console.log('pid='+pd.pid); GM_get('http://'+window.location.host+'/submitnewchat.php?playerid='+pd.pid+'&pwd='+pd.pwd+'&graf=/count '+encodeURI(ing1), function(response) { if(response!='') { //console.log('response: '+response); var r1 = response.match(/(<[^>]*>)*You have ([0-9]*) ([^<]*)\./); GM_get('http://'+window.location.host+'/submitnewchat.php?playerid='+pd.pid+'&pwd='+pd.pwd+'&graf=/count '+encodeURI(ing2), function(response) { if(response!='') { var r2 = response.match(/(<[^>]*>)*You have ([0-9]*) ([^<]*)\./); if (r1 && r2) { verifyItems(item,ing1,ing2,pd,r1,r2); } else { setItemState(item,r1,r2,ing1,ing2); } }}); } else { checkIngredientsSlow(item,ing1,ing2); }}); } function setItemState(item,r1,r2,ing1,ing2) { if (r1 && r2) { item.setAttribute('style','color:black;'); item.setAttribute('title','Found '+r1[2]+' '+r1[3]+' and '+r2[2]+' '+r2[3]+' at last check. Click to check again.'); } else { item.setAttribute('style','color:gray;'); if (r1) item.setAttribute('title','Found '+r1[2]+' '+r1[3]+' but no '+ing2+' in your inventory. Click to check again.'); else if (r2) item.setAttribute('title','Found '+r2[2]+' '+r2[3]+' but no '+ing1+' in your inventory. Click to check again.'); else item.setAttribute('title','Neither ingredient is in your inventory. Click to check again.'); } item.addEventListener('click',checkIngredientsHandler,false); } function verifyItems(item,ing1,ing2,pd,r1,r2) { GM_get('http://'+window.location.host+'/submitnewchat.php?playerid='+pd.pid+'&pwd='+pd.pwd+'&graf=/examine '+encodeURI(ing1), function(response) { var r3 = response.match(/^<[^>]*>Examining: ([^<]*)/); if (r3) r3 = (r3[1]==ing1) ? r3 : null; GM_get('http://'+window.location.host+'/submitnewchat.php?playerid='+pd.pid+'&pwd='+pd.pwd+'&graf=/examine '+encodeURI(ing2), function(response) { var r4 = response.match(/^<[^>]*>Examining: ([^<]*)/); if (r4) r4 = (r4[1]==ing2) ? r4 : null; setItemState(item,(r3) ? r1 : null,(r4) ? r2 : null,ing1,ing2); }); }); } function checkDiscoveries() { for (p in pageLinks) { var purl = p.replace(/:.*$/,'').replace(/ /g,'_'); GM_xmlhttpRequest({ method: 'GET', url: 'http://kol.coldfront.net/thekolwiki/index.php/'+purl, onload: function(details) { var q = this.url.replace(/[^/]*\//g,''); if (details.responseText) { var mdf = getPageMD5(details.responseText); //console.log('new md5 for '+q+': '+mdf); GM_setValue(q+'_newmd5',mdf); } } }); } } function getPageMD5(raw) { var text = ''; var j,i = raw.indexOf('<table>'); while(raw && i>=0) { raw = raw.substr(i+7); j = raw.indexOf('</table>'); if (j<0) break; // bad parse? text = text + raw.substr(0,j); raw = raw.substr(j); i = raw.indexOf('<table>'); } text = text.replace(/<[^>]*>/g,''); text = text.replace(/[\s\n]+/g,''); var m = MD5(text); //console.log('md5 of '+text); return m; } function findPwdhash() { var somef=window.parent.frames; var goo = null; for(var j=0;j<somef.length;j++) { if (somef[j].name=="charpane") { goo=somef[j]; var page = goo.document.documentElement.innerHTML; var pwdh = page.match(/pwdhash\s*=\s*\"([a-f0-9]+)\"/); if (pwdh) { var plid = page.match(/playerid\s*=\s*([a-f0-9]+)/); if (plid) { return {pwd:pwdh[1],pid:plid[1]}; } } } } } /** * * MD5 (Message-Digest Algorithm) * http://www.webtoolkit.info/ * **/ var MD5 = function (string) { function RotateLeft(lValue, iShiftBits) { return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits)); } function AddUnsigned(lX,lY) { var lX4,lY4,lX8,lY8,lResult; lX8 = (lX & 0x80000000); lY8 = (lY & 0x80000000); lX4 = (lX & 0x40000000); lY4 = (lY & 0x40000000); lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF); if (lX4 & lY4) { return (lResult ^ 0x80000000 ^ lX8 ^ lY8); } if (lX4 | lY4) { if (lResult & 0x40000000) { return (lResult ^ 0xC0000000 ^ lX8 ^ lY8); } else { return (lResult ^ 0x40000000 ^ lX8 ^ lY8); } } else { return (lResult ^ lX8 ^ lY8); } } function F(x,y,z) { return (x & y) | ((~x) & z); } function G(x,y,z) { return (x & z) | (y & (~z)); } function H(x,y,z) { return (x ^ y ^ z); } function I(x,y,z) { return (y ^ (x | (~z))); } function FF(a,b,c,d,x,s,ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b); }; function GG(a,b,c,d,x,s,ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b); }; function HH(a,b,c,d,x,s,ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b); }; function II(a,b,c,d,x,s,ac) { a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac)); return AddUnsigned(RotateLeft(a, s), b); }; function ConvertToWordArray(string) { var lWordCount; var lMessageLength = string.length; var lNumberOfWords_temp1=lMessageLength + 8; var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64; var lNumberOfWords = (lNumberOfWords_temp2+1)*16; var lWordArray=Array(lNumberOfWords-1); var lBytePosition = 0; var lByteCount = 0; while ( lByteCount < lMessageLength ) { lWordCount = (lByteCount-(lByteCount % 4))/4; lBytePosition = (lByteCount % 4)*8; lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount)<<lBytePosition)); lByteCount++; } lWordCount = (lByteCount-(lByteCount % 4))/4; lBytePosition = (lByteCount % 4)*8; lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition); lWordArray[lNumberOfWords-2] = lMessageLength<<3; lWordArray[lNumberOfWords-1] = lMessageLength>>>29; return lWordArray; }; function WordToHex(lValue) { var WordToHexValue="",WordToHexValue_temp="",lByte,lCount; for (lCount = 0;lCount<=3;lCount++) { lByte = (lValue>>>(lCount*8)) & 255; WordToHexValue_temp = "0" + lByte.toString(16); WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2); } return WordToHexValue; }; function Utf8Encode(string) { string = string.replace(/\r\n/g,"\n"); var utftext = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { utftext += String.fromCharCode(c); } else if((c > 127) && (c < 2048)) { utftext += String.fromCharCode((c >> 6) | 192); utftext += String.fromCharCode((c & 63) | 128); } else { utftext += String.fromCharCode((c >> 12) | 224); utftext += String.fromCharCode(((c >> 6) & 63) | 128); utftext += String.fromCharCode((c & 63) | 128); } } return utftext; }; var x=Array(); var k,AA,BB,CC,DD,a,b,c,d; var S11=7, S12=12, S13=17, S14=22; var S21=5, S22=9 , S23=14, S24=20; var S31=4, S32=11, S33=16, S34=23; var S41=6, S42=10, S43=15, S44=21; string = Utf8Encode(string); x = ConvertToWordArray(string); a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476; for (k=0;k<x.length;k+=16) { AA=a; BB=b; CC=c; DD=d; a=FF(a,b,c,d,x[k+0], S11,0xD76AA478); d=FF(d,a,b,c,x[k+1], S12,0xE8C7B756); c=FF(c,d,a,b,x[k+2], S13,0x242070DB); b=FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE); a=FF(a,b,c,d,x[k+4], S11,0xF57C0FAF); d=FF(d,a,b,c,x[k+5], S12,0x4787C62A); c=FF(c,d,a,b,x[k+6], S13,0xA8304613); b=FF(b,c,d,a,x[k+7], S14,0xFD469501); a=FF(a,b,c,d,x[k+8], S11,0x698098D8); d=FF(d,a,b,c,x[k+9], S12,0x8B44F7AF); c=FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1); b=FF(b,c,d,a,x[k+11],S14,0x895CD7BE); a=FF(a,b,c,d,x[k+12],S11,0x6B901122); d=FF(d,a,b,c,x[k+13],S12,0xFD987193); c=FF(c,d,a,b,x[k+14],S13,0xA679438E); b=FF(b,c,d,a,x[k+15],S14,0x49B40821); a=GG(a,b,c,d,x[k+1], S21,0xF61E2562); d=GG(d,a,b,c,x[k+6], S22,0xC040B340); c=GG(c,d,a,b,x[k+11],S23,0x265E5A51); b=GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA); a=GG(a,b,c,d,x[k+5], S21,0xD62F105D); d=GG(d,a,b,c,x[k+10],S22,0x2441453); c=GG(c,d,a,b,x[k+15],S23,0xD8A1E681); b=GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8); a=GG(a,b,c,d,x[k+9], S21,0x21E1CDE6); d=GG(d,a,b,c,x[k+14],S22,0xC33707D6); c=GG(c,d,a,b,x[k+3], S23,0xF4D50D87); b=GG(b,c,d,a,x[k+8], S24,0x455A14ED); a=GG(a,b,c,d,x[k+13],S21,0xA9E3E905); d=GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8); c=GG(c,d,a,b,x[k+7], S23,0x676F02D9); b=GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A); a=HH(a,b,c,d,x[k+5], S31,0xFFFA3942); d=HH(d,a,b,c,x[k+8], S32,0x8771F681); c=HH(c,d,a,b,x[k+11],S33,0x6D9D6122); b=HH(b,c,d,a,x[k+14],S34,0xFDE5380C); a=HH(a,b,c,d,x[k+1], S31,0xA4BEEA44); d=HH(d,a,b,c,x[k+4], S32,0x4BDECFA9); c=HH(c,d,a,b,x[k+7], S33,0xF6BB4B60); b=HH(b,c,d,a,x[k+10],S34,0xBEBFBC70); a=HH(a,b,c,d,x[k+13],S31,0x289B7EC6); d=HH(d,a,b,c,x[k+0], S32,0xEAA127FA); c=HH(c,d,a,b,x[k+3], S33,0xD4EF3085); b=HH(b,c,d,a,x[k+6], S34,0x4881D05); a=HH(a,b,c,d,x[k+9], S31,0xD9D4D039); d=HH(d,a,b,c,x[k+12],S32,0xE6DB99E5); c=HH(c,d,a,b,x[k+15],S33,0x1FA27CF8); b=HH(b,c,d,a,x[k+2], S34,0xC4AC5665); a=II(a,b,c,d,x[k+0], S41,0xF4292244); d=II(d,a,b,c,x[k+7], S42,0x432AFF97); c=II(c,d,a,b,x[k+14],S43,0xAB9423A7); b=II(b,c,d,a,x[k+5], S44,0xFC93A039); a=II(a,b,c,d,x[k+12],S41,0x655B59C3); d=II(d,a,b,c,x[k+3], S42,0x8F0CCC92); c=II(c,d,a,b,x[k+10],S43,0xFFEFF47D); b=II(b,c,d,a,x[k+1], S44,0x85845DD1); a=II(a,b,c,d,x[k+8], S41,0x6FA87E4F); d=II(d,a,b,c,x[k+15],S42,0xFE2CE6E0); c=II(c,d,a,b,x[k+6], S43,0xA3014314); b=II(b,c,d,a,x[k+13],S44,0x4E0811A1); a=II(a,b,c,d,x[k+4], S41,0xF7537E82); d=II(d,a,b,c,x[k+11],S42,0xBD3AF235); c=II(c,d,a,b,x[k+2], S43,0x2AD7D2BB); b=II(b,c,d,a,x[k+9], S44,0xEB86D391); a=AddUnsigned(a,AA); b=AddUnsigned(b,BB); c=AddUnsigned(c,CC); d=AddUnsigned(d,DD); } var temp = WordToHex(a)+WordToHex(b)+WordToHex(c)+WordToHex(d); return temp.toLowerCase(); } // -------------------------------------------- // ---------- account menu option ------------- // -------------------------------------------- // Charon's code function buildPrefs() { if (!document.querySelector('#privacy')) return; if (!document.querySelector('#scripts')) { //scripts tab is not built, do it here var scripts = document.querySelector('ul').appendChild(document.createElement('li')); scripts.id = 'scripts'; var a = scripts.appendChild(document.createElement('a')); a.href = '#'; var img = a.appendChild(document.createElement('img')); img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAACOElEQVRIibWXu9HsIAyFCQkpgCbUiFpRO2qFBiiAAkgVEjo8N7gjxvZi7/P3jGZfhs96HbEBH1y9dxARiAilFPTeMcZ4a4/wCZSZkVKCiICZQURg5r8Dt9YQY0QIASGEt2Efg5l5Qt1U9W/B27Yh54wQAnLOM9wxxrfz+xa41oqcM1QVtVZs2wZVnfkVEdRafws2M4jINFWFmYGZp+f+2lr7DdjMZusQEcYY6L1DVQ8e+30i8huwt0wpBTlnpJRmjpl5fkdECCG8HO6n4FLKbCERQe/94Z7WGkRktti2bd+DVRUpJZRSlhv23iEiyDkfCu0rsFdyjHEWkKoeFCvGiBjjhKkqYoxP+/sSrKrIOUNEZtF4OB3MzLPQiGhGZ69sV2Ffgkspc7GHkIhQa0UI4dDD/j6EgJTSAe5FaGbPwWOMqVBnc8l0jx3mv6nqUlZXOX8A+9OvNNnz6q3jHnlPr9a5nb0+gPd6vDdXJM/x2XLOMw376XU3TA5gM7sMMYDp6Qp89dBXI/QAvgqX5+gODOAyIk/BrbXbMD0D77vhbER0X1yrzR185VFKCWZ2C77N8eqp9yp0V7mttbn2XGArIbkUkPPk2bYNInJQpjNYRJbQlwRkde3FfwVOKU1ddxgz347Il8DMjBjjHBir4tqr2k/GYu/9Abb6HGN8qNyPwWZ2mdO76v3aY5fBO/PRue/Xrw8CZjbDSkTLHKeUDlHxI/BXYOB/a7mouDf+R83MMMaYk8sr/5UD/j/2nAi155cMxQAAAABJRU5ErkJggg=='; img.align = 'absmiddle'; img.border = '0'; img.style.paddingRight = '10px'; a.appendChild(document.createTextNode('Scripts')); a.addEventListener('click', function (e) { //make our new tab active when clicked, clear out the #guts div and add our settings to it e.stopPropagation(); document.querySelector('.active').className = ''; document.querySelector('#scripts').className = 'active'; document.querySelector('#guts').innerHTML = '<div class="scaffold"></div>'; document.querySelector('#guts').appendChild(getSettings()); }, false); } else { //script tab already exists document.querySelector('#scripts').firstChild.addEventListener('click', function (e) { //some other script is doing the activation work, just add our settings e.stopPropagation(); document.querySelector('#guts').appendChild(getSettings()); }, false); } } function getSettings() { //build our settings and return them for appending var contents = document.createElement('div'); contents.id = 'recipecounterprefs'; var fieldset = contents.appendChild(document.createElement('fieldset')); fieldset.setAttribute('style', 'width:33%; margin-top:20px'); var legend = fieldset.appendChild(document.createElement('legend')); legend.className = 'subhead'; legend.textContent = 'Recipe Counter'; var section = fieldset.appendChild(document.createElement('div')); section.className = 'indent'; section.appendChild(buildSettings()); return contents; } function buildSettings() { //var ul = document.createElement('ul'); //var li = document.createElement('li'); var ar = document.createElement('a'); ar.setAttribute('href','#'); ar.appendChild(document.createTextNode('Update all recipe lists')); ar.addEventListener('click',openAll,false); ar.setAttribute('title','Note that this opens up 6 new windows.'); //li.appendChild(ar); //ul.appendChild(li); return ar; } function openAll() { window.open('http://kol.coldfront.net/thekolwiki/index.php/Cocktailcrafting_Discoveries','Cocktailcrafting Discoveries'); window.open('http://kol.coldfront.net/thekolwiki/index.php/Cooking_Discoveries','Cooking Discoveries'); window.open('http://kol.coldfront.net/thekolwiki/index.php/Meat-Pasting_Discoveries','Meat-Pasting Discoveries'); window.open('http://kol.coldfront.net/thekolwiki/index.php/Meatsmithing_Discoveries','Meatsmithing Discoveries'); window.open('http://kol.coldfront.net/thekolwiki/index.php/Miscellaneous_Discoveries','Miscellaneous Discoveries'); } if (window.location.href.indexOf('http://kol.coldfront.net/thekolwiki/index.php/')>=0) { gather(getPageMD5(document.body.innerHTML)); } else if (window.location.pathname.indexOf('/account.php')==0) { buildPrefs(); } else { checkDiscoveries(); doPage(); }