BvS Candyween Helper

Calculates probabilities of each choice in Candyween houses

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name           BvS Candyween Helper
// @namespace      Garyzx
// @description    Calculates probabilities of each choice in Candyween houses
// @include        http*://*animecubed.com/billy/bvs/villagecandyween.html
// @include        http*://*animecubedgaming.com/billy/bvs/villagecandyween.html
// @version        1.08
// @history        1.08 New domain - animecubedgaming.com - Channel28
// @history        1.07 Now https compatible (Updated by Channel28)
// @history        1.06 Recognise Retail Power (thanks to Terrec)
// @history        1.05 Displays chances without visiting each house
// @history        1.04 Display data at the end, even if ads are turned off (thanks Thosha!)
// @history        1.04 Update probabilities
// @history        1.03 Replace eval() with closures to satisfy Greasemonkey restrictions (thanks to portwizard for finding the problem)
// @history        1.02 Remove debugging output (oops)
// @history        1.01 Auto-select first unvisited house
// @history        1.01 Log Party/Psycho data and format data for forums
// @history        1.01 Allow Candying at Party houses
// @history        1.00 Initial version
// @grant          none
// ==/UserScript==

var exts={};
exts["Decrepit"]="old";
exts["Creepy"]="creepy";
exts["Typical"]="typical";
exts["Spooky"]="spooky";
exts["Bright"]="silly";

var ints={};
ints["Candy"]=["big handfuls", "just giving", "tasty candy"];
ints["Party"]=["rocking party", "Come on in", "new dance"];
ints["Psycho"]=["wangly eye", "claw your way", "trigger a trapdoor"];

var cond={};
cond["Candy"]={Decrepit: 678, Creepy: 766, Typical: 700, Spooky: 691, Bright: 763};
cond["Party"]={Decrepit: 517, Creepy: 476, Typical: 478, Spooky: 444, Bright: 0};
cond["Psycho"]={Decrepit: 0, Creepy: 173, Typical: 165, Spooky: 141, Bright: 167};

var actions={};
actions["Party"]=["Hit On Somebody", "Rock Out", "Mope", "Tell Funny Stories"];
actions["Psycho"]=["Hide In The Closet", "Get An Axe", "Burn the Place Down", "Scream and Cower"];

function normalize(obj){
	var total=0;
	for(var i in obj)
		total+=obj[i];
	for(var i in obj)
		obj[i]/=total;
}

function get(key, def){
	var val;
	if(val=localStorage.getItem("candyween."+key))
		return val;
	return def;
}

function set(key, val){
	localStorage.setItem("candyween."+key, val)
}

var data=get("data", ",;,;,;,;,;,;,;,;,;,").split(";");
for(var n=0; n<10; n++)
	data[n]=data[n].split(",");

