NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name bots4 Fight Stats // @version 1.0.1 // @description Displays stats about previous fights while fighting // @author Clay Banger // @match https://bots4.net/* // @grant none // @require https://kryogenix.org/code/browser/sorttable/sorttable.js // @license MIT // @updateURL https://openuserjs.org/meta/Clay_Banger/bots4_Fight_Stats.meta.js // ==/UserScript== var $ = window.jQuery; var WINS=0; var LOSSES=1; var TOTAL_DURATION=2; var TOTAL_EXP=3; var ENERGY_FIGHTS=4; var TOTAL_ENERGY=5; var TOTAL_KUDOS=6; var OPPONENT_LEVEL=7; var OPPONENT_COLOUR=8; var LAST_BATTLED=9; var OPPONENT_ID=10; //cosmetic stuff var BACKGROUND_COLOUR = "#202020"; var BORDER_COLOUR = "#808080"; var TEXT_COLOUR = "#dddddd"; (function() { 'use strict'; //add the link, below HoF to /botsstats $("#left-nav>ul:first").append("<li><a href='/botsstats'>bots stats</a></li>"); if(document.title == "home - bots4"){ //grab the user/bot information and store if(!isUserRegistered(getUsername())) { console.log("Registering user"); linkBotUsername(); } } else if((document.title == "train - bots4") || (document.title == "fight - bots4")) { //get the battle length var battleLength = $("#remaining").html().replace("s",""); //get the current bot we are fighting. var opponentName = $('#battle-header').html(); //this name isn't stored as neatly as the bots in the fight list, we need to extract it from some HTML. var start = opponentName.indexOf("vs. ")+4; var end = opponentName.indexOf("</div>"); var attacker = opponentName.substring(opponentName.indexOf("\">")+2,start-5); opponentName = opponentName.substring(start,end); //look up existing data var fightStats = getStats(attacker, opponentName); if(fightStats === null) { //new bot, load up the defaults and information we have already collected fightStats = new Object(); fightStats.totalFights = 0; fightStats.avgBattleDur = 0; fightStats.winPerc = NaN; fightStats.timeToKEnergy = NaN; fightStats.avgExp = "-"; fightStats.avgKudos = "-"; fightStats.wins = 0; fightStats.losses = 0; fightStats.duration = 0; fightStats.totalExp = 0; fightStats.energyFights = 0; fightStats.totalEnergy = 0; fightStats.totalKudos = 0; fightStats.expMin = "-"; } //add some stats about this fight to the object fightStats.attacker = attacker; fightStats.defender = opponentName; fightStats.battleLength = battleLength; fightStats.speedBuff = 1; fightStats.expBuff = 1; fightStats.kudosBuff = 1; fightStats.energyBuff = 1; if (document.title == "fight - bots4") { fightStats.opponentLevel = window.location.pathname.match(/\/fight\/(\d+)\//)[1]; fightStats.opponentId = window.location.pathname.match(/\/fight\/\d+\/(\d+)\//)[1]; } else if(document.title == "train - bots4") { fightStats.opponentLevel = lookupTrainBot(parseInt(window.location.pathname.match(/\/train\/(\d+)\//)[1])); fightStats.opponentId = -1; } //get the buffs $(".buff").not(".buff-inactive").each(function(i) { //buff is active, we need to modify out battle output accordingly switch($(this).find("div[style='font-size: 1.5em;']").html()) { case "Spirit of Wolf I": fightStats.speedBuff = 1.5; break; case "Spirit of Wolf II": fightStats.speedBuff = 2; break; case "Spirit of Wolf III": fightStats.speedBuff = 2.5; break; case "Dark Energy I": fightStats.energyBuff = 1.5; break; case "Dark Energy II": fightStats.energyBuff = 2; break; case "Dark Energy III": fightStats.energyBuff = 2.5; break; case "Mindreave I": fightStats.expBuff = 0.75; break; case "Mindreave II": fightStats.expBuff = 0.5; break; case "Mindreave III": fightStats.expBuff = 0.25; break; case "Kodiac's Endless Intellect I": fightStats.expBuff = 1.5; break; case "Kodiac's Endless Intellect II": fightStats.expBuff = 2; break; case "Kodiac's Endless Intellect II": fightStats.expBuff = 2.5; break; case "Blitz's Bounty I": fightStats.kudosBuff = 1.5; break; case "Blitz's Bounty II": fightStats.kudosBuff = 2; break; case "Blitz's Bounty III": fightStats.kudosBuff = 2.5; break; case "Aura of Eternity": fightStats.kudosBuff = 2.5; break; case "Hastened Adventure": fightStats.speedBuff = 100; break; } }); //output the stats window var html = '<div id="botsstats" style="margin: 0 auto 0 auto; ' + 'border: 1px solid ' + BORDER_COLOUR + '; margin-top: 5px; margin-right: 5px; ' + 'font-size: small; background-color: ' + BACKGROUND_COLOUR + ';text-align:left;' + 'color: ' + TEXT_COLOUR + ';right: 0;top: 0;width: 200px;position:fixed;"><p style="margin: 2px 0 1px 0;"> ' + '<center><u>Fight Stats</u></center><br/>' + '<table border=0>' + '<tr><td>Challenger:</td><td>' + attacker + '</td></tr>' + '<tr><td>Defender:</td><td>' + opponentName + '</td></tr>' + '<tr><td>Total Fights:</td><td>' + numberWithCommas(fightStats.totalFights) + '</td></tr>' + '<tr><td>Avg Duration:</td><td>' + fightStats.avgBattleDur + 's</td></tr>' + '<tr><td>Win %:</td><td>' + fightStats.winPerc + '%</td></tr>'; if (!isNaN(fightStats.timeToKEnergy)) { html += '<tr><td>1K Energy Time:</td><td>' + fightStats.timeToKEnergy + 's</td></tr>'; } html += '<tr><td>Avg Exp:</td><td>' + numberWithCommas(fightStats.avgExp) + '</td></tr>'+ '<tr><td>Exp/min:</td><td>' + numberWithCommas(fightStats.expMin) +'</td></tr>' + '<tr><td>Avg Kudos:</td><td>' + numberWithCommas(fightStats.avgKudos) + '</td></tr>' + '</table><center><input type="button" id="reset" value="Reset" /></center></p></div>'; $("body").append(html); //add event listener to reset button $("#reset").bind( "click", function() { resetStats(opponentName, attacker); }); //get stats at the end of the battle findFinish(fightStats); } else if(document.title == "train list - bots4") { //show any stats we have alongside the training bots info if(!isUserRegistered(getUsername())) { //no bot name registered with that username, which is weird. } else { //find training bot names and look for matches with current logged in botname $(".box>a:first-child").each(function(i) { var trainInfo = getStats(getBotname(getUsername()), $(this).html()); if(trainInfo !== null) { //display found matches alongside training bot info $(this).parent().append("<table><tr><th>Fights</th><th>Win %</th><th>Avg Dur</th><th>Avg Exp</th><th>Exp/min</th><th>Avg Kudos</th></tr>"+ "<tr><td class='subtext'>"+numberWithCommas(trainInfo.totalFights)+"</td>" + "<td class='subtext'>"+trainInfo.winPerc+"%</td>" + "<td class='subtext'>"+trainInfo.avgBattleDur+"s</td>" + "<td class='subtext'>"+numberWithCommas(trainInfo.avgExp)+"</td>" + "<td class='subtext'>"+numberWithCommas(trainInfo.expMin)+"</td>" + "<td class='subtext'>"+numberWithCommas(trainInfo.avgKudos)+"</td></tr></table>"); } }); } } else if(document.title == "fight list - bots4") { //show any stats we have alongside the bots if(!isUserRegistered(getUsername())) { //no bot name registered with that username, which is weird. } else { //we good. //find botnames that match any in the list var botName = getBotname(getUsername()); //cycle through all of the bots listed on the page $(".botrow").each(function(i) { //check to see if we have info for the bot var rowBot = $(this).children().eq(2).html(); var fightStats = getStats(botName, rowBot); if(fightStats !== null) { //we have some stored details! var divName = rowBot.replace(/\ /g,"_"); var html = "<div style='position: relative'><img id='"+divName+"' src='/favicon.ico'/>"; html += "<div id='hidden_"+divName+"' style='position: absolute;display:none;width: 350px;' class='buff-details'><table><tr>"+ "<th class='sorttable_nosort'>Fights</th>"+ "<th class='sorttable_nosort'>Win %</th>"+ "<th class='sorttable_nosort'>Avg Dur</th>"; if (!isNaN(fightStats.timeToKEnergy)) { html += "<th class='sorttable_nosort'>1k Eng Time</th>"; } html += "<th class='sorttable_nosort'>Avg Exp</th>"+ "<th class='sorttable_nosort'>Exp/min</th>"+ "<th class='sorttable_nosort'>Avg Kudos</th></tr>" + "<tr><td>"+numberWithCommas(fightStats.totalFights)+"</td>" + "<td>"+fightStats.winPerc+"%</td>"+ "<td>"+fightStats.avgBattleDur+"s</td>"; if (!isNaN(fightStats.timeToKEnergy)) { html += "<td>"+fightStats.timeToKEnergy+"s</td>"; } html += "<td>"+numberWithCommas(fightStats.avgExp)+"</td>"+ "<td>"+numberWithCommas(fightStats.expMin)+"</td>" + "<td>"+numberWithCommas(fightStats.avgKudos)+"</td></tr>" + "</table></div></div>"; $(this).children().eq(11).append(html); //add mouse listeners $("#"+divName).mouseover(function(){ $("#hidden_"+this.id).css("display", "block"); }); $("#"+divName).mouseleave(function() { $("#hidden_"+this.id).css("display", "none"); }); } }); } } else if(window.location.href.indexOf("bots4.net/profile/") != -1) { //check if we have any stats var fightStats = []; var botname = $(".block-list:eq(1)>tbody>tr>td:eq(0)>span").html(); for(var j=0, len=localStorage.length; j<len; j++) { if(localStorage.key(j).match("BOTSSTATS_"+botname+"_") !== null) { fightStats.push(localStorage.key(j)); } } if(fightStats.length !== 0) { //we have some stats! var html = "<h2>Fight stats</h2><table><thead><tr>" + "<th>Challenger</th>" + "<th>Fights</th>"+ "<th>Win %</th>"+ "<th>Avg Dur</th>"+ "<th>1k Eng Time</th>"+ "<th>Avg Exp</th>"+ "<th>Exp/min</th>"+ "<th>Avg Kudos</th>"+ "<th>Last Battled</th></tr></thead><tbody>"; for(var j=0; j<fightStats.length;j++) { var challenger = fightStats[j].split("_")[2]; var stats = getStats(challenger ,botname); var lastBattle = new Date(parseInt(stats.lastBattled)); var ago = days_between(lastBattle, new Date()); var challengerDeets = getChallengerDetails(challenger); html +="<tr><td>"; if(challengerDeets === undefined) { html += challenger; } else { html += "<a href='/profile/"+challengerDeets.id+"' style='color: "+challengerDeets.colour+";'>"+challenger+"</a>"; } html += "</td>" + "<td>"+numberWithCommas(stats.totalFights)+"</td>" + "<td class='ratio_"+stats.winPercColour+"'>"+stats.winPerc+"%</td>"+ "<td>"+stats.avgBattleDur+"s</td>"+ "<td>"+stats.timeToKEnergy+"s</td>"+ "<td>"+numberWithCommas(stats.avgExp)+"</td>"+ "<td>"+numberWithCommas(stats.expMin)+"</td>"+ "<td style='color:"; console.log(fightStats.avgKudos); if(parseInt(stats.avgKudos)<0) { html += "red"; } else { html += "#0f0"; } html += "'>"+numberWithCommas(stats.avgKudos)+"</td>" + "<td >"+lastBattle.toLocaleDateString("en-GB")+"<br><span class='subtext'>[<span class='subsubtext'>"; if(ago === 0) { html += "today</span>"; } else { html += ago+" day"; if(ago != 1) { html += "s"; } html += "</span> ago"; } html += "]</span></td></tr>"; } html += "</tbody></table>"; $("h2:contains('Energy history')").before(html); } } else if(window.location.pathname == "/botsstats") { document.title = "bots stats - bots4"; $("#page-title").html("bots stats"); var html = "<h2>Bot List</h2><table id='bot_list' class='sortable'><thead><tr>"+ "<th class='sorttable_nosort'>botname</th>"+ "<th>level</th>"+ "<th>challenger</th>"+ "<th>total fights</th>"+ "<th>win %</th>"+ "<th>avg duration</th>"+ "<th>1k energy time</th>"+ "<th>avg exp</th>"+ "<th>exp/min</th>"+ "<th>avg kudos</th>"+ "<th>last battled</th>"+ "<th class='sorttable_nosort'></th>"+ "</tr></thead><tbody>"; for(var j=0;j<localStorage.length;j++) { if(localStorage.key(j).match(/BOTSSTATS_/g) !== null) { //we have a bot! do some calcs and output it var keyDeets = localStorage.key(j).split("_"); var fightStats = getStats(keyDeets[2], keyDeets[1]); var challengerDeets = getChallengerDetails(fightStats.challenger); var lastBattle = new Date(parseInt(fightStats.lastBattled)); var ago = days_between(lastBattle, new Date()); html += "<tr class='botrow'><td>"; if(parseInt(fightStats.opponentId) == -1) { //we have a training bot html += "<a href='/train' style='color: "+fightStats.opponentColour+";'>"; } else { //regular bot html += "<a href='/profile/"+fightStats.opponentId+"' style='color: "+fightStats.opponentColour+";'>"; } html += fightStats.defender+"</a></td>"+ "<td class='subtext' sorttable_customkey='"+fightStats.opponentLevel+"'>[<span class='subsubtext'>"+fightStats.opponentLevel+"</span>]</td>"+ "<td><a href='/profile/"+challengerDeets.id+"' style='color:"+challengerDeets.colour+"' sorttable_customkey='"+challengerDeets.name.toLowerCase()+"'>"+challengerDeets.name+"</a></td>"+ "<td>"+numberWithCommas(fightStats.totalFights)+"</td>" + "<td sorttable_customkey='"+fightStats.winPerc+"'><span class='ratio_"+fightStats.winPercColour+"'>"+fightStats.winPerc+"%</span></td>" + "<td>"+fightStats.avgBattleDur+"</td>" + "<td>"+fightStats.timeToKEnergy+"</td>" + "<td>"+numberWithCommas(fightStats.avgExp)+"</td>" + "<td>"+numberWithCommas(fightStats.expMin)+"</td>" + "<td style='color: "; if(fightStats.avgKudos<0) { html += "red"; } else { html += "#0f0"; } html += ";'>"+numberWithCommas(fightStats.avgKudos)+"</td>" + "<td sorttable_customkey='"+fightStats.lastBattled+"'>"+lastBattle.toLocaleDateString("en-GB")+"<br><span class='subtext'>[<span class='subsubtext'>"; if(ago === 0) { html += "today</span>"; } else { html += ago+" day"; if(ago != 1) { html += "s"; } html += "</span> ago"; } html += "]</span></td>" + "<td><input class='delete_button' type='button' value='Delete'/></td></tr>"; } } html += "</table>"; html += "<style>table.sortable th:not(.sorttable_sorted):not(.sorttable_sorted_reverse):not(.sorttable_nosort):after {content: ' \\25B4\\25BE' }</style>"; //add import and export buttons html += "<h2>Export</h2><input type='button' value='Export' id='export'/>"+ "<h2>Import</h2><textarea rows=1 cols=20 id='import_file'></textarea><br/><input type='button' value='Import' id='import'/><span id='import_span'></span>"+ "<h2>Clear</h2><input type='button' value='Clear' id='clear' /><span id='clear_span'></span>"; $("#content").append(html); //enable buttons $(".delete_button").each(function(i) { $(this).bind( "click", function() { removeRow($(this).parents("tr")); }); }); $("#export").bind( "click", function() { exportBotsStats(); }); $("#import").bind( "click", function() { importWarning(); }); $("#clear").bind( "click", function() { clearWarning(); }); } })(); function resetStats(opponentName, attacker) { localStorage.removeItem("BOTSSTATS_"+opponentName+"_"+attacker); $("#botsstats").html("<center>Stats Reset</center>"); } function getStats(attacker, defender) { //loads the supplied bot string into an object, returns null if it doesn't exist var rawStats = localStorage.getItem("BOTSSTATS_"+defender+"_"+attacker); if(rawStats === null) { return rawStats } else { rawStats = rawStats.split("_"); var calcStats = new Object(); calcStats.wins = parseInt(rawStats[WINS]); calcStats.losses = parseInt(rawStats[LOSSES]); calcStats.duration = parseFloat(rawStats[TOTAL_DURATION]); calcStats.totalExp = parseInt(rawStats[TOTAL_EXP]); calcStats.energyFights = parseInt(rawStats[ENERGY_FIGHTS]); calcStats.totalEnergy = parseInt(rawStats[TOTAL_ENERGY]); calcStats.totalKudos = parseInt(rawStats[TOTAL_KUDOS]); calcStats.opponentLevel = parseInt(rawStats[OPPONENT_LEVEL]); calcStats.opponentColour = rawStats[OPPONENT_COLOUR]; calcStats.lastBattled = rawStats[LAST_BATTLED]; calcStats.opponentId = rawStats[OPPONENT_ID]; calcStats.totalFights = calcStats.wins+calcStats.losses; calcStats.avgBattleDur = (calcStats.duration/parseFloat(calcStats.totalFights)).toFixed(2); if(calcStats.losses == 0) { calcStats.winPerc = 100.00; } else if((calcStats.losses == 0) && (calcStats.wins == 0)) { calcStats.winPerc = "NaN"; } else { calcStats.winPerc = ((parseFloat(calcStats.wins)/parseFloat(calcStats.totalFights))*100).toFixed(2); } calcStats.winPercColour = Math.round(calcStats.winPerc/6.666); if(calcStats.winPercColour === 0) { calcStats.winPercColour = 1; } calcStats.timeToKEnergy = Math.round((1000/(parseFloat(calcStats.totalEnergy)/parseFloat(calcStats.energyFights)))*calcStats.avgBattleDur); calcStats.avgExp = Math.round(parseFloat(calcStats.totalExp)/parseFloat(calcStats.totalFights)); calcStats.expMin = Math.round((60.0/calcStats.avgBattleDur)*calcStats.avgExp); calcStats.avgKudos = Math.round(calcStats.totalKudos/(calcStats.totalFights)); calcStats.defender = defender; calcStats.challenger = attacker; return calcStats; } } function getUsername() { return $(".box>div>a[href^='/profile']").html(); } function getBotname(username) { //returns undefined if the bot hasn't been linked var botName = localStorage.getItem("BOTSSTATSLINK_"+username); if(botName === null) { return undefined; } else { return botName.split("_")[0]; } } function getChallengerDetails(username) { var challengerDeets = localStorage["BOTSSTATSLINK_"+username]; if(challengerDeets !== undefined) { var deets = new Object(); deets.colour = challengerDeets.split("_")[2]; deets.id = challengerDeets.split("_")[1]; deets.name = username; return deets; } else { return undefined; } } function isUserRegistered(username) { if(getBotname(username) === undefined) { return false; } else { return true; } } function removeRow(row) { var botname = $(row).find("td:eq(0)>a").html(); var attacker = $(row).find("td:eq(2)>a").html(); localStorage.removeItem("BOTSSTATS_"+botname+"_"+attacker); $(row).remove(); } function linkBotUsername() { $.ajax($(".box>div>a[href^='/profile']").attr("href"), { success: function(data) { var user = getUsername(); var bot = data.match(/\<th\>\s*\<div\>Botname:\<\/div\>\s*\<\/th\>\s*\<td\>\<span style=\"color: #\w+;\"\>([^<]+)<\/span\>\<\/td\>/)[1]; var id = data.match(/\<th\>\s*\<div\>Id:\<\/div\>\s*\<\/th\>\s*\<td\>(\d+)\<\/td\>/)[1]; var colour = $(".box>div>a[href^='/profile']").css("color"); localStorage['BOTSSTATSLINK_'+user] = bot+"_"+id+"_"+colour; localStorage['BOTSSTATSLINK_'+bot] = user+"_"+id+"_"+colour; console.log("Bot/user linked!"); }, error: function(error) { console.log(error); } }); } function exportBotsStats() { var toExport = ""; for(var j=0, len=localStorage.length; j<len; j++) { if(localStorage.key(j).match(/BOTSSTATS/g) !== null) { toExport += localStorage.key(j)+"\""+localStorage[localStorage.key(j)]+"\n"; } } var today = new Date(); download(toExport, "bots_stats_export_"+today.getFullYear()+"_"+(today.getMonth()+1)+"_"+today.getDate()+".txt", "text/plain;charset=utf-8"); } function importWarning() { //check import data var toImport = $("#import_file").val().split('\n'); if(toImport!="") { $("#import_file").prop("disabled", true); var itsOK = 0; for(var i=0;i<toImport.length;i++) { var line = toImport[i] var check1 = line.match(/BOTSSTATS_[^_]+_[^"]+\"(?:-?[\d|.]+_){8}rgb\(\d+,\s*\d+,\s*\d+\)(?:_-?\d+){2}/); var check2 = line.match(/BOTSSTATSLINK_[^"]+\"[^_]+_\d+_rgb\(\d+,\s*\d+,\s*\d+\)/); if((check1 === null) && (check2 === null) && (line !== "")) { //check failed itsOK = i+1; i=toImport.length+100; } } if(itsOK===0) { $("#import_span").html(" <span style='color: red'>WARNING:</span> This will overwrite existing data. Click Import to continue"); $("#import").bind( "click", function() { importBotsStats(); }); } else { $("#import_span").html("Invalid import data. Issue on line: "+itsOK); $("#import_file").prop("disabled", false); } } else { $("#import_span").html("No data found"); } } function importBotsStats() { var toImport = $("#import_file").val().split('\n'); for(var i=0;i<toImport.length;i++) { var line = toImport[i]; //ignores blank lines if(line !== "") { line = line.split("\""); localStorage.setItem(line[0],line[1]); } } $("#import_span").html("Import successful! <input type='button' value='Reload' onClick='window.location.reload()' />"); $("#import").hide(); } function clearWarning() { $("#clear_span").html(" <span style='color: red'>WARNING: THIS WILL CLEAR ALL DATA!</span> Make sure you have a backup handy, just in case. Click Clear again to proceed."); $("#clear").bind( "click", function() { clearStats(); }); } function clearStats() { var listToDelete = []; for(var j=0; j<localStorage.length; j++) { if(localStorage.key(j).match(/BOTSSTATS/g) !== null) { listToDelete.push(localStorage.key(j)); } } for(var i=0;i<listToDelete.length;i++){ localStorage.removeItem(listToDelete[i]); } $("#clear_span").html("Cleared. <input type='button' value='Reload' onClick='window.location.reload()' />"); $("#clear").hide(); } function findFinish(fightStats) { if($("#battle-summary").length !== 0) { //the fight is over //pull the energy obtained from the battle log. var battleLog = $("#battle-log").html(); var kudos = ""; var energy = battleLog.match(/is exhausted and (?:loses|gives you) \<span class\=\"subsubtext\">(\d+)\<\/span\> energy./m); if(energy === null) { energy = 0; } else { energy = energy[1]; fightStats.energyFights++; } kudos = battleLog.match(/The B.O.T.S. Union takes \<span class\=\"subsubtext\">([\d|,]+)\<\/span\> kudos/m); if(kudos === null) { kudos = battleLog.match(/The B.O.T.S. Union hands you \<span class\=\"subsubtext\">([\d|,]+)\<\/span\> kudos/m)[1]; } else { kudos = kudos[1]; } var exp = battleLog.match(/Your bot gains \<span class\=\"subsubtext\">([\d|,]+)\<\/span\> experience points/m)[1]; //we now know how much energy we have. Now figure out who won. var winner = $("#battle-summary>tbody>tr>td:last>span").html(); var way = ""; if((winner == fightStats.defender) && (document.title != "train - bots4") && (document.title != "(!) train - bots4")) { //challenger lost way = "-"; } var addToWins = 0; var addToLoss = 0; if(winner == fightStats.defender) { addToLoss = 1; } else { addToWins = 1; } //get the colour of the opponent var opponentDisplay = $("#battle-summary>tbody>tr>td:eq(5)>span").css("color"); //current time, to serve as last battled time var lastBattled = (new Date).getTime(); //store var botInfo = [parseInt(fightStats.wins)+addToWins, fightStats.losses+addToLoss, (fightStats.duration+parseFloat(fightStats.battleLength)*fightStats.speedBuff).toFixed(2), parseFloat(fightStats.totalExp)+parseFloat(exp.replace(/\,/g,""))/fightStats.expBuff, fightStats.energyFights, fightStats.totalEnergy+parseInt(way+energy)/fightStats.energyBuff, fightStats.totalKudos+parseInt(way+kudos.replace(/\,/g,""))/fightStats.kudosBuff, fightStats.opponentLevel, opponentDisplay, lastBattled, fightStats.opponentId]; localStorage["BOTSSTATS_"+fightStats.defender+"_"+fightStats.attacker] = botInfo.join("_"); } else { //fight has not ended yet, wait another 0.1 second for the fight to end. setTimeout(function(){findFinish(fightStats);}, 100); } } function lookupTrainBot(number) { switch(number) { case 1: return 1; case 2: return 1; case 3: return 7; case 4: return 10; case 5: return 20; case 6: return 30; case 7: return 45; case 8: return 60; case 9: return 75; case 10: return 90; case 11: return 105; case 12: return 115; case 13: return 125; case 14: return 140; case 15: return 160; case 16: return 180; case 17: return 200; case 18: return 220; case 19: return 240; case 20: return 260; case 21: return 280; case 22: return 300; case 23: return 325; case 24: return 350; case 25: return 375; case 26: return 400; case 27: return 450; case 28: return 500; case 29: return 550; case 30: return 600; case 31: return 750; case 32: return 1000; case 33: return 1200; case 34: return 1500; case 35: return 1800; case 36: return 2100; default: return undefined; } } function days_between(date1, date2) { var ONE_DAY = 1000 * 60 * 60 * 24; var date1_ms = date1.getTime(); var date2_ms = date2.getTime(); var difference_ms = Math.abs(date1_ms - date2_ms); return Math.round(difference_ms/ONE_DAY); } //number format function. Only used to format the energy display. Credit for this function goes to mikez302 from StackOverflow. function numberWithCommas(x) { return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } // Function to download data to a file //from: https://stackoverflow.com/questions/13405129/javascript-create-and-save-file function download(data, filename, type) { var file = new Blob([data], {type: type}); if (window.navigator.msSaveOrOpenBlob) { // IE10+ window.navigator.msSaveOrOpenBlob(file, filename); } else { // Others var a = document.createElement("a"), url = URL.createObjectURL(file); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); setTimeout(function() { document.body.removeChild(a); window.URL.revokeObjectURL(url); }, 0); } }