您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Helps with solving the detective school puzzles in Kingdom of Loathing
当前为
// ==UserScript== // @name KoL Detective Helper // @namespace kol.interface.unfinished // @description Helps with solving the detective school puzzles in Kingdom of Loathing // @include https://*kingdomofloathing.com/wham.php* // @grant GM_setValue // @grant GM_getValue // @version 1.2 // ==/UserScript== // Version 1.2 // - highlight areas on hover over questions // Version 1.1 // - include possible responses in lists of people and jobs, so they can be recognized in answers prior to visiting // Version 1.0.1 // - highlight active row better // Version 1.0 var titleKey; var places; var person; var people; var jobs; var personPlaceJob = {}; var personSays = {}; function getTitle() { var t = document.evaluate( '//b[contains(.,"Who killed ")]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); if (t.singleNodeValue) { var title = t.singleNodeValue.innerHTML; // console.log('title is '+title); titleKey = title; var tt = document.evaluate( '//td[contains(.,"You have been on this case for ")]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); if (tt.singleNodeValue) { var re = tt.singleNodeValue.innerHTML.match(/You have been on this case for ([0-9][0-9]*) minute/); if (re) { var mins = re[1]; // console.log('minutes is '+mins); if (mins!=0) getTruthAndLies(); } } } } function gatherLocations() { var rc = []; var locs = document.evaluate( '//a[contains(@href,"wham.php?visit=")]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); for (var i=0;i<locs.snapshotLength;i++) { var loc = locs.snapshotItem(i); var aloc = loc.firstChild.firstChild.innerHTML; rc[rc.length] = aloc; // console.log('location: '+aloc); } return rc; } function gatherPeople() { var rc = []; for (var p in personPlaceJob) { rc[rc.length] = p; } return rc; } function gatherJobs() { var rc = []; for (var p in personPlaceJob) { rc[rc.length] = personPlaceJob[p].job; } return rc; } function highlightHover(e) { var tgt = this.getAttribute('tgt'); var tgtnode = document.evaluate( '//a[@href="wham.php?visit='+tgt+'"]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE,null); if (tgtnode.singleNodeValue) { tgtnode.singleNodeValue.setAttribute('style','color:blue;'); tgtnode.singleNodeValue.firstChild.setAttribute('size','3'); } } function unhighlightHover(e) { var tgt = this.getAttribute('tgt'); var tgtnode = document.evaluate( '//a[@href="wham.php?visit='+tgt+'"]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE,null); if (tgtnode.singleNodeValue) { tgtnode.singleNodeValue.setAttribute('style',''); tgtnode.singleNodeValue.firstChild.setAttribute('size','2'); } } function gatherMorePeople(people) { var re = /^[A-Z][a-z][A-Za-z]* [A-Z][a-z][A-Za-z]*(\s[A-Z][a-z][A-Za-z]*)?$/; var rea = /^wham\.php\?ask=([1-9])/; var asks = document.evaluate( '//a[contains(@href,"wham.php?ask=")]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); for (var i=0;i<asks.snapshotLength;i++) { var a = asks.snapshotItem(i); var subj = a.innerHTML; if (subj.match(re)) { if (people.indexOf(subj)<0) { people[people.length] = subj; } //console.log('Extra person: '+subj); } var m = a.getAttribute('href').match(rea); if (m) { a.setAttribute('tgt',m[1]); a.addEventListener('mouseover',highlightHover,false); a.addEventListener('mouseout',unhighlightHover,false); } } } function gatherMoreJobs(jobs) { var re = /^the victim's ([-a-z ]*)$/; var rea = /^wham\.php\?ask=rel&w=([1-9])/; var asks = document.evaluate( '//a[contains(@href,"wham.php?ask=rel")]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); for (var i=0;i<asks.snapshotLength;i++) { var a = asks.snapshotItem(i); var subj = a.innerHTML; var w = subj.match(re); if (w) { if (jobs.indexOf(w[1])<0) { jobs[jobs.length] = w[1]; //console.log('Extra job: '+w[1]); } } var m = a.getAttribute('href').match(rea); if (m) { a.setAttribute('tgt',m[1]); a.addEventListener('mouseover',highlightHover,false); a.addEventListener('mouseout',unhighlightHover,false); } } } // ------------------------------------------------- function gatherPerson() { var p = document.evaluate( '//input[@value="Accuse!"]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); if (p.singleNodeValue) { p = document.evaluate( './/b', p.singleNodeValue.parentNode.parentNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); if (p.singleNodeValue) { person = p.singleNodeValue.innerHTML; var role = String(p.singleNodeValue.nextSibling.nextSibling.nextSibling.nodeValue).trim(); var loc = String(p.singleNodeValue.nextSibling.nextSibling.nextSibling.nextSibling.innerHTML).trim().replace(")","").replace("(",""); //console.log(person+', '+role+' is at '+loc); var peep = personPlaceJob[person]; if (peep) { peep.job = role; peep.place = loc; } else { personPlaceJob[person] = { job:role, place:loc }; } if (people.indexOf(person)<0) people[people.length] = person; if (jobs.indexOf(role)<0) jobs[jobs.length] = role; //console.log('Person: '+person); } } } function gatherAnswer(person) { if (!person) { return; } var a = document.evaluate( '//td[@colspan="2" and @width="500"]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); if (a.singleNodeValue) { var t = a.singleNodeValue.innerHTML; var p,l,j; var accused = checkAccused(t); //console.log('accused? ' + accused); for (var i in people) { var re = new RegExp('\\b'+people[i]+'\\b'); if (re.test(t)) { p = people[i]; //console.log('Talking about person '+p); } } for (var i in places) { var re = new RegExp('\\b'+places[i]+'\\b'); if (re.test(t)) { if (!l || l.length<places[i].length) { l = places[i]; } //console.log('Talking about location '+l); } } var ts = t.replace(/I don't know how s*he got stuck with [a-z -]* like me, either\./,''); // console.log('looking for jobs'); for (var i in jobs) { var re = new RegExp('\\b'+jobs[i]+'\\b'); var w = ts.search(re); if (w>=3 && ts.substr(w-3,3).toLowerCase()!="ex-") { if (!j || j.length<jobs[i].length) { j = jobs[i]; } // console.log('Talking about job '+j); } } var map = personSays[person]; if (!map) { map = new Object(); personSays[person] = map; } if (p && l) { //console.log(p + ' -> ' + l); map[p+'.place'] = l; } if (p && j) { //console.log(p + ' -> ' + j); map[p+'.job'] = j; } if (l && j) { //console.log(l + ' -> ' + j); map[l] = j; } if (accused) { if (p) map.accused = p; else if (j) map.accused = j; else map.accused = 'n/a'; } } } function checkAccused(text) { var re = /("Do you have any thoughts on who did it\?" you ask.|"Help me out here," you say\. "You know all the people in this house. Who's the most likely killer\?"|"Who do you think is the most likely to be the killer\?" you ask\.|"Who do you think the killer is\?" you ask.|"Does anyone else here seem particularly suspicious to you\?" you ask\.|"If you had to guess," you ask, "who would you say did it\?")/; return re.test(text); } // ------------------------------------------------- function saveTruthAndLies() { GM_setValue('truth',JSON.stringify(personPlaceJob)); GM_setValue('lies',JSON.stringify(personSays)); // var i = 1; // // console.log('Truth:'); // for (var p in personPlaceJob) { // console.log(i+'. '+p+': '+personPlaceJob[p].job+', '+personPlaceJob[p].place); // i = i+1; // } // // console.log('Lies:'); // i = 1; // for (var p in personSays) { // var ps = personSays[p]; // var s = ''; // for (var rel in ps) { // if (s) // s += ', '; // s += rel+':'+ps[rel]; // } // console.log(i+'. '+p+' says '+s); // i = i+1; // } } function getTruthAndLies() { var t = GM_getValue('truth',''); if (t) { personPlaceJob = JSON.parse(t); } var lies = GM_getValue('lies',''); if (lies) { personSays = JSON.parse(lies); } } function abbreviateName(name) { var re = /^([A-Z])[a-zA-Z]* ([A-Z])[a-zA-Z]*(\s?([A-Z]))?/; var m = name.match(re); if (m) { if (m[4]) return m[1]+m[2]+m[4]; return m[1]+m[2]; } return name; } function display() { var tbl = document.createElement('table'); tbl.setAttribute('style','width:95%;font-size:9pt;border-collapse:collapse;border:1px solid black;'); tbl.setAttribute('cellpadding','3'); tbl.setAttribute('cellspacing','2'); // headers var c,r = tbl.insertRow(); r.setAttribute('style','border:1px solid black;'); c = r.insertCell(); c.appendChild(document.createTextNode('Perp')); for (var ppl in people) { var name = abbreviateName(people[ppl]); c = r.insertCell(); c.appendChild(document.createTextNode(name)); // c = r.insertCell(); // c.appendChild(document.createTextNode(name)); } for (var loc in places) { c = r.insertCell(); c.appendChild(document.createTextNode(places[loc])); } c = r.insertCell(); c.appendChild(document.createTextNode('Acc')); for (var p in personSays) { r = tbl.insertRow(); var rattrib = "border:1px solid black;"; c = r.insertCell(); if (p==person) { var b = document.createElement('b'); b.appendChild(document.createTextNode(p)); c.appendChild(b); rattrib = rattrib + "background-color:rgb(250,230,230);"; } else { c.appendChild(document.createTextNode(p)); } r.setAttribute('style',rattrib); c.appendChild(document.createElement('br')); if (personPlaceJob[p] && personPlaceJob[p].place) { var b = document.createElement('div'); b.setAttribute('style','font-size:smaller;'); if (personPlaceJob[p].job) { b.appendChild(document.createTextNode(personPlaceJob[p].job)); b.appendChild(document.createElement('br')); } b.appendChild(document.createTextNode(personPlaceJob[p].place)); c.appendChild(b); } for (var ppl in people) { c = r.insertCell(); var place = personSays[p][people[ppl]+'.place']; if (place) { var d = document.createElement('div'); // check truth if (personPlaceJob[people[ppl]] && personPlaceJob[people[ppl]].place) { // we know this association if (personPlaceJob[people[ppl]].place==place) { d.setAttribute('style','color:green;border-bottom:1px solid black;'); } else { d.setAttribute('style','color:red;border-bottom:1px solid black;'); } } else { d.setAttribute('style','color:gray;border-bottom:1px solid black;'); } d.appendChild(document.createTextNode(place)); c.appendChild(d); } else { c.appendChild(document.createElement('br')); } //c = r.insertCell(); //c.appendChild(document.createElement('br')); var job = personSays[p][people[ppl]+'.job']; if (job) { var d = document.createElement('div'); // check truth if (personPlaceJob[people[ppl]] && personPlaceJob[people[ppl]].job) { if (personPlaceJob[people[ppl]] && personPlaceJob[people[ppl]].job==job) { d.setAttribute('style','color:green;border-top:1px solid black;'); } else { d.setAttribute('style','color:red;border-top:1px solid black;'); } } else { d.setAttribute('style','color:gray;border-top:1px solid black;'); } d.appendChild(document.createTextNode(job)); c.appendChild(d); } else { c.appendChild(document.createElement('br')); } } for (var loc in places) { c = r.insertCell(); var job = personSays[p][places[loc]]; if (job) { var d = document.createElement('div'); d.setAttribute('style','color:gray;'); // check truth for (var others in personPlaceJob) { var other = personPlaceJob[others]; if (other.job==job && other.place) { if (other.place==places[loc]) { d.setAttribute('style','color:green;'); } else { d.setAttribute('style','color:red;'); } break; } else if (other.place==places[loc] && other.job) { if (other.job==job) { d.setAttribute('style','color:green;'); } else { d.setAttribute('style','color:red;'); } break; } } d.appendChild(document.createTextNode(job)); c.appendChild(d); } } c = r.insertCell(); if (personSays[p].accused) { c.appendChild(document.createTextNode(personSays[p].accused)); } } document.body.appendChild(tbl); } // ------------------------------------------------- getTitle(); places = gatherLocations(); people = gatherPeople(); jobs = gatherJobs(); gatherPerson(); gatherMorePeople(people); gatherMoreJobs(jobs); gatherAnswer(person); saveTruthAndLies(); display();