There are 15 previous versions of this script.
// AstroEmipres Battle Calc - battle calculator script for astroempires.com
//
// Copyright (C) 2008 dave@mindkeep.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ==UserScript==
// @name AstroEmpiresBattleCalc
// @namespace mindkeep.org
// @description AstroEmpiresBattleCalc
// @include http://*.astroempires.com/combat.aspx*
// ==/UserScript==
var NAME_INDEX = 0;
var START_QUANT_INDEX = 1;
var END_QUANT_INDEX = 2;
var POWER_INDEX = 3;
var ARMOR_INDEX = 4;
var SHIELD_INDEX = 5;
var DEBUG_OFF = 0;
var DEBUG_TIMING = 1;
var DEBUG_VERBOSE = 2;
var bc_debug_level = DEBUG_TIMING;
function debugBC(output)
{
if (bc_debug_level > DEBUG_OFF)
{
console.log(output);
}
}
function debugBC_V(output)
{
if (bc_debug_level >= DEBUG_VERBOSE)
{
console.log(output);
}
}
function initEndQuants(rows)
{
for (var i = 0; i < rows.snapshotLength; i++)
{
var row = rows.snapshotItem(i);
// end quant = start quant
row.childNodes[END_QUANT_INDEX].firstChild.firstChild.nodeValue =
row.childNodes[START_QUANT_INDEX].firstChild.firstChild.nodeValue;
}
debugBC_V("initEndQuants("+rows+") complete.");
}
function calcDamagePerUnit(power, shield, over)
{
var damagePerUnit = 0;
if (power > shield)
{
damagePerUnit = (power - shield) + (shield * over);
}
else
{
damagePerUnit = (power * over);
}
debugBC_V("calcDamagePerUnit("+power+", "+shield+", "+over+") returned "+damagePerUnit+", complete.");
return damagePerUnit;
}
function attackOneWay(aRows, dRows)
{
for (var i = 0; i < aRows.snapshotLength; i++)
{
var aRow = aRows.snapshotItem(i);
var aUnits = aRow.childNodes[START_QUANT_INDEX].firstChild.firstChild.nodeValue - 0;
var aPower = aRow.childNodes[POWER_INDEX].firstChild.nodeValue - 0;
var aName = aRow.childNodes[NAME_INDEX].firstChild.nodeValue;
//find power over shields
var aOverShields = 0.01;
if (aName == "Ion Bombers" || aName == "Ion Frigates")
{
aOverShields = 0.50;
}
// is this a turret structure?
// this means use not so intelligent damage distribution, interesting...
var aIsTurret = false;
if (aName == "Barracks" ||
aName == "Laser Turrets" ||
aName == "Missle Turrets" ||
aName == "Plasma Turrets" ||
aName == "Ion Turrets" ||
aName == "Photon Turrets" ||
aName == "Disruptor Turrets" ||
aName == "Deflection Shields" ||
aName == "Planetary Shield" ||
aName == "Planetary Ring")
{
aIsTurret = true;
}
debugBC_V("aRow = aRows.snapshotItem("+i+")\n"+
"\taName = "+aName+"\n"+
"\taUnits = "+aUnits+"\n"+
"\taPower = "+aPower+"\n"+
"\taOverShields = "+aOverShields+"\n"+
"\taIsTurret = "+aIsTurret);
while (aUnits > 0.0001) // prevent spinning
{
//find total defense size
var dFleetTypeCount = 0;
var totalDamagePerUnit = 0;
for (var j = 0; j < dRows.snapshotLength; j++)
{
var dRow = dRows.snapshotItem(j);
var dUnits = dRow.childNodes[END_QUANT_INDEX].firstChild.firstChild.nodeValue - 0;
var dShield = dRow.childNodes[SHIELD_INDEX].firstChild.nodeValue - 0;
if (dUnits > 0)
{
totalDamagePerUnit = totalDamagePerUnit +
calcDamagePerUnit(aPower, dShield, aOverShields);
dFleetTypeCount++;
}
}
debugBC_V("dFleetTypeCount = "+dFleetTypeCount);
if (dFleetTypeCount <= 0)
{
debugBC_V("All Fleet Destroyed!");
break;
}
debugBC_V("totalDamagePerUnit = "+totalDamagePerUnit);
var aUnitsUsed = 0;
for (var j = 0; j < dRows.snapshotLength; j++)
{
var dRow = dRows.snapshotItem(j);
var dName = dRow.childNodes[NAME_INDEX].firstChild.nodeValue;
var dUnits = dRow.childNodes[END_QUANT_INDEX].firstChild.firstChild.nodeValue - 0;
if (dUnits == 0)
{
debugBC_V(dName+" group is destroyed, skipping.");
continue;
}
var dArmor = dRow.childNodes[ARMOR_INDEX].firstChild.nodeValue - 0;
var dHp = dUnits * dArmor;
var dShield = dRow.childNodes[SHIELD_INDEX].firstChild.nodeValue - 0;
debugBC_V("dRow = dRows.snapshotItem("+j+")\n"+
"\tdName = "+dName+"\n"+
"\tdUnits = "+dUnits+"\n"+
"\tdArmor = "+dArmor+"\n"+
"\tdHp = "+dHp+"\n"+
"\tdShield = "+dShield);
var damagePerUnit = calcDamagePerUnit(aPower, dShield, aOverShields);
//attackers for this defender group
var attackingUnits = aUnits * damagePerUnit / totalDamagePerUnit;
if (aIsTurret)
{
attackingUnits = aUnits / dFleetTypeCount;
}
var damage = attackingUnits * damagePerUnit; //max damage
debugBC_V(aName+" attackingUnits("+attackingUnits+") * damagePerUnit("+damagePerUnit+") = damage("+damage+")");
if (damage >= dHp)
{
dRow.childNodes[END_QUANT_INDEX].firstChild.firstChild.nodeValue = 0;
aUnitsUsed = aUnitsUsed + dHp / damagePerUnit;
debugBC_V(dName+" units destroyed!\n"+
"\tdHp / damagePerUnit = "+(dHp/damagePerUnit)+"\n"+
"\taUnitsUsed = "+aUnitsUsed);
}
else
{
dRow.childNodes[END_QUANT_INDEX].firstChild.firstChild.nodeValue =
(dHp - damage) / dArmor;
aUnitsUsed = aUnitsUsed + attackingUnits;
debugBC_V(dName+" units remaining = "+((dHp-damage)/dArmor)+"\n"+
"\taUnitsUsed = "+aUnitsUsed);
}
}
aUnits = aUnits - aUnitsUsed;
debugBC_V("aUnits remaining = "+aUnits);
}
}
debugBC_V("attackOneWay("+aRows+", "+dRows+") complete.");
}
function findScale(name)
{
var scale;
if (name == "Fighters" ||
name == "Bombers" ||
name == "Heavy Bombers" ||
name == "Ion Bombers" ||
name == "Corvette" ||
name == "Recycler" ||
name == "Destroyer" ||
name == "Frigate" ||
name == "Ion Frigate" ||
name == "Scout Ship" ||
name == "Outpost Ship")
{
scale = 0;
}
else if (name == "Cruiser" ||
name == "Carrier" ||
name == "Heavy Cruiser")
{
scale = 1;
}
else
{
scale = 2;
}
debugBC_V("findScale("+name+") returned "+scale+", complete.");
return scale;
}
function roundUp(value, scale)
{
var mult = Math.pow(10,scale);
var rounded = Math.ceil(value*mult) / mult;
debugBC_V("roundUp("+value+", "+scale+") returned "+rounded+", complete.");
return rounded;
}
function roundEndQuants(rows)
{
for (var i = 0; i < rows.snapshotLength; i++)
{
var row = rows.snapshotItem(i);
var scale = findScale(row.childNodes[NAME_INDEX].firstChild.nodeValue);
var roundedValue = roundUp(row.childNodes[END_QUANT_INDEX].firstChild.firstChild.nodeValue, scale);
row.childNodes[END_QUANT_INDEX].firstChild.firstChild.nodeValue = roundedValue;
if (row.childNodes[END_QUANT_INDEX].firstChild.firstChild.nodeValue !=
row.childNodes[START_QUANT_INDEX].firstChild.firstChild.nodeValue)
{
row.childNodes[END_QUANT_INDEX].style.color = "magenta";
}
else
{
row.childNodes[END_QUANT_INDEX].style.color = "lime";
}
}
debugBC_V("roundEndQuants("+rows+") complete.");
}
function runBattleCalc()
{
var startTime = new Date();
var attackerRows = document.evaluate(
"//table//th[contains(text(),'Attack Force') and @colspan='6']/../..//tr[@align='center']",
document,
null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null);
var defenderRows = document.evaluate(
"//table//th[contains(text(),'Defensive Force') and @colspan='6']/../..//tr[@align='center']",
document,
null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null);
initEndQuants(attackerRows);
initEndQuants(defenderRows);
attackOneWay(attackerRows, defenderRows);
attackOneWay(defenderRows, attackerRows);
roundEndQuants(attackerRows);
roundEndQuants(defenderRows);
var endTime = new Date();
var runSeconds = endTime.getTime() - startTime.getTime();
debugBC("AE Battle Calc Completed Successfully!\n" +
"\tCalc Duration: " + runSeconds / 1000 + " seconds\n" +
"\tEnd Time: " + endTime.toString());
debugBC_V("runBattleCalc() complete.");
}
function isConfirmPage()
{
var temp = false;
var confirmTitle = document.evaluate(
"//center//b[contains(text(),'Confirm Attack')]",
document,
null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null);
if (confirmTitle.snapshotLength >= 1)
{
temp = true;
}
debugBC_V("isConfirmPage() returned "+temp+", complete.");
return temp;
}
//main
if (isConfirmPage())
{
runBattleCalc();
}