By Mad Frog
Has no other scripts.
// ==UserScript==
// @name evo+
// @version 2.4.0
// @namespace http://wildservices.net/userscripts
// @description Enchances evo game :-)
// @include http://ev5.neondragon.net/*
// @include http://evo-dev.neondragon.net/*
// @author ~ravenlord~ (r4v3n10rd@gmail.com) - original 1.0x source
// @author HETMAN (kanarinios@gmail.com) - upgrades
// @author mindfox & Fire - upgrades
// @author MadFrog (mbfrog@gmail.com)
// @author Roland
// @author WhyteWolf (whytewolf1@gmail.com)
// @author Gavry
// @author Ressol
// ==/UserScript==
/*
* $Id: evoplus.user.js,v 1.19 2006/07/01 20:55:50 madfrog Exp $
*
* $Log: evoplus.user.js,v $
* Revision 1.19 2006/07/01 20:55:50 madfrog
* Added a quick "add to buddies" link to the alliance members pages
*
* Revision 1.18 2006/06/29 18:26:41 madfrog
* Updated dEvo stats
* The allocated % on the Sector Scan was not taking the food into account
* Optimized parsing on the Sector Scan
*
* Revision 1.17 2006/06/22 23:57:46 madfrog
* Saving the Efficient Breeding Center coefficient as float was breaking GM
* Removed an unused configuration item (for the scan page)
*
* Revision 1.16 2006/06/22 23:14:53 madfrog
* Implemented changes from Ressol:
* Sector Scan: Max/min attacker score in scan result.
* Sector Scan: Allocated land ratio and estimated land defense.
* Sector Scan: Number formatting / fields colorful.
* Creature Scan: Estimated creatures launch cost.
* Battle Report: Add land loss ratio in defense side.
* Alliances Page: Add average member score
*
* Revision 1.15 2006/06/22 19:59:32 madfrog
* Enabled the use of plugin scripts
* Efficient Breeding Center setting is now saved in a GM_Variable (useful?)
* Fixed a typo (Archological path)
* Moved all utility functions at the bottom
*
* Revision 1.14 2006/06/21 22:39:17 madfrog
* Fixed a problem with Efficient Breeding Center on the create page
*
* Revision 1.13 2006/03/17 17:12:38 madfrog
* Fixed a problem with the land ratio calculator that caused an infinite loop
*
* Revision 1.12 2006/03/09 22:00:36 madfrog
* removed a [NOD] tag from the script name :P
*
* Revision 1.11 2006/03/09 11:47:02 madfrog
* added automatic handling ot the evo-dev.neondragon.net URL
* forgot to credit Hemna for the evo-dev critter stats
*
* Revision 1.10 2006/03/09 01:55:06 madfrog
* added support for evo-dev (5 mns ticks and creature stats - thanks to [BT]Hemna)
* added support for the Efficient Breeding center on on the create page
* fixed problems on the news page (NaNs on the BRs. /0 is innocent ;))
* added average land per alliance member on the alliance ranking page (Gavry)
*
* Revision 1.9 2006/02/19 17:13:30 madfrog
* Corrected a bug in the cost evaluation of losses (it broke with defenses like forts)
* Removed a couple of NaNs caused by a div by zero (pun intended)
*
* Revision 1.8 2006/02/17 18:56:39 madfrog
* Simplified land ratio on the resources page
* Disabled land grab stats if defending
* Added cost evaluation of losses on battle reports
* Version bump
*
* Revision 1.7 2006/02/09 18:35:52 madfrog
* Adapted to the new user interface
*
* Revision 1.6 2006/02/02 13:19:33 whytewolf
* minor cost fix for OP and MP costs
* also spelling correction
*
* Revision 1.5 2006/02/01 19:56:01 madfrog
*
* Implemented Maximum possible boosts (for scans, affected by previous change) separated from the players's boosts (for create and fleets).
* Hooked the boost configuration to a menu command.
* A bit of code cleanup in the land ratio display.
* Better tooltip information in the scans att2/def2 evaluations.
*
* Revision 1.4 2006/01/31 22:56:12 whytewolf
*
* typo correction and version bump
* and version change to include magor.minor.bug
*
* Revision 1.3 2006/01/31 22:42:36 whytewolf
*
* added land ratio function
* and MaxBoost Configureation
*
* Revision 1.2 2006/01/30 16:19:18 madfrog
* Added land grab stats on the news page (from Roland's)
*
* Revision 1.1 2006/01/30 13:21:09 madfrog
* First 2.0 version. Almost complete rewrite of the 1.x series with some addtional features.
*
*/
// ***************************************************************************
// ** Global Variables
// ***************************************************************************
const scriptversion = '2.4.0';
const scriptversionID = 'evo+ ' + scriptversion;
const scriptTag = 'Armageddon';
GM_log(scriptversionID + " start");
// xscript data sharing
unsafeWindow.evo_plus = new Array();
// page handlers
var pageHandlers = new Array();
var units = new Object(); // units :P
var contents = null; // pointer to the 'content' node in the page
// boosts
const UT_NONE = 0;
const UT_NATURAL = 1;
const UT_ENG = 2;
// max possible boosts
var maxBoosts = new Array();
maxBoosts[UT_NONE] = 0;
maxBoosts[UT_NATURAL] = 0.3946625; //max boost for natural
maxBoosts[UT_ENG] = 0.33126875; //max boost for eng
unsafeWindow.evo_plus['maxBoosts'] = maxBoosts;
// user current boosts
var boosts = new Array();
boosts[UT_NONE] = 0;
boosts[UT_NATURAL] = Number(GM_getValue('boostNat', maxBoosts[UT_NATURAL]));
boosts[UT_ENG] = Number(GM_getValue('boostEng', maxBoosts[UT_ENG]));
unsafeWindow.evo_plus['boosts'] = boosts;
var pMetal = 0, pMineral = 0, pFood = 0; //player's resources
var pRank = null, pScore = null; // player's ranking and score
var eeb = Number(GM_getValue('eeb', 1)); // efficient breeding center ratio
var dEvo = /^http:\/\/evo-dev\./.test(document.location.href);
//
// ***************************************************************************
// ** Page handlers
// ***************************************************************************
//
// Add stuff to the scans and create pages
//
regPageHandler(/^\/create/i, function () { evoCreate(1); evoCreate(2); evoCreate(3); });
regPageHandler(/^\/scans/i, function () { evoCreate(1); });
// handle each creation table
function evoCreate(tableID) {
//
// event handlers
//
// refreshes the max numbers when click on "max" or form field change
function evoUpdateAvailableUnits(table) {
var tmpMetal = pMetal;
var tmpMineral = pMineral;
var rows = table.rows;
var row, unit, unitsToOrder, maxUnitsAvailable, span;
// keep data between the two passes
var createDataArray = new Array();
function createData(unit, unitsToOrder, isTooMuch) {
this.unit = unit;
this.unitsToOrder = unitsToOrder;
this.isTooMuch = isTooMuch;
}
// first pass
// - gather all necessary data for second pass
// - adjust metal/mineral amount
for(var i = 2; i < (rows.length - 1); i++) {
row = rows[i];
unit = row.cells[1].getElementsByTagName('SPAN')[0].textContent.toLowerCase();
unit = units[unit];
unitsToOrder = Number(row.cells[3].getElementsByTagName('INPUT')[0].value);
if( isNaN(unitsToOrder) ) unitsToOrder = 0;
createDataArray[i] = new createData(unit, unitsToOrder, unitsToOrder > unit.getMaxUnits(tmpMetal, tmpMineral));
if(! createDataArray[i].isTooMuch ) {
tmpMetal = Math.max(tmpMetal - unitsToOrder * unit.getMetal(), 0);
tmpMineral = Math.max(tmpMineral - unitsToOrder * unit.getMineral(), 0);
}
}
// second pass
// - ui logic
for(var i = 2; i < (rows.length - 1); i++) {
row = rows[i];
maxUnitsAvailable = createDataArray[i].unit.getMaxUnits(tmpMetal, tmpMineral);
span = row.cells[3].getElementsByTagName('SPAN')[0];
// have to replace the data of the child text node
// span.textContent = html would recreate the child text node and cancel the onclick event
span.firstChild.data = 'max: ' + String(createDataArray[i].isTooMuch ? maxUnitsAvailable : (maxUnitsAvailable + createDataArray[i].unitsToOrder));
span.style.color = createDataArray[i].isTooMuch ? 'red' : '#CCCCCC';
}
}
var onBlur = function() { evoUpdateAvailableUnits(table); };
var onClick = function(e) {
if( e.target.tagName.toLowerCase() == 'input' ) return;
this.getElementsByTagName('input')[0].value = /max: (\d+)/m.exec(this.textContent)[1];
evoUpdateAvailableUnits(table);
};
//
// Helper functions
//
function addHeader(cellIndex, label) {
var cell = table.rows[0].insertCell(cellIndex);
cell.innerHTML = label;
cell.align = "center"; cell.vAlign = "bottom"; cell.width = "60px";
cell = table.rows[1].insertCell(cellIndex); cell.className = "alt1";
}
function addStat(row, cellIndex, base, square, value, boost) {
var cell = row.insertCell(cellIndex);
cell.className = row.cells[1].className; cell.align = "center";
cell.innerHTML = '<span title="Unboosted: ' + base + '">' + (base*boost).toFixed(1)
+ '</span><br /><span class="t_enormous" title="Unboosted: ' + square + '">' + (square*boost*boost).toFixed(0)
+ '</span><br /><span title="Unboosted: ' + evoNumber2String(value) + '">' + evoNumber2String((value*boost*boost).toFixed(0)) + '</span>';
}
//
// main
//
var unit, cell, unitCost, row;
var table = null;
var isScanPage = document.location.pathname == '/scans';
var xPathTerm = ".//div[@class='"+(dEvo?"separator title":"title")+"'";
if( isScanPage)
xPathTerm = xPathTerm+ "][3]/following-sibling::table[1]";
else
xPathTerm = xPathTerm + "]["+tableID+"]/following-sibling::table[1]";
table = document.evaluate(xPathTerm, contents, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
if(table == null) return;
var showstats = !isScanPage && (tableID == 1 || tableID == 2);
// Efficient breeding center?
if( showstats && tableID == 1 ) {
var monkey = document.evaluate(".//tbody/tr/td[2][./a/span[@class='b' and text()='Monkey']]/text()",
table, null, XPathResult.STRING_TYPE, null).stringValue;
if( monkey ) {
var match = /(\d+) metal, (\d+) mineral each\./.exec(monkey);
if( match ) {
eeb = parseInt(match[1]) / units['monkey'].metal;
GM_setValue('eeb', String(eeb));
}
}
}
// add creatures/items stats
if( showstats ) {
// column headers
addHeader(4, 'Attack/<br /><strong>Attack<sup>2</sup></strong>/<br /><span title="Att2 per 100,000 resources (metal + mineral)">per 100K</span>');
addHeader(5, 'Defense/<br /><strong>Defense<sup>2</sup></strong>/<br /><span title="Def2 per 100,000 resources (metal + mineral)">per 100K</span>');
addHeader(6, 'Total/<br /><strong>Total<sup>2</sup></strong>/<br /><span title="Att2+Def2 per 100,000 resources (metal + mineral)">per 100K</span>');
}
// display stats for each item
for( var i = 2; i < (table.rows.length - 1); i++ ) {
row = table.rows[i];
if( showstats ) {
unit = (row.cells[1].getElementsByTagName('SPAN'))[0].textContent.toLowerCase();
unit = units[unit];
unitCost = unit.getMetal() + unit.getMineral();
var att2 = unit.getAttackScore(1);
var def2 = unit.getDefenseScore(1);
var average = att2 + def2;
var boost = 1 + unit.getBoost();
addStat(row, 4, unit.attack, att2, Math.round(att2*100000/unitCost), boost);
addStat(row, 5, unit.defense, def2, Math.round(def2*100000/unitCost), boost);
addStat(row, 6, (unit.defense + unit.attack), average, Math.round(average*100000/unitCost), boost);
}
// new UI
cell = document.createElement('SPAN');
cell.style.display = "block";
row.cells[3].style.cursor = "pointer";
cell.textContent = ' '; // forces the creation of a text node
row.cells[3].appendChild(cell);
// update hook
row.cells[3].getElementsByTagName('INPUT')[0].addEventListener('blur', onBlur, false);
// order max amount hook
row.cells[3].addEventListener('click', onClick, false);
}
// hook up a confirmation dialog on the form
var youSure = function(e)
{
if(! confirm('Are you sure you want to produce these items/creatures?'))
e.preventDefault();
}
var daForm = table.getElementsByTagName('FORM')[0];
daForm.addEventListener('submit', youSure, false);
evoUpdateAvailableUnits(table);
}
//
// changes to the overview page
//
regPageHandler(/^\/(overview)?$/i, evoOverview);
function evoOverview() {
var tick = dEvo ? 5 : 60;
var i, ticks, total;
var node, match;
var now = new Date(document.lastModified);
var searchKey = dEvo ? "separator title":"title";
now.setUTCMinutes(now.getUTCMinutes() - now.getUTCMinutes() % tick);
// let's try to grab the player's coords
node = document.evaluate(".//span[preceding-sibling::span[@class='t_medium b' and text()='Status of continent']]",
contents, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
if( node != null && (match = node.innerHTML.match(/(\d*?),(\d*?),(\d*?):\w/)) ) {
GM_setValue(dEvo?'devoCoords':'evoCoords', match[0]);
unsafeWindow.evo_plus.coords = match[0];
} else
GM_log("Unable to find your coordinates :(", 1);
// look for the fleets status table and show the ETA
node = document.evaluate('.//div[@class="'+searchKey+'" and contains(., "Fleets\' status")]/following-sibling::div[1]/table', contents, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
if( node ) {
node.rows[0].cells[3].textContent = 'Ticks';
node.rows[0].insertCell(4);
node.rows[0].cells[4].textContent = 'ETA';
// let's parse the ETAs...
for(i = 1; i < node.rows.length; i++) {
if( node.rows[i].cells.length == 4 ) {
node.rows[i].insertCell(4);
if(! isNaN(ticks = parseInt(node.rows[i].cells[3].textContent)) ) {
var eta = new Date(now.valueOf() + (ticks * tick * 60000));
node.rows[i].cells[4].textContent = evoFromatNumberZ(eta.getUTCHours(),2) + ":" + evoFromatNumberZ(eta.getUTCMinutes(),2) + " GMT";
}
}
}
}
// Same for the R&D
var nodes = document.evaluate(".//div[@class='alt2 t_little' and preceding-sibling::div[@class='"+searchKey+"' and starts-with(.,'Currently')]]",
contents, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
if( !dEvo ) {
for( i = 0; node = nodes.snapshotItem(i); i++ ) {
node.innerHTML = node.innerHTML.replace(/(\d+)% \((\d+)\/(\d+) ticks\) complete\./,
function(str, p1, p2, p3, offset, s) {
var minutes = (Number(p3) - Number(p2)) * tick;
var eta = new Date(now.valueOf() + (minutes * 60000));
return p1 + '% (' + p2 + '/' + p3 + ' ticks) complete - ETA: ' + evoFromatNumberZ(eta.getUTCHours(),2) + ":" + evoFromatNumberZ(eta.getUTCMinutes(),2) + " GMT" + (minutes > 1440 ? ' (+' + Math.floor(minutes/1440) + ' day' + ( minutes >= 2880 ? 's' : '' ) + ')' : '');
});
}
} else {
for( i = 0; node = nodes.snapshotItem(i); i++ ) {
node.innerHTML = node.innerHTML.replace(/(\d+)% \((\d+)\/(\d+)\) complete\./,
function(str, p1, p2, p3, offset, s) {
var minutes = (Number(p3) - Number(p2)) * tick;
var eta = new Date(now.valueOf() + (minutes * 60000));
return p1 + '% (' + p2 + '/' + p3 + ') complete - ETA: ' + evoFromatNumberZ(eta.getUTCHours(),2) + ":" + evoFromatNumberZ(eta.getUTCMinutes(),2) + " GMT" + (minutes > 1440 ? ' (+' + Math.floor(minutes/1440) + ' day' + ( minutes >= 2880 ? 's' : '' ) + ')' : '');
});
}
}
// same for the creatures and stuff
if( !dEvo)
nodes = document.evaluate(".//div[@class='alt2 t_little' and preceding-sibling::div[@class='title' and text()='Current Production']]/table/tbody/tr[count(td)=3]",
contents, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
else
nodes = document.evaluate(".//div[@class='separator title']/following-sibling::div[@class='alt2 t_little']/table/tbody/tr[count(td)=3]",
contents, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for( i = 0; node = nodes.snapshotItem(i); i++ ) {
// add a column
node.insertCell(3);
if( match = /\d+% complete, (\d+) ticks remain/.exec(node.cells[2].textContent) ) {
var eta = new Date(now.valueOf() + (Number(match[1]) * tick * 60000));
node.cells[3].textContent = evoFromatNumberZ(eta.getUTCHours(),2) + ":" + evoFromatNumberZ(eta.getUTCMinutes(),2) + " GMT";
}
}
// add a link to the continent/planet
nodes = document.evaluate(".//td[child::span[@class='t_medium b']]", contents, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for( i= 0; node = nodes.snapshotItem(i); i++ )
node.innerHTML = node.innerHTML.replace(/<span class="t_little".*\((\d+,\d+,\d+)(:\w)?\)<\/span>/i, '<a href="/$1" style="text-decoration:none">$&</a>');
// attackers - defenders
if( node = document.evaluate(".//div[@class='alt2 t_little']/center/span[@class='t_little']", contents, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue ) {
attackers = new Array();
defenders = new Array();
var j, first = 24, last = 0;
nodes = node.getElementsByTagName('font');
for(i=0; i < 24; i++) attackers[i] = defenders[i] = 0;
for(i = 0; i < nodes.length; i++ ) {
if( match = /Incoming (\d+) creatures .* they will be here to (ATTACK|DEFEND) in (\d+) tick/.exec(nodes[i].innerHTML) ) {
var num = parseInt(match[3]);
if( match[2] == 'ATTACK' ) {
for(j = num; j < num + 3; j++) attackers[j] += parseInt(match[1]);
} else {
for(j = num; j < num + 6; j++) defenders[j] += parseInt(match[1]);
}
if( j > last ) last = j;
if( num < first ) first = num;
} else if( match = /(\d+) creatures (DEFENDING|ATTACKING) .* - (\d+) tick/.exec(nodes[i].innerHTML) ) {
var num = match[3];
if( match[2] == 'ATTACKING' ) {
for(j = 0; j < num; j++) attackers[j] += parseInt(match[1]);
} else {
for(j = 0; j < num; j++) defenders[j] += parseInt(match[1]);
}
if( num > last ) last = num;
first = 0;
}
}
var table = document.createElement('table');
table.className = 't_little';
table.cellSpacing = 1;
var rowT = table.insertRow(table.rows.length);
var rowA = table.insertRow(table.rows.length);
var rowD = table.insertRow(table.rows.length);
var cell;
rowT.innerHTML = "<td class=\"row1 b\">Tick</td>";
rowA.innerHTML = "<td class=\"row1 b\">Attackers</td>";
rowD.innerHTML = "<td class=\"row1 b\">Defenders</td>";
for( i = first; i < last; i++ ) {
(cell = rowT.insertCell(rowT.cells.length)).textContent = i; cell.style.textAlign = "center"; cell.style.padding = "0 2px 0 2px";
(cell = rowA.insertCell(rowA.cells.length)).textContent = attackers[i]; cell.style.textAlign = "center"; cell.style.padding = "0 2px 0 2px";
(cell = rowD.insertCell(rowD.cells.length)).textContent = defenders[i]; cell.style.textAlign = "center"; cell.style.padding = "0 2px 0 2px";
}
node.parentNode.insertBefore(table, node.nextSibling);
}
}
//
// restores the land cost display on the resources page
//
regPageHandler(/^\/resources\/overview/i, evoResources);
function evoResources() {
var resourcetable = document.evaluate(".//table[@class='t_little' and preceding-sibling::div[@class='title' and text()='Land']]",
contents, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
evoLandRatio();
if( resourcetable ) {
// do we have the graphic?
if( resourcetable.rows[0].cells[0].innerHTML == 'Unused Land' ) return;
// get current amount of allocated
var land = Number(resourcetable.rows[1].cells[1].innerHTML) + Number(resourcetable.rows[2].cells[1].innerHTML) + Number(resourcetable.rows[3].cells[1].innerHTML);
// onclick function....
showAllocCost = function(e) {
var parent = this.parentNode;
this.style.cursor = 'auto';
this.style.textDecoration = "none";
if( parent.nextSibling != null ) return;
parent = parent.parentNode;
var elm = document.createElement('IMG');
elm.src = 'http://ev5.neondragon.net/graphs/land.php?land=' + land;
parent.appendChild(elm);
elm = document.createElement('BR');
parent.appendChild(elm);
elm = document.createElement('SPAN');
elm.className = 't_little';
elm.innerHTML = '<SPAN class="red">Red</SPAN> values are the costs in metal to initiate the number of land on the x axis.';
parent.appendChild(elm);
};
var elm = document.createElement('DIV');
var span = document.createElement('SPAN');
elm.className = "title";
span.innerHTML = 'Land Initiation Cost';
span.style.textDecoration = "underline";
span.style.cursor = "pointer";
span.addEventListener('click',showAllocCost, false);
elm.appendChild(span);
resourcetable.parentNode.appendChild(elm);
}
function evoLandRatio() {
var fields = resourcetable.rows.length;
var food = Number(evoString2Number(resourcetable.rows[fields - 1].cells[1].textContent));
var mineral = Number(evoString2Number(resourcetable.rows[fields - 2].cells[1].textContent));
var metal = Number(evoString2Number(resourcetable.rows[fields - 3].cells[1].textContent));
if( isNaN(food) || isNaN(mineral) || isNaN(metal) ) return;
var gcd = gcf(gcf(metal,mineral),food);
metal = metal / gcd;
mineral = mineral / gcd;
food = food / gcd;
var row = resourcetable.insertRow(fields);
row.className = 'row2';
node = row.insertCell(0);
node.innerHTML = 'Ratio';
node.className = 'alt1 b';
node.style.textAlign = 'right';
node = row.insertCell(1);
node.innerHTML = metal + ':' + mineral + ':' + food;
node.style.textAlign = 'center';
// give approx. ratio with: 1 <= food <= 2
if( food > 2 && food < metal && food < mineral ) {
gcd = Math.pow(2, Math.floor(Math.log(food) / Math.log(2))) // divider
gcd = food / (food = Math.round(food / gcd)); // refine the divider
metal = Math.round(metal / gcd);
mineral = Math.round(mineral / gcd);
gcd = gcf(gcf(metal,mineral),food);
food /= gcd;
mineral /= gcd;
metal /= gcd;
node = row.insertCell(2);
node.innerHTML = '(~' + metal + ':' + mineral + ':' + food + ')';
node.style.textAlign = 'center';
node = row.insertCell(3);
node.colSpan = 2;
} else {
node = row.insertCell(2);
node.colSpan = 3;
}
}
}
//
// Alliances page
//
// @FIXME: optimize the below. I initially used a snapshot of each row because i ran into problems
// can't remember what though :(
//
if( !dEvo ) regPageHandler(/^\/alliances$/i, evoAlliances);
function evoAlliances() {
var row;
var rows = document.evaluate(".//table/tbody[tr/td[text()='Alliance Name']]/tr[count(td)=5]",
contents, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for(var i = 1; row = rows.snapshotItem(i); i++) {
row.cells[3].innerHTML = evoNumber2String(row.cells[3].textContent) + "<br><font color='#AAAAFF'>"+ evoNumber2String(Math.ceil(evoString2Number(row.cells[3].textContent)/evoString2Number(row.cells[2].textContent)))+"</font>";
row.cells[3].style.textAlign = "right";
row.cells[3].style.padding = "0 2px 0 2px";
}
}
//
// Alliance members
//
regPageHandler(/^\/alliances\/members/i, evoAllianceMembers);
function evoAllianceMembers() {
var smin = Math.ceil(pScore * 0.35);
var tmax = Math.floor(pScore / 0.35);
var tab = document.evaluate(".//table[tbody/tr/td[text()='Ruler of Continent Name']]", contents, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
var nbr = 0;
var sums1 = 0;
if(tab != null) {
for(var i=1; i < tab.rows.length; i++) {
var str = tab.rows[i].cells[2].innerHTML;
var g2 = evoString2Number(str);
var cell2 = tab.rows[i].cells[2];
sums1 = sums1 + g2;
cell2.style.textAlign = 'right';
if( g2 < smin ) cell2.style.color = '#CC4411';
else if( g2 > tmax ) { cell2.style.color = '#0000FF'; nbr++; }
else { cell2.style.color = '#00FF00'; nbr++; }
}
var g3=evoNumber2String(sums1);
tab.rows[0].cells[2].innerHTML = tab.rows[0].cells[2].innerHTML +'<font color="#00FF00"> '+ g3 + '</font><BR>Targets for me: <font color="#00FF00">' + nbr + '</font>';
} else
return;
var count = 0;
// quick buddy
// This feature makes a direct request to the server which is deemed illegal
// neon has however kindly accepted to allow it only for this particular feature
// since it puts less strain on the server than doing it the regular way
// AGAIN, THIS IS AN EXCEPTION. DON't USE XmlHttpRequest!!! IT IS ILLEGAL!
function onBuddy(e) {
var postData;
e.preventDefault();
try {
postData = e.target.href.match(/\/buddies\/add\?(.*)$/)[1];
} catch ( e ) {
return;
}
if( count++ ) {
alert("Wow... take it easy! One buddy at a time, will you?");
--count;
return;
}
e.target.textContent = "Please wait...";
e.target.href = '#';
GM_xmlhttpRequest({
method: 'POST',
url: 'http://'+document.location.hostname+'/buddies/add',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: postData,
onreadystatechange: function(responseDetails) {
if( responseDetails.readyState == 4 && responseDetails.status == 200 ) {
e.target.parentNode.removeChild(e.target);
--count;
}
},
onerror: function(responseDetails) {
e.target.href = "/buddies/add?" + postData;
e.target.textContent = ' Add to buddies';
--count;
}
});
}
var i, match;
var re = /javascript:return continentBox\(\d+,(\d+),(\d+),(\d+),(\d+),'(\w)','([^']+)','([^']+)','([^']+)','([^']+)','([^']*)',\s*'([^']*)'/;
var users = document.evaluate(".//a[@class='cleanlink continfo']", contents, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
for(i = 0; node = users.snapshotItem(i); i++) {
if( match = re.exec(node.getAttribute('onclick')) ) {
if( match[11] == '' ) {
var br, td = node.parentNode.parentNode;
var a = document.createElement('a');
a.href = '/buddies/add?x=' + match[2] + '&y=' + match[3] + '&z=' + match[4] + '&c=' + match[5] + '&nickname=' + encodeURIComponent(match[6]) + '&label=' + encodeURIComponent(node.textContent.match(/\[([^\]]+)\]/)[1]);
a.appendChild(document.createTextNode(' Add to buddies'));
a.addEventListener('click', onBuddy, false);
if(! (br = node.parentNode.nextSibling) )
td.appendChild(document.createElement('br'));
else
br.nextSibling.textContent += ' ';
td.appendChild(a);
}
}
}
}
//
// Add some color to the scores on the universe pages
//
regPageHandler(/^\/(universe\/(home|search)|(\d+(,\d+)*))$/i, evoUniverse);
function evoUniverse() {
var smin = Math.ceil(pScore * 0.35);
var tmax = Math.floor(pScore / 0.35);
var table = document.getElementById('cont_list');
if( table != null ) {
// let's add some color and look for potential targets ;)
for(var i=2; i < table.rows.length; i++) {
if( table.rows[i].cells.length < 4 )
continue;
var cell1 = table.rows[i].cells[1];
var cell3 = table.rows[i].cells[3];
var target = evoString2Number(cell3.innerHTML);
if( target < smin )
cell3.style.color = '#CC4411';
else if( target > tmax )
cell3.style.color ='#0000FF';
else
cell3.style.color = '#00FF00';
}
var git = document.evaluate(".//table[tbody/tr[1]/td[1][text() = 'Key']]", contents, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
if( git != null ) {
var d = git.insertRow(4);
d.className = "lightblue_bg_row2";
d.innerHTML = '<td>Text colours:</td><td colspan="3" align="center"><font color="#FFFFFF">White</font> name of continent shows that this person is online<BR><font color="#C4C4C4">Gray</font> name of continent shows that this person is offline<BR><font color="#646464">Dark gray</font> name shows that person is offline from more than week</td>';
var c = git.insertRow(5);
c.className = "lightblue_bg_row1";
c.innerHTML = '<td>Score colours:</td><td colspan="3" align="center">Player with that <font color="#CC4411">score</font> can attack you, but you can\'t<BR>Player with that <font color="#00FF00">score</font> can attack you, and you can also attack him<BR>Player with that <font color="#0000FF">score</font> can\'t attack you, but you can :D</td>';
}
}
}
//
// Evaluation of att/def on scans
//
regPageHandler(/^\/scans/i, evoScans );
function evoScans(){
var scan = document.evaluate(".//div[@class='helpmessage']/strong", contents, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (!scan) return;
var table = document.evaluate("./following-sibling::table", scan, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
scan = scan.textContent;
if (scan.indexOf("Sector Scan") != -1) {
var defenceData = new Array(
new Array(7, 'fort'),
new Array(8, 'satellite mark 2'),
new Array(9, 'nanowire wall')
);
var attack, defence, overallAttack = 0, overallDefence = 0;
var row, cells, nDef, unit, newCell;
var landAmt = 0, nLands = 0, unused = 0;
var rows = table.rows;
for (var i = 0; i < defenceData.length; i++){
cells = rows[defenceData[i][0]].cells;
if( cells.length == 4) {
// land defence
nLands = parseInt(cells[1].innerHTML);
if (!isNaN(nLands)) landAmt += nLands;
// static defences
nDef = parseInt(cells[3].innerHTML);
if (isNaN(nDef)) continue;
unit = units[defenceData[i][1]];
attack = unit.getAttackScore(nDef);
defence = unit.getDefenseScore(nDef);
overallAttack += attack;
overallDefence += defence;
cells[3].title = 'Estimated boosted att2/def2: ' + evoNumber2String(attack.toFixed(0)) + ' / ' + evoNumber2String(defence.toFixed(0));
}
}
// formatting score number / add attacker's score range
var resPics = new Array ('metal.png','mineral.png','food.png');
for (var i = 2; i < 5; i++) {
rows[i].cells[2].innerHTML = "<img style=\"vertical-align: top\" src='http://images.neondragon.net/ev5/resources/"+resPics[i-2]+"' border='0'> "+rows[i].cells[2].innerHTML;
rows[i].cells[3].innerHTML = "<font color=#ADD8E6>"+evoNumber2String(parseInt(rows[i].cells[3].innerHTML))+"<font>";
}
resPics = null;
var score = parseInt(rows[2].cells[1].innerHTML);
rows[2].cells[1].innerHTML = "<font color#FF850B>"+evoNumber2String(score)+"<font>";
rows[3].cells[0].innerHTML = "Max. Attacker Score";
rows[3].cells[0].className = "alt1 b";
rows[3].cells[1].innerHTML = "<font color=#FF850B>"+evoNumber2String(Math.ceil(score/.35))+"<font>";
rows[4].cells[0].innerHTML = "Min. Attacker Score";
rows[4].cells[0].className = "alt1 b";
rows[4].cells[1].innerHTML = "<font color=#FF850B>"+evoNumber2String(Math.ceil(score/2.5))+"<font>";
unused = parseInt(rows[6].cells[1].innerHTML);
row = table.insertRow(10);
row.title = "This DOES NOT include the creature stats";
newCell = row.insertCell(0);
newCell.className = "alt1 b";
newCell.innerHTML = "Land ratio/def2<sup>*</sup>";
newCell = row.insertCell(1);
newCell.innerHTML = "<font color=yellow>"+evoNumber2String((landAmt/(landAmt+unused)*100).toFixed(2))+"%</font> / <font color=#8FED9B>"+ evoNumber2String(((landAmt+unused)*(105*105)*1.4).toFixed(0))+"</font>";
newCell = row.insertCell(2);
newCell.className = "alt1 b";
newCell.innerHTML = "Overall att2/def2<sup>*</sup>";
newCell = row.insertCell(3);
newCell.innerHTML = "<font color=#F25763>"+evoNumber2String(overallAttack.toFixed(0)) + "</font> / <font color=#8FED9B>" + evoNumber2String(overallDefence.toFixed(0))+"</font>";
for( var i=6; i<=9; i++) {
if( rows[i].cells[1].innerHTML.length > 0)
rows[i].cells[1].innerHTML = evoNumber2String(parseInt(rows[i].cells[1].innerHTML));
if( rows[i].cells[3].innerHTML.length>0)
rows[i].cells[3].innerHTML = evoNumber2String(parseInt(rows[i].cells[3].innerHTML));
}
} else if (scan.indexOf("Creature Scan") != -1) {
var rows = table.rows;
var row, cells, cell, unit, quantity, boost;
var attack, defence, overallAttack = 0, overallDefence = 0;
var foodCost = 0;
for (var i = 2; i < rows.length; i++){
row = rows[i];
cells = row.cells;
for (var j = 0; j < cells.length; j += 2) {
unit = units[cells[j].textContent.toLowerCase()];
cell = cells[j + 1];
quantity = parseInt(cell.innerHTML);
boost = 1 + unit.getMaxBoost();
attack = unit.getAttackScore(quantity) * boost * boost;
defence = unit.getDefenseScore(quantity) * boost * boost;
foodCost += unit.getFoodCost(quantity);
overallAttack += attack;
overallDefence += defence;
cell.title = 'Estimated boosted att2/def2: ' + evoNumber2String(attack.toFixed(0)) + ' / ' + evoNumber2String(defence.toFixed(0));
}
}
var newRow = table.insertRow(rows.length);
newRow.title = 'Estimation of att2/def2 with max possible boosts';
var newCell = newRow.insertCell(0);
newCell.className = "alt1 b";
newCell.innerHTML = "Overall att2/def2<sup>*</sup>";
newCell = newRow.insertCell(1);
newCell.innerHTML = "<font color=#F25763>"+evoNumber2String(overallAttack.toFixed(0)) + "</font> / <font color=#8FED9B>" + evoNumber2String(overallDefence.toFixed(0))+"</font>"; // modify by ressol
if( dEvo ) newCell.innerHTML = newCell.innerHTML + " / <font color=#4B74AF>" + evoNumber2String((overallDefence/1.4*3.15).toFixed(0))+"</font>";
newCell.colSpan = 5;
newRow = table.insertRow(rows.length);
newCell = newRow.insertCell(0);
newCell.className = "alt1 b";
newCell.innerHTML = "Launch cost";
newCell = newRow.insertCell(1);
newCell.innerHTML = "<font color=#FF850B>"+evoNumber2String(foodCost.toFixed(0)) + "</font>"; // modify by ressol
newCell.colSpan = 5;
}
}
//
// Fleets page
//
regPageHandler(/^\/fleets/i, evoFleets );
function evoFleets(){
function updateFleetsAddCell(row, cellIndex, className, scores){
var cell = row.insertCell(cellIndex);
cell.className = className;
cell.style.textAlign = 'center';
cell.colSpan = 2;
if (cellIndex > 0) {
cell.style.fontSize = "12px";
cell.innerHTML = evoNumber2String(scores[1]);
cell.title = 'Unboosted: ' + evoNumber2String(scores[0]);
} else {
cell.innerHTML = scores; // cell title actually
}
}
function updateFleetsAddRow(fleetsTable, isAttack){
var row = fleetsTable.insertRow(fleetsTable.rows.length - 2);
updateFleetsAddCell(row, 0, "alt1 b", (isAttack ? "Attack" : "Defence") + '<br /><span style="font-size:smaller; font-weight: normal">(estimation w/ max boost)</span>');
updateFleetsAddCell(row, 1, "red_bg", getFleetScore(1, fleetsTable, isAttack));
updateFleetsAddCell(row, 2, "yellow_bg", getFleetScore(2, fleetsTable, isAttack));
updateFleetsAddCell(row, 3, "green_bg", getFleetScore(3, fleetsTable, isAttack));
}
function getFleetScore(fleetNo, table, isAttack){
var rows, row;
var unit, quantity, total = 0;
var i, j, baseScore, boost, noBoostScore = 0, maxBoostScore = 0;
rows = document.evaluate(".//tr[td[1]/a]", table, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for( i = 0; row = rows.snapshotItem(i); i++ ) {
if( row.cells[0].rowSpan > 1 ) break;
unit = units[row.cells[0].textContent.toLowerCase()];
quantity = Number(row.cells[fleetNo * 2 + 1].textContent);
total += quantity;
baseScore = isAttack ? unit.getAttackScore(quantity) : unit.getDefenseScore(quantity);
noBoostScore += baseScore;
boost = unit.getBoost() + 1;
maxBoostScore += baseScore * boost * boost;
}
row.cells[0].rowSpan = 12;
var cell = sumRow.cells[1 + fleetNo];
cell.textContent = total;
cell.style.textAlign = 'center';
cell.style.fontSize = '12px';
return new Array(Math.round(noBoostScore), Math.round(maxBoostScore))
}
var fleetsTable = null;
if( dEvo )
fleetsTable = document.evaluate(".//table[preceding-sibling::h2[@class='title']][1]",
contents, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
else
fleetsTable = document.evaluate(".//table[preceding-sibling::h2[@class='forum' and text()='Fleet Organisation']][1]",
contents, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
// add row for fleet counts
var sumRow = document.evaluate(".//tr[td[position()=1 and text()='Move to']]", fleetsTable, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
sumRow = fleetsTable.insertRow(sumRow.rowIndex);
sumRow.innerHTML = '<td class="alt1 b">Total</td><td class="alt2" colspan="2"></td><td class="red_bg" colspan="2"></td><td class="yellow_bg" colspan="2"></td><td class="green_bg" colspan="2"></td>';
updateFleetsAddRow(fleetsTable, true);
updateFleetsAddRow(fleetsTable, false);
}
//
// News page
//
regPageHandler(/^\/news/i, evoNews );
function evoNews() {
function addCell(row, cellIndex, attributes, html) {
var cell = row.insertCell(cellIndex);
if (attributes)
for (var i = 0; i < attributes.length; i++)
cell.setAttribute(attributes[i][0], attributes[i][1]);
if (html) cell.innerHTML = html;
return cell;
}
var dEvoExpTerm = ".//h3[@class='cnewstitle' and child::span[starts-with(.,'Battle Report')]]/following-sibling::table";
var RegExpTerm = (dEvo?dEvoExpTerm:".//tr[td[position()=2 and starts-with(.,'Battle Report')]]/following-sibling::tr[1]/td/table");
var battleReports = document.evaluate(RegExpTerm, contents, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
var battleReport;
var rows, html, attDefRow, isAttacker, att, myAtt, def, myDef,
idx, idx2, unit, quantity, boost, landType, land, myLand, summaryRow, cell, j;
var ruler = document.evaluate("//p[@id='openpanel']/strong[1]/text()", document, null, XPathResult.STRING_TYPE, null).stringValue;
var attPrefixRegex = /.*att<sup>2<\/sup>:\s*/;
var attSuffixRegex = /<br.*/;
var defPrefixRegex = /.*def<sup>2<\/sup>:\s*/;
for (var i = 0; battleReport = battleReports.snapshotItem(i); i++) {
rows = battleReport.rows;
attDefRow = rows[0];
isAttacker = attDefRow.cells[1].textContent.toLowerCase().indexOf(ruler.toLowerCase()) != -1;
idx = isAttacker ? 1 : 2;
att = attDefRow.cells[idx].innerHTML.replace(attPrefixRegex, "").replace(attSuffixRegex, "");
att = parseInt(att ? att : 0);
def = attDefRow.cells[idx].innerHTML.replace(defPrefixRegex, "");
def = parseInt(def ? def : 0);
myAtt = 0;
myDef = 0;
idx2 = isAttacker ? 1 : 6;
for (j = 3; j < rows.length; j++) {
unit = units[rows[j].cells[0].innerHTML.toLowerCase()];
if (!unit) break;
idx = rows[j].cells[idx2].innerHTML.indexOf("<br>");
quantity = parseInt(rows[j].cells[idx2].innerHTML.substring(idx + 4));
boost = 1+unit.getBoost();
myAtt += unit.getAttackScore(quantity) * boost * boost;
myDef += unit.getDefenseScore(quantity) * boost * boost;
}
summaryRow = battleReport.insertRow(rows.length);
cell = addCell(summaryRow, 0, new Array(new Array("colSpan", "11"), new Array("height", "3")));
summaryRow = battleReport.insertRow(rows.length);
cell = addCell(summaryRow, 0, new Array(new Array("class", "alt1 b")), "Summary");
html = "Att: " + evoNumber2String(myAtt.toFixed(0)) + " / <b>" + evoNumber2String(att) + "</b> (" + (att != 0 ? parseInt(100 * myAtt / att) : 0) + "%)<br/>" +
"Def: " + evoNumber2String(myDef.toFixed(0)) + " / <b>" + evoNumber2String(def) + "</b> (" + (def != 0 ? parseInt(100 * myDef / def) : 0) + "%)";
if (isAttacker) {
cell = addCell(summaryRow, 1, new Array(new Array("class", "red_bg_row2"), new Array("colSpan", "2")), html);
html = "";
for (; j < rows.length - 2; j++) {
if (rows[j].cells[0].innerHTML.indexOf("Land Capture") != -1) {
j++;
break;
}
}
for (; j < rows.length - 2; j++) {
landType = rows[j].cells[0].innerHTML;
land = rows[j].cells[2].firstChild.innerHTML;
myLand = rows[j].cells[2].innerHTML.replace(/.*<br>/, "");
idx = landType.length + (11 - landType.length) * 6;
landType = (landType + " ").substring(0, idx);
html += landType + ": " + myLand + " / <b>" + land + "</b> (" + parseInt(100 * myLand / land) + "%)<br/>";
}
cell = addCell(summaryRow, 2, new Array(new Array("class", "red_bg_row2"), new Array("colSpan", "3")), html);
cell = addCell(summaryRow, 3, new Array(new Array("class", "green_bg_row2"), new Array("colSpan", "5")));
} else {
cell = addCell(summaryRow, 1, new Array(new Array("class", "red_bg_row2"), new Array("colSpan", "5")));
cell = addCell(summaryRow, 2, new Array(new Array("class", "green_bg_row2"), new Array("colSpan", "5")), html);
}
// calcul land loss ratio
for( j=rows.length-3;j>rows.length-8; j--) {
if (rows[j].cells[0].innerHTML.indexOf("Land Capture") != -1) {
j++;
for(; j < rows.length -2; j++) {
landBefo = parseInt(rows[j].cells[4].innerHTML);
landLoss = parseInt(rows[j].cells[6].innerHTML);
rows[j].cells[6].className=rows[j].cells[6].className.substring(0,13)+" red";
rows[j].cells[6].innerHTML = "<B>"+rows[j].cells[6].innerHTML+"</B>"+(isAttacker?"<BR>":" ")+"("+(100*landLoss/landBefo).toFixed(2)+"%)";
}
break;
}
}
// losses evaluation
//
var total = new Array(), losses = new Array();
total[0] = total[1] = losses[0] = losses[1] = 0;
function updateLosses(unit, cells, idx, isAtt) {
var a = cells[idx].firstChild;
if(! a ) return; // no figures in the BR for defenses on the attacker's side
a = Number(a.textContent);
var l = Number(cells[idx+1].firstChild.textContent);
if( a == 0 ) return;
cells[idx+1].title = Math.round(100*l/a) + '% (' + evoNumber2String(Math.abs(l) * (unit.metal + unit.mineral)) + ')';
// take captures into account for the global stats
total[isAtt] += (a + Number(cells[idx+3].firstChild.textContent)) * (unit.metal + unit.mineral);
losses[isAtt] += (l + Number(cells[idx+2].firstChild.textContent)) * (unit.metal + unit.mineral);
}
for (j = 3; j < rows.length; j++) {
unit = rows[j].cells[0].innerHTML.toLowerCase();
if (unit == '') break;
unit = units[unit];
if (!unit) continue; // unknown unit?
updateLosses(unit, rows[j].cells, 1, 0);
updateLosses(unit, rows[j].cells, 6, 1);
}
battleReport.insertRow(j+2).innerHTML = '<TD class="row1 b"></TD><TD class="red_bg_row1 b">' + evoNumber2String(total[0]) + '</TD><TD class="red_bg_row1 b red" colspan="4">' + evoNumber2String(losses[0]) + ' (' + (losses[0]==0?0:Math.round(100*losses[0]/total[0])) + '%)</TD>'
+ '<TD class="green_bg_row1 b">' + evoNumber2String(total[1]) + '</TD><TD class="green_bg_row1 b red" colspan="4">' + evoNumber2String(losses[1]) + ' (' + (losses[1]==0?0:Math.round(100*losses[1]/total[1])) + '%)</TD>';
}
}
//
// Rankings page
//
regPageHandler(/^\/rankings\/alliance$/i, evoRankings);
function evoRankings() {
var row;
var score;
var land;
var members;
var rows = document.evaluate(".//table/tbody[tr/td[text()='Alliance Name']]/tr[count(td)=5]", contents, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for (var i = 2; row = rows.snapshotItem(i); i++ ) {
members = row.cells[2].textContent;
score = evoString2Number(row.cells[4].textContent);
land = evoString2Number(row.cells[3].textContent);
row.cells[0].style.textAlign = "center";
row.cells[1].style.padding = "0 2px 0 2px";
row.cells[2].style.textAlign = "center";
row.cells[3].innerHTML = row.cells[3].textContent + "<br><font color='#AAAAFF'>" + evoNumber2String(Math.ceil(land / members)) + "</font>";
row.cells[3].style.textAlign = "right";
row.cells[3].style.padding = "0 2px 0 2px";
row.cells[4].innerHTML = row.cells[4].textContent + "<br><font color='#AAAAFF'>" + evoNumber2String(Math.ceil(score / members)) + "</font>";
row.cells[4].style.textAlign = "right";
row.cells[4].style.padding = "0 2px 0 2px";
}
}
//
// ***************************************************************************
// ** CONFIG
// ***************************************************************************
//
GM_registerMenuCommand( "Configure boosts...", evoConfigBoosts, null, null, 'b' );
function evoConfigBoosts() {
var n;
if( (n = prompt("Boost for Natural Creatures? (e.g. 39.46625)", boosts[UT_NATURAL]*100)) != null && !isNaN(n = Number(n)) )
GM_setValue('boostNat', String(n/100));
if( (n = prompt("Boost for Archeoligocal Creatures? (e.g. 33.126875)", boosts[UT_ENG]*100)) != null && !isNaN(n = Number(n)) )
GM_setValue('boostEng', String(n/100));
alert("Please reload the page for the changes to take effect.");
}
//
// ***************************************************************************
// ** MAIN
// ***************************************************************************
//
(function () {
var totalPlayers = null;
var match;
var node;
var panel;
var profiler = Date.now();
// Initialization
// -----------------------------------------------------------------------
// contents node
contents = document.getElementById("content");
// get out of the bloody forums message editor
if( contents == null ) return;
// initialize the units table
evoUnitsInitialize();
// grab player's available resources
panel = document.getElementById("openpanel");
if( panel != null ) {
match = panel.textContent.match(/Metal:\s+([\d,]+)\s+Mineral:\s+([\d,]+)\s+Food:\s+([\d,]+)\s+Gold:\s+([\d,]+)\s+Score:\s+([\d,]+)/);
unsafeWindow.evo_plus['pMetal'] = pMetal = evoString2Number(match[1]);
unsafeWindow.evo_plus['pMineral'] = pMineral = evoString2Number(match[2]);
unsafeWindow.evo_plus['pFood'] = pFood = evoString2Number(match[3]);
unsafeWindow.evo_plus['pScore'] = pScore = evoString2Number(match[5]);
}
// ranking
panel = document.evaluate("//div[@id='panelinfo']/table/tbody/tr/td[2]/p", document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
if( panel != null ) {
if( match = /Current\s+Ranking:\s+([,0-9]+)\s+of\s+([,0-9]+)/.exec(panel.textContent) ) {
pRank = match[1];
totalPlayers = match[2];
}
}
// coords
unsafeWindow.evo_plus.coords = GM_getValue(dEvo?'devoCoords':'evoCoords');
// Dispatch
// -----------------------------------------------------------------------
for(var i = 0; i < pageHandlers.length; i++ ) {
if( pageHandlers[i].urlRegEx == null || pageHandlers[i].urlRegEx.test(document.location.pathname) )
pageHandlers[i].handler();
}
// THE evo+ bar
// -----------------------------------------------------------------------
node = document.createElement('DIV');
node.style.textAlign="right";
node.style.marginRight="5px";
node.style.marginTop="3px";
node.style.marginBottom="3px";
function addItemToContent(c, text, className, html, isLastItem) {
c.appendChild(document.createTextNode(text));
var span = document.createElement('SPAN');
span.className = className;
if (isLastItem)
html += " | ";
span.innerHTML = html;
c.appendChild(span);
}
addItemToContent(node, 'Rank: ', 't_normal b', pRank + "/" + totalPlayers, true);
addItemToContent(node, 'Min. TargetScore: ', 't_normal b', evoNumber2String(Math.ceil(pScore * 0.35)), true);
addItemToContent(node, 'Max. AttackerScore: ', 't_normal b', evoNumber2String(Math.floor(pScore / 0.35)), false);
contents.parentNode.insertBefore(node, contents);
node = document.createElement('DIV');
node.style.color = "#6A9C01";
node.style.fontSize = "8pt"; node.style.fontWeight = "bold";
node.style.paddingLeft = "3px"; node.style.paddingTop = "3px";
node.style.position = "absolute";
node.innerHTML = scriptversionID;
node.title = scriptTag;
node.id = "evomagik";
panel = document.getElementById('userinfo');
panel.parentNode.insertBefore(node, panel);
profiler = Date.now() - profiler;
// GM_log('evo+ exec time: ' + profiler + ' ms');
}) ();
//
// ***************************************************************************
// ** Helper functions
// ***************************************************************************
function gcf(a,b){while(b!=0){t=a%b;a=b;b=t}return a;}
function evoLayoutChanged() {
alert('Oops.. Page layout was not recognized, Neon probably changed the page :(');
}
function evoNumber2String(num) {
var re = /(\d+)(\d{3})/g;
num = String(num);
var decimalIdx = num.indexOf('.');
var part1 = '1', part2="";
if( decimalIdx != -1 ) {
part1 = num.substring(0, decimalIdx);
part2 = num.substring(decimalIdx + 1, num.length);
}
else
part1 = num;
while( re.test(part1) )
part1 = part1.replace(re, '$1,$2');
return part2 == "" ? part1 : part1 + "." + part2;
}
function evoString2Number(num) {
return Number(num.replace(/,/g,''));
}
function evoFromatNumberZ(num, zeros) {
var str = "0000" + Math.floor(Math.abs(num));
return str.substr(-zeros);
}
//
// ***************************************************************************
// ** Objects
// ***************************************************************************
// evoUnit
function evoUnit(unitName, unitType, ticks, metal, mineral, attack, defense, intel, weight, defenseBoost, eats) {
this.unitName = unitName;
this.unitType = unitType;
this.defense = defense;
this.attack = attack;
this.metal = metal;
this.ticks = ticks;
this.intel = intel;
this.weight = weight;
this.mineral = mineral;
this.eats = eats;
this.defenseBoost = defenseBoost/100 + 1;
return this;
}
//
// Page Handler hooks
function pageHandler(urlRegEx, handler) {
this.urlRegEx = urlRegEx;
this.handler = handler;
}
function regPageHandler(urlRegEx, handler) {
pageHandlers.push(new pageHandler(urlRegEx, handler));
}
//
// ***************************************************************************
// ** MISC
// ***************************************************************************
// GM implementation of cookies :)
function evoSetCookie(name, value, hours) {
GM_setValue('cv_' + name, value);
var expire = new Date();
expire.setUTCHours(expire.getUTCHours() + hours);
GM_setValue('cx_' + name, expire.toGMTString());
}
function evoGetCookie(name) {
var value = GM_getValue('cv_' + name);
var expire = GM_getValue('cx_' + name);
if( value != null && expire != null ) {
expire = new Date(expire);
if( expire.valueOf() >= Date.now() ) return value;
}
return null;
}
//
// ***************************************************************************
// ** Evo units stats
// ***************************************************************************
function evoUnitsInitialize() {
evoUnit.prototype.getFoodCost = function(count) {
return this.eats?count * (this.mineral+this.metal)/100:0;
}
evoUnit.prototype.getAttackScore = function(count) {
return count * this.attack * this.attack;
}
evoUnit.prototype.getDefenseScore = function(count) {
//Changed to reflect correct formula, Thanks to Mefisto of Alexandria
return count * this.defense * this.defense * this.defenseBoost;
}
evoUnit.prototype.getMaxUnits = function (metal, mineral) {
if( this.unitType == UT_NATURAL )
return Math.min(Math.floor(metal / (this.metal * eeb)), Math.floor(mineral / (this.mineral * eeb)));
else
return Math.min(Math.floor(metal / this.metal), Math.floor(mineral / this.mineral));
}
evoUnit.prototype.getMetal = function() {
return this.unitType == UT_NATURAL ? (this.metal * eeb) : this.metal;
}
evoUnit.prototype.getMineral = function() {
return this.unitType == UT_NATURAL ? (this.mineral * eeb) : this.mineral;
}
evoUnit.prototype.getMaxBoost = function() {
return maxBoosts[this.unitType];
}
evoUnit.prototype.getBoost = function() {
return boosts[this.unitType];
}
if(! dEvo ) {
units['monkey'] = new evoUnit('Monkey' ,UT_NATURAL ,4 ,500 ,250 ,4 ,4 ,4 ,0 ,40 ,true);
units['sheep'] = new evoUnit('Sheep' ,UT_NATURAL ,5 ,3000 ,1500 ,13 ,9 ,7 ,0 ,40 ,true);
units['horse'] = new evoUnit('Horse' ,UT_NATURAL ,6 ,4000 ,2000 ,15 ,10 ,8 ,1 ,40 ,true);
units['cow'] = new evoUnit('Cow' ,UT_NATURAL ,6 ,4500 ,2500 ,16 ,8 ,7 ,1 ,40 ,true);
units['fox'] = new evoUnit('Fox' ,UT_NATURAL ,10 ,10000 ,4000 ,25 ,23 ,18 ,0 ,40 ,true);
units['hyena'] = new evoUnit('Hyena' ,UT_NATURAL ,11 ,11000 ,4500 ,28 ,26 ,12 ,0 ,40 ,true);
units['wolf'] = new evoUnit('Wolf' ,UT_NATURAL ,12 ,12000 ,5000 ,30 ,25 ,18 ,0 ,40 ,true);
units['python'] = new evoUnit('Python' ,UT_NATURAL ,12 ,18000 ,7500 ,45 ,35 ,10 ,1 ,40 ,true);
units['ostrich'] = new evoUnit('Ostrich' ,UT_NATURAL ,13 ,19000 ,8000 ,48 ,37 ,11 ,2 ,40 ,true);
units['kangaroo'] = new evoUnit('Kangaroo' ,UT_NATURAL ,14 ,28000 ,14000 ,55 ,55 ,7 ,1 ,40 ,true);
units['lynx'] = new evoUnit('Lynx' ,UT_NATURAL ,15 ,20000 ,9000 ,50 ,38 ,12 ,1 ,40 ,true);
units['puma'] = new evoUnit('Puma' ,UT_NATURAL ,15 ,20000 ,8000 ,45 ,40 ,12 ,1 ,40 ,true);
units['lion'] = new evoUnit('Lion' ,UT_NATURAL ,15 ,20000 ,9000 ,42 ,45 ,12 ,1 ,40 ,true);
units['panther'] = new evoUnit('Panther' ,UT_NATURAL ,16 ,25000 ,12500 ,30 ,60 ,12 ,1 ,40 ,true);
units['bear'] = new evoUnit('Bear' ,UT_NATURAL ,16 ,30000 ,15000 ,60 ,50 ,17 ,2 ,40 ,true);
units['cheetah'] = new evoUnit('Cheetah' ,UT_NATURAL ,18 ,25000 ,12500 ,60 ,25 ,12 ,1 ,40 ,true);
units['walrus'] = new evoUnit('Walrus' ,UT_NATURAL ,19 ,44000 ,22000 ,70 ,50 ,7 ,2 ,40 ,true);
units['tiger'] = new evoUnit('Tiger' ,UT_NATURAL ,20 ,30000 ,15000 ,55 ,55 ,14 ,1 ,40 ,true);
units['rhino'] = new evoUnit('Rhino' ,UT_NATURAL ,24 ,60000 ,36000 ,80 ,40 ,2 ,3 ,40 ,true);
units['elephant'] = new evoUnit('Elephant' ,UT_NATURAL ,24 ,52000 ,26000 ,75 ,55 ,7 ,4 ,40 ,true);
units['centaur'] = new evoUnit('Centaur' ,UT_ENG ,6 ,5000 ,2500 ,25 ,20 ,19 ,1 ,40 ,true);
units['unicorn'] = new evoUnit('Unicorn' ,UT_ENG ,8 ,12000 ,6000 ,40 ,30 ,20 ,1 ,40 ,true);
units['minotaur'] = new evoUnit('Minotaur' ,UT_ENG ,18 ,50000 ,25000 ,65 ,50 ,13 ,2 ,40 ,true);
units['gryphon'] = new evoUnit('Gryphon' ,UT_ENG ,14 ,28000 ,14000 ,55 ,40 ,18 ,2 ,40 ,true);
units['dragon'] = new evoUnit('Dragon' ,UT_ENG ,24 ,100000 ,50000 ,85 ,65 ,10 ,3 ,40 ,true);
units['fire sprite'] = new evoUnit('Fire Sprite' ,UT_ENG ,5 ,6000 ,3000 ,35 ,17 ,14 ,0 ,40 ,true);
units['salamander'] = new evoUnit('Salamander' ,UT_ENG ,7 ,15000 ,7500 ,56 ,26 ,15 ,1 ,40 ,true);
units['phoenix'] = new evoUnit('Phoenix' ,UT_ENG ,12 ,36000 ,18000 ,77 ,35 ,14 ,1 ,40 ,true);
units['wyvern'] = new evoUnit('Wyvern' ,UT_ENG ,14 ,64000 ,32000 ,91 ,45 ,10 ,2 ,40 ,true);
units['demon'] = new evoUnit('Demon' ,UT_ENG ,21 ,140000 ,70000 ,119 ,59 ,7 ,3 ,40 ,true);
units['dyrad'] = new evoUnit('Dyrad' ,UT_ENG ,6 ,4000 ,3750 ,28 ,22 ,21 ,1 ,40 ,true);
units['baskilisk'] = new evoUnit('Baskilisk' ,UT_ENG ,9 ,12000 ,9000 ,44 ,33 ,22 ,1 ,40 ,true);
units['medusa'] = new evoUnit('Medusa' ,UT_ENG ,15 ,30000 ,22500 ,61 ,44 ,20 ,1 ,40 ,true);
units['cockatrice'] = new evoUnit('Cockatrice' ,UT_ENG ,20 ,50000 ,37500 ,71 ,55 ,14 ,2 ,40 ,true);
units['werewolf'] = new evoUnit('Werewolf' ,UT_ENG ,26 ,100000 ,75000 ,85 ,65 ,12 ,2 ,40 ,true);
units['avimimus'] = new evoUnit('Avimimus' ,UT_ENG ,5 ,4000 ,2000 ,23 ,18 ,12 ,1 ,40 ,true);
units['therizinsaurus'] = new evoUnit('Therizinsaurus' ,UT_ENG ,7 ,9600 ,4800 ,36 ,28 ,13 ,1 ,40 ,true);
units['styracosaurus'] = new evoUnit('Styracosaurus' ,UT_ENG ,13 ,22400 ,11200 ,50 ,35 ,10 ,2 ,40 ,true);
units['carnotaurus'] = new evoUnit('Carnotaurus' ,UT_ENG ,15 ,40000 ,20000 ,58 ,45 ,6 ,3 ,40 ,true);
units['giganotosaurus'] = new evoUnit('Giganotosaurus' ,UT_ENG ,20 ,80000 ,40000 ,77 ,58 ,2 ,4 ,40 ,true);
units['scarab beetle'] = new evoUnit('Scarab Beetle' ,UT_ENG ,8 ,6500 ,3250 ,30 ,26 ,19 ,0 ,40 ,true);
units['mummy'] = new evoUnit('Mummy' ,UT_ENG ,12 ,16000 ,8000 ,52 ,39 ,13 ,1 ,40 ,true);
units['sta'] = new evoUnit('Sta' ,UT_ENG ,18 ,38000 ,19000 ,72 ,52 ,12 ,1 ,40 ,true);
units['sphinx'] = new evoUnit('Sphinx' ,UT_ENG ,22 ,70000 ,35000 ,83 ,65 ,18 ,3 ,40 ,true);
units['anubis incarnate'] = new evoUnit('Anubis Incarnate' ,UT_ENG ,32 ,180000 ,90000 ,110 ,83 ,8 ,3 ,40 ,true);
units['fort'] = new evoUnit('Fort' ,UT_NONE ,4 ,2000 ,1000 ,25 ,40 ,0 ,0 ,40 ,false);
units['satellite'] = new evoUnit('Satellite' ,UT_NONE ,6 ,8000 ,4000 ,30 ,35 ,0 ,0 ,40 ,false);
units['nanowire wall'] = new evoUnit('Nanowire wall' ,UT_NONE ,10 ,12000 ,4500 ,65 ,65 ,0 ,0 ,40 ,false);
units['satellite mark 2'] = new evoUnit('Satellite Mark 2' ,UT_NONE ,6 ,8000 ,4000 ,35 ,45 ,0 ,0 ,40 ,false);
units['wave reflector'] = new evoUnit('Wave Reflector' ,UT_NONE ,4 ,2000 ,2000 ,0 ,0 ,0 ,0 ,0 ,false);
units['biochemical missile']=new evoUnit('Biochemical Missile',UT_NONE ,12 ,10000 ,20000 ,0 ,0 ,0 ,0 ,0 ,false);
units['nanovirus missile']= new evoUnit('Nanovirus Missile',UT_NONE ,12 ,30000 ,15000 ,0 ,0 ,0 ,0 ,0 ,false);
units['bombs'] = new evoUnit('Bombs' ,UT_NONE ,12 ,11000 ,7000 ,0 ,0 ,0 ,0 ,0 ,false);
units['neural reorganiser bomb']=new evoUnit('Neural Reorganiser Bomb',UT_NONE,24,50000,32000,0 ,0 ,0 ,0 ,0 ,false);
units['poison bombs'] = new evoUnit('Poison Bombs' ,UT_NONE ,16 ,16000 ,12000 ,0 ,0 ,0 ,0 ,0 ,false);
units['land scan'] = new evoUnit('Land Scan' ,UT_NONE ,4 ,1000 ,2000 ,0 ,0 ,0 ,0 ,0 ,false);
units['scan amplifier'] = new evoUnit('Scan Amplifier' ,UT_NONE ,4 ,1000 ,1000 ,0 ,0 ,0 ,0 ,0 ,false);
units['sector scan'] = new evoUnit('Sector Scan' ,UT_NONE ,8 ,2000 ,4000 ,0 ,0 ,0 ,0 ,0 ,false);
units['creature scan'] = new evoUnit('Creature Scan' ,UT_NONE ,8 ,3000 ,6000 ,0 ,0 ,0 ,0 ,0 ,false);
units['r&d scan'] = new evoUnit('R&D Scan' ,UT_NONE ,6 ,2000 ,3000 ,0 ,0 ,0 ,0 ,0 ,false);
units['news scan'] = new evoUnit('News Scan' ,UT_NONE ,18 ,10000 ,20000 ,0 ,0 ,0 ,0 ,0 ,false);
units['military scan'] = new evoUnit('Military Scan' ,UT_NONE ,12 ,6000 ,12000 ,0 ,0 ,0 ,0 ,0 ,false);
units['microwave pulse'] = new evoUnit('Microwave Pulse' ,UT_NONE ,20 ,520000 ,1040000 ,0 ,0 ,0 ,0 ,0 ,false);
units['overload pulse'] = new evoUnit('Overload Pulse' ,UT_NONE ,24 ,1600000 ,3200000 ,0 ,0 ,0 ,0 ,0 ,false);
} else {
// DEVO Stats
units['monkey'] = new evoUnit('Monkey' ,UT_NATURAL ,4 ,500 ,250 ,5 ,5 ,4 ,0 ,40 ,true);
units['sheep'] = new evoUnit('Sheep' ,UT_NATURAL ,4 ,1500 ,750 ,11 ,11 ,5 ,0 ,40 ,true);
units['horse'] = new evoUnit('Horse' ,UT_NATURAL ,5 ,2000 ,1000 ,13 ,13 ,6 ,1 ,40 ,true);
units['cow'] = new evoUnit('Cow' ,UT_NATURAL ,6 ,4500 ,2500 ,16 ,8 ,7 ,1 ,40 ,true);
units['fox'] = new evoUnit('Fox' ,UT_NATURAL ,9 ,7200 ,3200 ,24 ,25 ,8 ,0 ,40 ,true);
units['hyena'] = new evoUnit('Hyena' ,UT_NATURAL ,10 ,8800 ,3600 ,28 ,27 ,8 ,1 ,40 ,true);
units['wolf'] = new evoUnit('Wolf' ,UT_NATURAL ,10 ,8000 ,3500 ,27 ,25 ,14 ,0 ,40 ,true);
units['python'] = new evoUnit('Python' ,UT_NATURAL ,12 ,12500 ,5000 ,36 ,31 ,7 ,1 ,40 ,true);
units['ostrich'] = new evoUnit('Ostrich' ,UT_NATURAL ,13 ,18000 ,8000 ,43 ,41 ,6 ,2 ,40 ,true);
units['kangaroo'] = new evoUnit('Kangaroo' ,UT_NATURAL ,15 ,17000 ,8000 ,37 ,42 ,5 ,1 ,40 ,true);
units['lynx'] = new evoUnit('Lynx' ,UT_NATURAL ,15 ,12000 ,5500 ,35 ,31 ,10 ,1 ,40 ,true);
units['puma'] = new evoUnit('Puma' ,UT_NATURAL ,13 ,11000 ,5000 ,32 ,32 ,6 ,1 ,40 ,true);
units['lion'] = new evoUnit('Lion' ,UT_NATURAL ,15 ,12000 ,5000 ,31 ,35 ,10 ,1 ,40 ,true);
units['panther'] = new evoUnit('Panther' ,UT_NATURAL ,16 ,14000 ,7000 ,30 ,40 ,6 ,1 ,40 ,true);
units['bear'] = new evoUnit('Bear' ,UT_NATURAL ,16 ,26000 ,13000 ,57 ,50 ,12 ,3 ,40 ,true);
units['cheetah'] = new evoUnit('Cheetah' ,UT_NATURAL ,16 ,14000 ,7000 ,41 ,29 ,5 ,1 ,40 ,true);
units['walrus'] = new evoUnit('Walrus' ,UT_NATURAL ,18 ,28000 ,14000 ,53 ,54 ,4 ,2 ,40 ,true);
units['tiger'] = new evoUnit('Tiger' ,UT_NATURAL ,20 ,18000 ,9000 ,43 ,43 ,11 ,2 ,40 ,true);
units['rhino'] = new evoUnit('Rhino' ,UT_NATURAL ,24 ,28000 ,17000 ,66 ,53 ,3 ,3 ,40 ,true);
units['elephant'] = new evoUnit('Elephant' ,UT_NATURAL ,22 ,40000 ,20000 ,65 ,69 ,21 ,4 ,40 ,true);
units['centaur'] = new evoUnit('Centaur' ,UT_ENG ,5 ,4000 ,2400 ,22 ,23 ,10 ,1 ,40 ,true);
units['unicorn'] = new evoUnit('Unicorn' ,UT_ENG ,8 ,7200 ,3600 ,30 ,25 ,6 ,1 ,40 ,true);
units['minotaur'] = new evoUnit('Minotaur' ,UT_ENG ,12 ,10800 ,5400 ,36 ,35 ,8 ,2 ,40 ,true);
units['gryphon'] = new evoUnit('Gryphon' ,UT_ENG ,18 ,19000 ,9500 ,54 ,43 ,14 ,2 ,40 ,true);
units['dragon'] = new evoUnit('Dragon' ,UT_ENG ,24 ,30000 ,10500 ,76 ,67 ,8 ,3 ,40 ,true);
units['fire sprite'] = new evoUnit('Fire Sprite' ,UT_ENG ,5 ,5000 ,2500 ,25 ,18 ,4 ,0 ,40 ,true);
units['salamander'] = new evoUnit('Salamander' ,UT_ENG ,7 ,9000 ,4500 ,36 ,26 ,10 ,1 ,40 ,true);
units['phoenix'] = new evoUnit('Phoenix' ,UT_ENG ,12 ,14600 ,7300 ,44 ,35 ,6 ,1 ,40 ,true);
units['wyvern'] = new evoUnit('Wyvern' ,UT_ENG ,14 ,25000 ,17500 ,69 ,45 ,7 ,2 ,40 ,true);
units['demon'] = new evoUnit('Demon' ,UT_ENG ,21 ,36000 ,18000 ,96 ,60 ,5 ,3 ,40 ,true);
units['dryad'] = new evoUnit('Dryad' ,UT_ENG ,6 ,3600 ,2700 ,21 ,21 ,13 ,1 ,40 ,true);
units['basilisk'] = new evoUnit('Basilisk' ,UT_ENG ,9 ,6000 ,4500 ,29 ,24 ,21 ,1 ,40 ,true);
units['medusa'] = new evoUnit('Medusa' ,UT_ENG ,15 ,10000 ,7500 ,37 ,34 ,15 ,1 ,40 ,true);
units['cockatrice'] = new evoUnit('Cockatrice' ,UT_ENG ,20 ,18000 ,13500 ,54 ,45 ,23 ,2 ,40 ,true);
units['werewolf'] = new evoUnit('Werewolf' ,UT_ENG ,26 ,28000 ,18500 ,71 ,65 ,30 ,2 ,40 ,true);
units['avimimus'] = new evoUnit('Avimimus' ,UT_ENG ,5 ,3700 ,1850 ,22 ,17 ,2 ,1 ,40 ,true);
units['therizinsaurus'] = new evoUnit('Therizinsaurus' ,UT_ENG ,7 ,5000 ,2500 ,23 ,22 ,3 ,1 ,40 ,true);
units['styracosaurus'] = new evoUnit('Styracosaurus' ,UT_ENG ,13 ,9000 ,4500 ,32 ,41 ,8 ,2 ,40 ,true);
units['carnotaurus'] = new evoUnit('Carnotaurus' ,UT_ENG ,15 ,15000 ,7500 ,48 ,55 ,5 ,3 ,40 ,true);
units['giganotosaurus'] = new evoUnit('Giganotosaurus' ,UT_ENG ,20 ,24000 ,12000 ,74 ,58 ,4 ,4 ,40 ,true);
units['scarab beetle'] = new evoUnit('Scarab Beetle' ,UT_ENG ,8 ,6000 ,3000 ,26 ,23 ,7 ,0 ,40 ,true);
units['mummy'] = new evoUnit('Mummy' ,UT_ENG ,12 ,11000 ,5500 ,36 ,34 ,1 ,0 ,40 ,true);
units['sta'] = new evoUnit('Sta' ,UT_ENG ,18 ,18000 ,9000 ,45 ,42 ,12 ,1 ,40 ,true);
units['sphinx'] = new evoUnit('Sphinx' ,UT_ENG ,22 ,28000 ,14000 ,67 ,56 ,4 ,3 ,40 ,true);
units['anubis incarnate'] = new evoUnit('Anubis Incarnate' ,UT_ENG ,32 ,42000 ,21000 ,93 ,78 ,8 ,3 ,40 ,true);
units['fort'] = new evoUnit('Fort' ,UT_NONE ,4 ,2000 ,1000 ,25 ,40 ,0 ,0 ,215 ,false);
units['satellite'] = new evoUnit('Satellite' ,UT_NONE ,6 ,8000 ,4000 ,30 ,35 ,0 ,0 ,215 ,false);
units['nanowire wall'] = new evoUnit('Nanowire wall' ,UT_NONE ,10 ,12000 ,4500 ,65 ,65 ,0 ,0 ,215 ,false);
units['satellite mark 2'] = new evoUnit('Satellite Mark 2' ,UT_NONE ,6 ,8000 ,4000 ,35 ,45 ,0 ,0 ,215 ,false);
units['wave reflector'] = new evoUnit('Wave Reflector' ,UT_NONE ,4 ,2000 ,2000 ,0 ,0 ,0 ,0 ,0 ,false);
units['biochemical missile']=new evoUnit('Biochemical Missile',UT_NONE ,12 ,10000 ,20000 ,0 ,0 ,0 ,0 ,0 ,false);
units['nanovirus missile']= new evoUnit('Nanovirus Missile',UT_NONE ,12 ,30000 ,15000 ,0 ,0 ,0 ,0 ,0 ,false);
units['bombs'] = new evoUnit('Bombs' ,UT_NONE ,12 ,11000 ,7000 ,0 ,0 ,0 ,0 ,0 ,false);
units['neural reorganiser bomb']=new evoUnit('Neural Reorganiser Bomb',UT_NONE,24,50000,32000,0 ,0 ,0 ,0 ,0 ,false);
units['poison bombs'] = new evoUnit('Poison Bombs' ,UT_NONE ,16 ,16000 ,12000 ,0 ,0 ,0 ,0 ,0 ,false);
units['land scan'] = new evoUnit('Land Scan' ,UT_NONE ,4 ,1000 ,2000 ,0 ,0 ,0 ,0 ,0 ,false);
units['scan amplifier'] = new evoUnit('Scan Amplifier' ,UT_NONE ,4 ,1000 ,1000 ,0 ,0 ,0 ,0 ,0 ,false);
units['sector scan'] = new evoUnit('Sector Scan' ,UT_NONE ,8 ,2000 ,4000 ,0 ,0 ,0 ,0 ,0 ,false);
units['creature scan'] = new evoUnit('Creature Scan' ,UT_NONE ,8 ,3000 ,6000 ,0 ,0 ,0 ,0 ,0 ,false);
units['r&d scan'] = new evoUnit('R&D Scan' ,UT_NONE ,6 ,2000 ,3000 ,0 ,0 ,0 ,0 ,0 ,false);
units['news scan'] = new evoUnit('News Scan' ,UT_NONE ,18 ,10000 ,20000 ,0 ,0 ,0 ,0 ,0 ,false);
units['military scan'] = new evoUnit('Military Scan' ,UT_NONE ,12 ,6000 ,12000 ,0 ,0 ,0 ,0 ,0 ,false);
units['microwave pulse'] = new evoUnit('Microwave Pulse' ,UT_NONE ,20 ,520000 ,1040000 ,0 ,0 ,0 ,0 ,0 ,false);
units['overload pulse'] = new evoUnit('Overload Pulse' ,UT_NONE ,24 ,1600000 ,3200000 ,0 ,0 ,0 ,0 ,0 ,false);
}
unsafeWindow.evo_plus['units'] = units;
}