if(document.body.innerHTML.match("Visit a House")){
   var table_items = document.evaluate("//form[@name='cw1']/table/tbody/tr/td", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
   for (var i = 0; i < 10; i++){
      for(var n in exts)
         if(table_items.snapshotItem(i).innerHTML.match(exts[n]))
            data[i][0]=n;
   }
   var retail = document.body.textContent.match(/House #(\d+) is a Candy/);
   if(retail) {
      data[retail[1]-1][1]="Candy";
   }
}

if(document.body.innerHTML.match(/>House #[0-9]+<\/font>/)){
	var houseNum=parseInt(document.body.innerHTML.match(/>House #([0-9]+)<\/font>/)[1])-1;
	if(document.body.innerHTML.match("think"))
	for(var i in ints){
		if(document.body.innerHTML.match("IS a "+i))
		data[houseNum][1]=i;
		else if(document.body.innerHTML.match("a "+i))
		data[houseNum][1]="Not "+i;
		}
	for(var i in ints)
	for(var j in ints[i])
	if(document.body.innerHTML.match(ints[i][j]))
	data[houseNum][1]=i;
	set("lastHouse", houseNum);
	set("lastAct", "");
}

if(document.body.innerHTML.match("Pick an Action")){
	for(var n=1; n<=4; n++)
		document.getElementById("spact"+n).addEventListener("focus", function(){
			set("lastAct", this.value);
		}, false);
}

if(get("lastAct")){
	var n=parseInt(get("lastAct"));
	var result="";
	if(document.body.innerHTML.match(/That choice's result:<br><b>[^<]+</))
		result=document.body.innerHTML.match(/That choice's result:<br><b>([^<]+)</)[1];
	else if(document.body.innerHTML.match(/You Got [^!]+!/))
		result=document.body.innerHTML.match(/You Got ([^!]+)!/)[1];
	else if(document.body.innerHTML.match(/4 Time/))
		result="-4 Time";
	if(result){
		set("lastAct", "");
		var games=JSON.parse(get("minigames", "[]"));
		games.push([parseInt(get("lastHouse")), n-1, result]);
		set("minigames", JSON.stringify(games));
	}
}

for(var i in cond)
	normalize(cond[i]);

var probs=[];
for(var n=0; n<10; n++){
	probs[n]={};
	for(var i in ints)
		probs[n][i]=0;
}

var notCandy=[];
for(notCandy[0]=0; notCandy[0]<7; notCandy[0]++)
for(notCandy[1]=notCandy[0]+1; notCandy[1]<8; notCandy[1]++)
for(notCandy[2]=notCandy[1]+1; notCandy[2]<9; notCandy[2]++)
for(notCandy[3]=notCandy[2]+1; notCandy[3]<10; notCandy[3]++)
for(var psycho=0; psycho<4; psycho++){
	var houses=[];
	for(var n=0; n<10; n++)
		houses[n]="Candy";
	for(var n=0; n<4; n++)
		houses[notCandy[n]]="Party";
	houses[notCandy[psycho]]="Psycho";
	var prob=1;
	for(var n=0; n<10; n++){
		if(data[n][0])
			prob*=cond[houses[n]][data[n][0]];
		if(data[n][1]){
			if(data[n][1].match("Not")){
				if(data[n][1].match(houses[n])){
					prob=0;
					break;
				}
			}
			else
				if(!data[n][1].match(houses[n])){
					prob=0;
					break;
				}
		}
	}
	for(var n=0; n<10; n++)
		probs[n][houses[n]]+=prob;
}

for(var n=0; n<10; n++){
	normalize(probs[n]);
	for(var i in probs[n])
		if(probs[n][i]>0.9999)
			data[n][1]=i;
	var body="";
	for(var i in probs[n])
		if(probs[n][i]>0.0001)
			body+=Math.round(probs[n][i]*1000)/10+"% "+i+", ";
	body=body.substr(0, body.length-2);
	var header="?", color="redswitch=[1]";
	if(data[n][0]){
		header=data[n][0];
		color="";
	}
	if(data[n][1]){
		header+=", "+data[n][1];
		if(!data[n][1].match("Not"))
			color="greenswitch=[1]";
	}
	if(document.body.innerHTML.match("Visit a House"))
		document.evaluate("//label[@for='house"+(n+1)+"']", document, null, XPathResult.ANY_TYPE, null).iterateNext().title
				="header=["+header+"] body=["+body+"] "+color;
}

var maximized="";
function maximize(int){
	if(avoiding==int){
		maximized=int;
		avoid(avoiding);
		return;
	}
	var max=0;
	for(var n=0; n<10; n++)
		if(!document.getElementById("house"+(n+1)).disabled && probs[n][int]>max){
			max=probs[n][int];
			document.getElementById("house"+(n+1)).click();
		}
	if(max==0){
		if(avoiding)
			alert("All "+int+" houses are "+avoiding+" houses!");
		else
			alert("No more "+int+" houses!");
	}
	else
		maximized=int;
}

function minimize(int){
	var min=1;
	for(var n=0; n<10; n++)
		if(!document.getElementById("house"+(n+1)).disabled && probs[n][int]<min){
			min=probs[n][int];
			document.getElementById("house"+(n+1)).click();
		}
	if(min==1)
		alert("All remaining houses are "+int+"houses!");
}

var avoiding="";
function avoid(int){
	if(avoiding==int){
		for(var n=0; n<10; n++)
			document.getElementById("house"+(n+1)).disabled=visited[n];
		avoiding="";
		if(maximized)
			window.setTimeout(function() {maximize(maximized);}, 100);
		document.getElementById("avoid"+int).value="Avoid "+int+" houses";
	}
	else{
		avoiding=int;
		for(var n=0; n<10; n++)
			if(probs[n][int]>0.0001){
				document.getElementById("house"+(n+1)).disabled=true;
				document.getElementById("house"+(n+1)).checked=false;
			}
			else
				document.getElementById("house"+(n+1)).disabled=visited[n];
		if(maximized && maximized!=int)
			window.setTimeout(function() {maximize(maximized);}, 100);
		for(var i in ints)
			if(document.getElementById("avoid"+i))
				document.getElementById("avoid"+i).value="Avoid "+i+" houses";
		document.getElementById("avoid"+int).value="Unavoid "+int+" houses";
	}
}

if(document.body.innerHTML.match("Perform")){
	var houseNum=parseInt(document.body.innerHTML.match(/>House #([0-9]+)<\/font>/)[1])-1;
	var results=["Candy", "Party", "Psycho"];
	for(var n=0; n<3; n++){
		document.evaluate("//*[@for='ha"+(n+1)+"']", document, null, XPathResult.ANY_TYPE, null)
				.iterateNext().innerHTML+=" ("+Math.round(probs[houseNum][results[n]]*1000)/10+"%)";
		if(probs[houseNum][results[n]]<0.0001 && !(results[n]=="Candy" && probs[houseNum]["Party"]>0.9999))
			document.getElementById("ha"+(n+1)).disabled=true;
		else if(probs[houseNum][results[n]]>0.9999)
			document.getElementById("ha"+(n+1)).click();
	}
}
else if(document.body.innerHTML.match("Visit")){
	var visited=[];
	for(var n=0; n<10; n++)
		visited[n]=document.getElementById("house"+(n+1)).disabled;
	var div=document.createElement("div");
	document.forms.namedItem("cw1").appendChild(div);
	div.appendChild(document.createElement("br"));
	var table=document.createElement("table");
	for(var n=0; n<2; n++){
		var tr=document.createElement("tr");
		for(var i in ints){
			var td=document.createElement("td");
			var a=document.createElement("input");
			a.type="button";
			if(n==0){
				a.value="Maximize "+i+" chance";
				(function(j){a.addEventListener("click", function(){maximize(j);}, true)})(i);
			}
			else{
				var avoidable=false;
				for(var j=0; j<10; j++)
					if(!document.getElementById("house"+(j+1)).disabled && probs[j][i]<0.0001)
						avoidable=true;
				if(avoidable){
					a.value="Avoid "+i+" houses";
					a.id="avoid"+i;
					(function(j){a.addEventListener("click", function(){avoid(j);}, true)})(i);
				}
				else{
					a.value="Minimize "+i+" chance";
					(function(j){a.addEventListener("click", function(){minimize(j);}, true)})(i);
				}
			}
			td.appendChild(a);
			tr.appendChild(td);
		}
		table.appendChild(tr);
	}
	div.appendChild(table);
	var complete=true, next=-1;
	for(var i=0; i<10; i++)
		if(!data[i][0]){
			complete=false;
			if(next==-1)
				next=i+1;
		}
	if(!complete){
		div.appendChild(document.createElement("br"));
		var note=document.createElement("div");
		note.innerHTML="For optimal results, visit all houses once first.";
		note.style.fontWeight="bold";
		note.style.fontVariant="small-caps";
		note.style.fontStyle="italic";
		div.appendChild(note);
		document.getElementById("house"+next).click();
	}
	div.appendChild(document.createElement("br"));
	var a=document.createElement("a");
	a.innerHTML="Clear data";
	a.href="#";
	a.addEventListener("click", function(){
		if(confirm("Are you sure you want to clear all data?\nThis cannot be undone.")){
			for(var i in data)
				for(var j in data[i])
					data[i][j]="";
			set("data", ",;,;,;,;,;,;,;,;,;,");
			set("minigames", "[]");
			alert("Data cleared.");
		}
	}, true);
	a.style.fontSize="12px";
	a.style.color="black";
	a.style.fontWeight="bold";
	div.appendChild(a);
}
else if(document.body.innerHTML.match("See you")){
	var div=document.createElement("div");
	var area=document.createElement("textarea");
	var minigames=JSON.parse(get("minigames", "[]"));
	var output=[];
	for(var n=0; n<10; n++){
		output[n]=(n+1)+". ";
		if(data[n][0])
			output[n]+=data[n][0];
		if(data[n][1])
			output[n]+=" - "+data[n][1];
	}
	for(var n in minigames)
		output[minigames[n][0]]+=" ("+actions[data[minigames[n][0]][1]][minigames[n][1]]+": "+minigames[n][2]+")";
	area.value="Ally: "+get("ally")+"\n\n";
	for(var n=0; n<10; n++)
		area.value+=output[n]+"\n";
	area.rows=14;
	area.cols=60;
	area.addEventListener("focus", function(){this.select()}, false);
	div.innerHTML="Please <a href='/billy/forum/posting.php?mode=reply&f=36&t=16645' target='_blank'>post</a>"+
			" the below into <a href='/billy/forum/viewtopic.php?f=36&t=16645' target='_blank'>this thread</a>.<br><br>";
	div.appendChild(area);
	document.evaluate("//table[@width=510]/tbody/tr/td",
			document, null, XPathResult.ANY_TYPE, null ).iterateNext().appendChild(div);
}
else if(document.body.innerHTML.match("Choose Partner") || document.body.innerHTML.match("You chose")){
	for(var i in data)
		for(var j in data[i])
			data[i][j]="";
	set("minigames", "[]");
	if(document.body.innerHTML.match("You chose")){
		set("ally", document.body.innerHTML.match(/You chose ([^!]+)!/)[1]);
	}
}

for(var n=0; n<10; n++)
	data[n]=data[n].join(",");
set("data", data.join(";"));