NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name bb_extra
// @version 0.6.9
// @description Display extra information in the Blood Brothers wikia familiar pages
// @include http://bloodbrothersgame.wikia.com/wiki/*
// @copyright 2014, Chin
// @run-at document-end
// @grant none
// ==/UserScript==
/////////////////////////////////////////////////////////////////////////////////////
// Preference section
// Change to false if you don't want something to be displayed
/////////////////////////////////////////////////////////////////////////////////////
var displayTotalPE = true;
var displayTotalPOPE = true;
var displayTier = true;
var displaySkill = true;
/////////////////////////////////////////////////////////////////////////////////////
// Code section
/////////////////////////////////////////////////////////////////////////////////////
var data = {
hpMax: 0,
atkMax: 0,
defMax: 0,
wisMax: 0,
agiMax: 0,
hpPE: 0,
atkPE: 0,
defPE: 0,
wisPE: 0,
agiPE: 0,
hpPOPE: 0,
atkPOPE: 0,
defPOPE: 0,
wisPOPE: 0,
agiPOPE: 0,
pvpTier: "N/A",
raidTier: "N/A",
towerTier: "N/A",
price: "N/A",
priceDate:"",
category: "",
statTable: "",
isFinalEvolution: false
};
var tierURL = [];
tierURL.pvp = "http://bloodbrothersgame.wikia.com/index.php?title=Familiar_Tier_List/PvP&action=render";
tierURL.raid = "http://bloodbrothersgame.wikia.com/index.php?title=Familiar_Tier_List/Raid&action=render";
tierURL.tower = "http://bloodbrothersgame.wikia.com/index.php?title=Familiar_Tier_List/Tower&action=render";
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function endsWith(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
function getStats () {
function onFinishCalculatedPOPE() {
if (displayTotalPE || displayTotalPOPE) addTotalStats();
}
/**
* Parse the POPE info from the POPE table, then add it to our page
*/
function getPOPEFromTable() {
// parse the response text into DOM
var doc = document.implementation.createHTMLDocument("POPE");
doc.documentElement.innerHTML = sessionStorage.popeTable;
var famName = (document.getElementById("WikiaPageHeader").getElementsByTagName("h1"))[0].innerHTML.trim();
var table = (doc.getElementsByClassName("wikitable"))[0];
var rows = (table.getElementsByTagName("tbody"))[0].getElementsByTagName("tr");
for (var i = rows.length - 1; i >= 2; i--) {
try {
var cells = rows[i].getElementsByTagName("td");
var cellFam = (cells[2].innerText || cells[2].textContent).trim();
if (cellFam == famName) {
data.hpPOPE = parseInt((cells[5].innerText || cells[5].textContent).replace(/,/g, ""));
data.atkPOPE = parseInt((cells[6].innerText || cells[6].textContent).replace(/,/g, ""));
data.defPOPE = parseInt((cells[7].innerText || cells[7].textContent).replace(/,/g, ""));
data.wisPOPE = parseInt((cells[8].innerText || cells[8].textContent).replace(/,/g, ""));
data.agiPOPE = parseInt((cells[9].innerText || cells[9].textContent).replace(/,/g, ""));
}
} catch (e) {}
}
onFinishCalculatedPOPE();
}
data.statTable = document.getElementsByClassName("article-table");
var rowPE = ((data.statTable[0].getElementsByTagName("tbody"))[0].getElementsByTagName("tr"))[3];
//PE stats
data.hpPE = parseInt((rowPE.getElementsByTagName("td"))[1].childNodes[0].nodeValue.replace(/,/g, ""));
data.atkPE = parseInt((rowPE.getElementsByTagName("td"))[2].childNodes[0].nodeValue.replace(/,/g, ""));
data.defPE = parseInt((rowPE.getElementsByTagName("td"))[3].childNodes[0].nodeValue.replace(/,/g, ""));
data.wisPE = parseInt((rowPE.getElementsByTagName("td"))[4].childNodes[0].nodeValue.replace(/,/g, ""));
data.agiPE = parseInt((rowPE.getElementsByTagName("td"))[5].childNodes[0].nodeValue.replace(/,/g, ""));
data.isFinalEvolution = (document.getElementsByClassName("container")[0]).innerHTML.indexOf("Final Evolution") != -1;
data.category = ((document.getElementsByClassName("name"))[0].getElementsByTagName("a"))[0].childNodes[0].nodeValue;
if (data.isFinalEvolution) {
var toAdd = 0;
if (endsWith(data.category, "1")) toAdd = 500; // 1 star
else if (endsWith(data.category, "2")) toAdd = 550; // 2 star
else if (endsWith(data.category, "3")) toAdd = 605; // 3 star
if (endsWith(data.category, "1")) {
// we generally don't care about the max stats, but in this case (1 star) we do
var rowMax = ((data.statTable[0].getElementsByTagName("tbody"))[0].getElementsByTagName("tr"))[2];
data.hpMax = parseInt((rowMax.getElementsByTagName("td"))[1].childNodes[0].nodeValue.replace(/,/g, ""));
data.atkMax = parseInt((rowMax.getElementsByTagName("td"))[2].childNodes[0].nodeValue.replace(/,/g, ""));
data.defMax = parseInt((rowMax.getElementsByTagName("td"))[3].childNodes[0].nodeValue.replace(/,/g, ""));
data.wisMax = parseInt((rowMax.getElementsByTagName("td"))[4].childNodes[0].nodeValue.replace(/,/g, ""));
data.agiMax = parseInt((rowMax.getElementsByTagName("td"))[5].childNodes[0].nodeValue.replace(/,/g, ""));
data.hpPOPE = data.hpMax + toAdd;
data.atkPOPE = data.atkMax + toAdd;
data.defPOPE = data.defMax + toAdd;
data.wisPOPE = data.wisMax + toAdd;
data.agiPOPE = data.agiMax + toAdd;
onFinishCalculatedPOPE();
}
else if (!endsWith(data.category, "4")){
data.hpPOPE = data.hpPE + toAdd;
data.atkPOPE = data.atkPE + toAdd;
data.defPOPE = data.defPE + toAdd;
data.wisPOPE = data.wisPE + toAdd;
data.agiPOPE = data.agiPE + toAdd;
onFinishCalculatedPOPE();
}
else {
// only fetch the POPE stat table when it's a 4-star familiar
if (!sessionStorage.popeTable) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
sessionStorage.popeTable = xmlhttp.responseText;
getPOPEFromTable();
}
};
xmlhttp.open("GET", "http://bloodbrothersgame.wikia.com/wiki/POPE_Stats_Table", true);
xmlhttp.send();
console.log("Fetching POPE table");
}
else {
// already cached, just parse it and get the result
getPOPEFromTable();
}
}
}
}
/**
* Inject the total stats HTML into the page
*/
function addTotalStats() {
var totalPE = data.hpPE + data.atkPE + data.defPE + data.wisPE + data.agiPE;
var totalPEText = (isNaN(totalPE) || totalPE == 0)? "N/A" : numberWithCommas(totalPE);
var totalPOPE = data.hpPOPE + data.atkPOPE + data.defPOPE + data.wisPOPE + data.agiPOPE;
var totalPOPEText = (isNaN(totalPOPE) || totalPOPE == 0)? "N/A" : numberWithCommas(totalPOPE);
var newText = "";
if (!displayTotalPOPE && displayTotalPE)
newText = "<tr><td style='text-align:center;padding:0em;'><span style='border-bottom: 1px dotted; font-weight: bold; padding: 0em' title='Total PE stats'><a>Total</a></span></td><td></td><td></td><td></td><td></td><td>"
+ totalPEText + "</td></tr>";
else if (displayTotalPOPE && !displayTotalPE)
newText = "<tr><td style='text-align:center;padding:0em;'><span style='border-bottom: 1px dotted; font-weight: bold; padding: 0em' title='Total POPE stats'><a>Total</a></span></td><td></td><td></td><td></td><td></td><td>"
+ totalPOPEText + "</td></tr>";
else if (displayTotalPOPE && displayTotalPE)
newText = "<tr><td style='text-align:center;padding:0em;'><span style='border-bottom: 1px dotted; font-weight: bold; padding: 0em' title='Total PE stats and total POPE stats'><a>Total</a></span></td><td></td><td></td><td></td><td>"
+ totalPEText + "</td><td>"
+ totalPOPEText + "</td></tr>";
// add the new row to tbody
(data.statTable[0].getElementsByTagName("tbody"))[0].innerHTML += newText;
// or add it directly to the PE row, but can cause overflow in small screens
//var addedPETotalText = "<td>" + numberWithCommas(totalPE) + "</td>";
//rowPE.innerHTML += addedPETotalText;
}
/*
* Initially, call getPvP(), which has getRaid() as callback,
* getRaid() has getTower() as callback
* and finally, getTower() has addTierInfo() as callback
* Ideally, getPvP(), getRaid() and getTower() should be done in parallel instead of
* being done serially like this, but that's for later
*/
function getTierInfo () {
function getPvP() {
// fetch the pvp tier page
if (!sessionStorage.pvp) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
sessionStorage.pvp = xmlhttp.responseText;
data.pvp = getTier("pvp");
getRaid();
}
};
xmlhttp.open("GET", tierURL.pvp, true);
xmlhttp.send();
sessionStorage.pvp = xmlhttp.responseText;
console.log("Fetching pvp tier");
}
else {
data.pvp = getTier("pvp");
getRaid();
}
}
function getRaid() {
// fetch the raid tier page
if (!sessionStorage.raid) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
sessionStorage.raid = xmlhttp.responseText;
data.raid = getTier("raid");
getTower();
}
};
xmlhttp.open("GET", tierURL.raid, true);
xmlhttp.send();
sessionStorage.raid = xmlhttp.responseText;
console.log("Fetching raid tier");
}
else {
data.raid = getTier("raid");
getTower();
}
}
function getTower() {
// fetch the tower tier page
if (!sessionStorage.tower) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
sessionStorage.tower = xmlhttp.responseText;
data.tower = getTier("tower");
addTierInfo();
}
};
xmlhttp.open("GET", tierURL.tower, true);
xmlhttp.send();
sessionStorage.tower = xmlhttp.responseText;
console.log("Fetching tower tier");
}
else {
data.tower = getTier("tower");
addTierInfo();
}
}
function getTier(category) {
// parse the response text into DOM
var tierResult = "N/A";
var tierTable = "";
var doc = document.implementation.createHTMLDocument("Tier");
doc.documentElement.innerHTML = sessionStorage[category];
var tables = doc.getElementsByClassName("wikitable");
if (!tables) {
return tierResult;
}
var famName = (document.getElementById("WikiaPageHeader").getElementsByTagName("h1"))[0].innerHTML;
for (var i = 0; i < tables.length; i++){
if (!tables[i])
break;
var items = tables[i].innerHTML;
if (items.indexOf(famName) != -1) {
tierTable = tables[i].id;
tierResult = tierTable.substr(5).replace(".2B", "+");
console.log("Tier: " + tierResult);
break;
}
}
return tierResult;
}
getPvP();
}
/*
* Add the tier info row to the stat table
* This has to be called AFTER the tiers info have all been fetched
*/
function addTierInfo () {
var table = (document.getElementsByClassName("article-table"))[0];
var newText = "<tr>" +
"<td style='text-align:center;padding:0em;'><span style='border-bottom: 1px dotted; font-weight: bold; padding: 0em' title='PVP tier'><a>PVP</a></span></td><td>"
+ data.pvp + "</td><td style='text-align:center;padding:0em;'><span style='border-bottom: 1px dotted; font-weight: bold; padding: 0em' title='Raid tier'><a>Raid</a></span></td><td>"
+ data.raid + "</td><td style='text-align:center;padding:0em;'><span style='border-bottom: 1px dotted; font-weight: bold; padding: 0em' title='Tower tier'><a>Tower</a></span></td><td>"
+ data.tower + "</td></tr>";
// add the new row to tbody
(table.getElementsByTagName("tbody"))[0].innerHTML += newText;
}
function addSkillInfo () {
// get the list of skills
var skillList = (((document.getElementsByClassName("infobox"))[0].getElementsByTagName("tr"))[3]).getElementsByTagName("a");
var skillLink1 = skillList[0].getAttribute("href");
if (!sessionStorage[skillLink1]) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
sessionStorage[skillLink1] = xmlhttp.responseText;
skill1();
}
};
xmlhttp.open("GET", skillLink1, true);
xmlhttp.send();
}
else {
skill1();
}
function skill1 () {
// parse the response text into DOM
var doc = document.implementation.createHTMLDocument("Skill");
doc.documentElement.innerHTML = sessionStorage[skillLink1];
// get the skill info box
var infoBox = (doc.getElementsByClassName("infobox"))[0];
// insert the skill box to the side
var content = document.getElementsByClassName("WikiaPageContentWrapper")[0];
var rail = document.getElementById("WikiaRail");
content.insertBefore(infoBox, rail)
}
function skill2 () {
// parse the response text into DOM
var doc = document.implementation.createHTMLDocument("Skill");
doc.documentElement.innerHTML = sessionStorage[skillLink2];
// get the skill info box
var infoBox = (doc.getElementsByClassName("infobox"))[0];
// insert the skill box to the side
var content = document.getElementsByClassName("WikiaPageContentWrapper")[0];
var rail = document.getElementById("WikiaRail");
content.insertBefore(infoBox, rail)
}
// if there's a second skill, add it too
if (!(typeof skillList[1] === 'undefined')) {
var skillLink2 = skillList[1].getAttribute("href");
if (!sessionStorage[skillLink2]) {
var xmlhttp2 = new XMLHttpRequest();
xmlhttp2.onreadystatechange = function() {
if (xmlhttp2.readyState == 4 && xmlhttp2.status == 200) {
sessionStorage[skillLink2] = xmlhttp2.responseText;
skill2();
}
};
xmlhttp2.open("GET", skillLink2, true);
xmlhttp2.send();
}
else {
skill2();
}
}
}
try {
getStats();
if (displayTier) getTierInfo();
if (displaySkill) addSkillInfo();
}
catch (err) {
console.log("error: " + err);
console.log("bb_extra error: probably not a fam page");
}