BvS Candyween Helper

Calculates probabilities of each choice in Candyween houses

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==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(";"));