By jiji1
—
Last update
Nov 14, 2009
—
Installed
13,838 times.
Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)
scr_meta=<><![CDATA[
// ==UserScript==
// @name Travian: Antifarm\Troop saver
// @namespace Travian
// @description Script for Travian game. Sends your and reinforce troops away on attack; refreshes and relogins automatically. Supports multiple villages.
// @author m4rtini, deFox, Arias
// @version 1.2.7
// @license GNU General Public License
// @include http://*.travian*.*/dorf1.php*
// @require http://sizzlemctwizzle.com/updater.php?id=38017
// ==/UserScript==
]]></>.toString();
// Authors information - DO NOT CHANGE (unless you're an author too)
var a = "\
Authors:\
Original version by m4rtini.\
Extensive modifications by deFox.\
Auto updater by Arias.\
";
/**
* Date:
* 22 Jan 2008 - 05 Sep 2009
* Usage:
* Set troopTarget[] to coordinates of the villages where you want to
* send the troops to. You may also change other parameters; but don't
* think that setting it to any value will work. Don't make drastic
* changes.
* You should always see status message of the program in right panel.
* If it's not there, then the script isn't working. Note that it only
* works when you're in "Village and around" view (when address bar
* contains 'dorf1.php').
* Copying and copyrights:
* 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 2 of the License, or
* (at your option) any later version.
* Changelog:
* 15 Sep 2009, deFox:
* - Added checksum to troop send requests (due to T3.5 update)
* - Fixed mistake in saving only specific troop types
* 05 Sep 2009, Arias:
* - Added auto-update code
* 18 Aug 2009, deFox:
* - Resources planned at the moment of attack are now displayed
* - Unified way of handling requests
* - Users can now choose how the troops are sent (reinforce/attack/raid)
* - Numeric values are now always treated as decimal
* - Started work on resources saving function (unfinished yet)
* 02 Aug 2009, deFox:
* - Fixed auto-relogin code mistake
* 28 Jul 2009, deFox:
* - Updated troops retreating code
* - Reverted script name
* 23 Jul 2009, deFox:
* - Added sound playing function
* - Created authors preserve code
* 22 Jul 2009, deFox:
* - Fixed tag names because of travian 3.5 update
* - Verified and corrected some XPath code
*/
// Change these to some valid coordinates for your server.
// You can leave only one target village, or add more (as many as you want),
// just keep the number in brackets incrementing.
// Type X and Y coords; the third parameter controls how the troops are sent:
// 1-reinforce, 2-attack, 3-raid.
var troopTarget = new Array();
troopTarget[0] = [86,-72,1];
//troopTarget[1] = [70,-40,1];
//troopTarget[2] = [69,-39,1];
// Time to attack when the troops will be sent; in seconds.
// If your internet connection is very fast, then you could reduce it, ie. to 10 seconds.
const tmSave = 40;
// Time between page reloads when idle (no attack detected); in seconds
// The time will be increased by a random factor between 0 and 25%.
// If you don't have any enemies nearby, then you should increase it, let's say to 15*60.
// On the other hand, if you have many villages to switch between, you may want
// to make it smaller - only one village is checked on one reload, so for 5 villages
// you may want to set it to 4*60 to make a specific village checked every 20 minutes.
const tmIdleReload = 7*60;
// Percentage of tmSave after which the troops will be called back to your village.
// Should be between .50 and .99. Lower values may result in the troops getting back
// too early, higher values may lead to not calling them back at all.
const tmSaveCallBackPercent = 0.60;
// Some of the options below have logic value,
// which means they may be set to 'true' or 'false'.
// Determines if the script should reload page automatically in given intervals
var autoReload = true;
// Determines if the script should automatically 'press' login button if logged out
var autoLogin = true;
// Determines if the script should use its save troops code
var autoSaveTroops = true;
// Determines if the script should switch between villages.
// Setting this to 'false' will stick to the currently selected village.
var autoSwitchVillage = true;
// Determines if the script should call back reinforce troops on attack.
var autoSaveReinforce = true;
// Selects whether every kind of unit is saved or not. There are 11 types of troops,
// so there's one logic value for every kind - except for the first value, which is unused.
var saveUnitKind = new Array(true,true,true,true,true,true,true,true,true,true,true,true);
// Determines if the script should play a WAV file when attack is detected
var soundOnAttack = true;
// File name of the sound played if attack is detected
var soundUrl = "http://simplythebest.net/sounds/WAV/WAV_files/cartoon_WAV_files/charge.wav";
// Determines if the sound should be looped and play all the time
var soundLoop = false;
// Determines if the script should show information messages in right panel.
var showStatusMesages = true;
// Logging - for debugging purposes.
var logDebugMesages = false;
// End of configuration options.
// Internal values - do not change
var reloadOn = true;
var troopSaveState = 0;
var troopSaveErrors = 0;
var travActiveVilliage = 0;
var travActiveVilliageStr = "";
var nodeToAppendNb = "";
var tmIdleReloadExact = (tmIdleReload+Math.floor(tmIdleReload*Math.random()/4));
var activeVilliage = new Array();
activeVilliage["res_amount"] = new Array(0,0,0,0);
activeVilliage["res_produced"] = new Array(0,0,0,0);
activeVilliage["res_limit"] = new Array(0,0,0,0);
activeVilliage["field_kind"] = new Array(40);
activeVilliage["field_level"] = new Array(40);
activeVilliage["attack_log"] = new Array();
activeVilliage["crannys_capacity"] = 0;
var travTimeToFirstAttack = 990*60*60;
const SendAs_Default = 0;
const SendAs_Reinforce = 1;
const SendAs_Attack = 2;
const SendAs_Raid = 3;
const TSState_Monitoring = 0;
const TSState_SaveReinforce = 2;
const TSState_SaveTroops = 3;
const TSState_RetreatTroops = 5;
const Refrsh_SameUrl = 0;
const Refrsh_UrlClearParams = 1;
const Refrsh_ChangeVillage = 2;
const BLD_Woodcutter = 1;
const BLD_ClayPit = 2;
const BLD_IronMine = 3;
const BLD_Cropland = 4;
const BLD_Sawmill = 5;
const BLD_Brickyard = 6;
const BLD_IronFoundry = 7;
const BLD_GrainMill = 8;
const BLD_Bakery = 9;
const BLD_Warehouse = 10;
const BLD_Granary = 11;
const BLD_Blacksmith = 12;
const BLD_Armoury = 13;
const BLD_TournmSquare = 14;
const BLD_MainBuilding = 15;
const BLD_RallyPoint = 16;
const BLD_Marketplace = 17;
const BLD_Embassy = 18;
const BLD_Barracks = 19;
const BLD_Stable = 20;
const BLD_Workshop = 21;
const BLD_Academy = 22;
const BLD_Cranny = 23;
const BLD_TownHall = 24;
const BLD_Residence = 25;
const BLD_Palace = 26;
const BLD_Treasury = 27;
const BLD_TradeOffice = 28;
const BLD_GrBarracks = 29;
const BLD_GrStable = 30;
const BLD_CityWall = 31;
const BLD_EarthWall = 32;
const BLD_Palisade = 33;
const BLD_Stonemason = 34;
const BLD_Brewery = 35;
const BLD_Trapper = 36;
const BLD_HeroMansion = 37;
const BLD_GrWarehouse = 38;
const BLD_GrGranary = 39;
const BLD_WonderOTWorld= 40;
const BLD_HorseDrinkTr = 41;
var XPFirst = XPathResult.FIRST_ORDERED_NODE_TYPE;
var XPList = XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE;
var XPIterate = XPathResult.UNORDERED_NODE_ITERATOR_TYPE;
var XPNumber = XPathResult.NUMBER_TYPE;
var XPAny = XPathResult.ANY_TYPE;
/*
* The main function of this script.
*/
function functionMainTS(e)
{
loadActiveVillage();
loadTroopSaveState();
prepareDivDocking();
if (autoLogin)
loginCheck(document);
updateResAndProdInVillage(document);
doStateSpecificAction(document);
}
function doStateSpecificAction(doc)
{
//sendResources(doc); sheduleReloadCheck(tmIdleReloadExact*1000); return;
switch (troopSaveState)
{
case TSState_Monitoring: // 'monitoring' state
if (autoSaveTroops)
checkForAttackAndInitSaveTroops(doc);
// setTroopSaveState(TSState_SaveReinforce);//DEBUG command to force the saving immediatelly
break;
case TSState_SaveReinforce: // 'time to call off reinforce' state
if (autoSaveReinforce)
retreatReinforceTroops(doc);
// note: no 'break' here
case TSState_SaveTroops: // 'time to save troops' state
saveTroops(doc);
break;
case TSState_RetreatTroops: // 'check for retreat troops' state
checkRetreatTroops(doc);
break;
}
//TS_message("Active vil. "+getActiveVillageStr(document)+".");
//playAttackSound(doc);
//retreatReinforceTroops(doc);
}
//*** Start of autoupdate code ***
var AnotherAutoUpdater = {
// Config values, change these to match your script
id: '53931', // Script id on Userscripts.org
days: 1, // Days to wait between update checks
// Don't edit after this line, unless you know what you're doing ;-)
name: /\/\/\s*@name\s+(.*)\s*\n/i.exec(scr_meta)[1],
version: /\/\/\s*@version\s+(.*)\s*\n/i.exec(scr_meta)[1].replace(/\./g, ''),
time: new Date().getTime(),
call: function(response) {
GM_xmlhttpRequest({
method: 'GET',
url: 'https://userscripts.org/scripts/source/'+this.id+'.meta.js',
onload: function(xpr) {AnotherAutoUpdater.compare(xpr,response);}
});
},
compare: function(xpr,response) {
this.xversion=/\/\/\s*@version\s+(.*)\s*\n/i.exec(xpr.responseText);
this.xname=/\/\/\s*@name\s+(.*)\s*\n/i.exec(xpr.responseText);
if ( (this.xversion) && (this.xname[1] == this.name) ) {
this.xversion = this.xversion[1].replace(/\./g, '');
this.xname = this.xname[1];
} else {
if ( (xpr.responseText.match("the page you requested doesn't exist")) || (this.xname[1] != this.name) )
GM_setValue('updated_'+this.id, 'off');
return false;
}
if ( (+this.xversion > +this.version) && (confirm('A new version of the '+this.xname+' user script is available. Do you want to update?')) ) {
GM_setValue('updated_'+this.id, this.time+'');
top.location.href = 'https://userscripts.org/scripts/source/'+this.id+'.user.js';
} else if ( (this.xversion) && (+this.xversion > +this.version) ) {
if(confirm('Do you want to turn off auto updating for this script?')) {
GM_setValue('updated_'+this.id, 'off');
GM_registerMenuCommand("Auto Update "+this.name, function(){GM_setValue('updated_'+this.id, new Date().getTime()+''); AnotherAutoUpdater.call(true);});
alert('Automatic updates can be re-enabled for this script from the User Script Commands submenu.');
} else {
GM_setValue('updated_'+this.id, this.time+'');
}
} else {
if(response) alert('No updates available for '+this.name);
GM_setValue('updated_'+this.id, this.time+'');
}
},
check: function() {
if (GM_getValue('updated_'+this.id, 0) == 0) GM_setValue('updated_'+this.id, this.time+'');
if ( (GM_getValue('updated_'+this.id, 0) != 'off') && (+this.time > (+GM_getValue('updated_'+this.id, 0) + (1000*60*60*24*this.days))) ) {
this.call();
} else if (GM_getValue('updated_'+this.id, 0) == 'off') {
GM_registerMenuCommand("Enable "+this.name+" updates", function(){GM_setValue('updated_'+this.id, new Date().getTime()+'');AnotherAutoUpdater.call(true);});
} else {
GM_registerMenuCommand("Check "+this.name+" for updates", function(){GM_setValue('updated_'+this.id, new Date().getTime()+'');AnotherAutoUpdater.call(true);});
}
}
};
if (self.location == top.location && typeof GM_xmlhttpRequest != 'undefined') AnotherAutoUpdater.check();
//*** End of autoupdate code ***
// Now sub-functions will be defined
function find(xpath, xpres, startnode) {
if (!startnode) {startnode = document;}
var ret = document.evaluate(xpath, startnode, null, xpres, null);
return xpres == XPFirst ? ret.singleNodeValue : ret;
}
function addAttributes(elem, cAttribute) {
//proposed by Acr111. Thank you !
if (cAttribute !== undefined) {
for (var xi = 0; xi < cAttribute.length; xi++){
elem.setAttribute(cAttribute[xi][0], cAttribute[xi][1]);
if (cAttribute[xi][0].toUpperCase() == 'TITLE') elem.setAttribute('alt', cAttribute[xi][1]);
}
}
}
function newDiv(iHTML, cAttribute) {
var aDiv = document.createElement("div");
aDiv.innerHTML = iHTML;
addAttributes(aDiv, cAttribute);
return aDiv;
}
function newTable(cAttribute) {
var aTable = document.createElement("table");
addAttributes(aTable, cAttribute);
return aTable;
}
function newRow(iHTML, cAttribute) {
var aRow = document.createElement("tr");
aRow.innerHTML = iHTML;
addAttributes(aRow, cAttribute);
return aRow;
}
function newCell(iHTML, cAttribute) {
var aCell = document.createElement("td");
aCell.innerHTML = iHTML;
addAttributes(aCell, cAttribute);
return aCell;
}
function newEmbed(iHTML, cAttribute) {
var aCell = document.createElement("embed");
aCell.innerHTML = iHTML;
addAttributes(aCell, cAttribute);
return aCell;
}
function prepareDivDocking()
{
var dlright1 = 'sright';
var divlmidall;
var divDock = find("//div[@id='" + dlright1 + "']", XPFirst);
if (divDock == null)
{
divDock = newDiv("", [["id", dlright1],["style", "width:100%"]]);
divlmidall = find("//body/div[@id='lmidall']", XPFirst);
if (divlmidall == null)
divlmidall = find("//body/div[@id='mid']/div[@id='side_info']", XPFirst);
if (divlmidall == null)
divlmidall = find("//body", XPFirst);
divlmidall.appendChild(divDock);
}
if (divDock != null)
{
nodeToAppendNb = divDock;
}
}
/*
* Creates the right message and adds it to document.
*/
function showRightMessageBlock(doc,statusText)
{
if (typeof(nodeToAppendNb) != "object") return;
var aTable = createRightMessageBlock(statusText);
var parNB = doc.createElement("p");
parNB.appendChild(aTable);
aTable = parNB;
nodeToAppendNb.appendChild(aTable);
}
/*
* Create a right message, which strores the status.
*/
function createRightMessageBlock(statusText)
{
var aTable = newTable([["style", "width:0%;"]]);
var tr = newRow("");
var td = newCell("", []);
var pText = document.createTextNode(statusText);
dInfo = [509, 545, '60'];
aTable.setAttribute("style", "background-color: #e7e7e7; width: 310px; height: 24px; margin: -16px 0 0 -12px; padding: 0 0 0 0;");
td.appendChild(pText);
tr.appendChild(td);
aTable.appendChild(tr);
return aTable;
}
/*
* A function to show status messages in right panel.
*/
function TS_message(text)
{
if (logDebugMesages)
GM_log(text);
if (showStatusMesages)
showRightMessageBlock(document,"TS: "+text);
}
/*
* A function to log debug mesages into Javascript console.
*/
function TS_debug(text)
{
if (logDebugMesages)
GM_log(text);
}
/*
* Sends given 'post' request, with given callback function.
*/
function TS_postRequest(reqUrl,reqData,reqCallback)
{
TS_debug("POST: "+reqUrl+" "+reqData);
GM_xmlhttpRequest({
method: "POST",
url: reqUrl,
headers:{'Content-type':'application/x-www-form-urlencoded',
},
data:encodeURI(reqData),
onload: function(responseDetails)
{
var pulled;
pulled = document.createElement("div");
pulled.innerHTML = responseDetails.responseText;
reqCallback(pulled);
},
onerror: function(responseDetails)
{
var pulled;
pulled = document.createElement("div");
pulled.innerHTML = responseDetails.responseText;
reqCallback(pulled);
}
});
}
/*
* Sends given 'get' request, with given callback function.
*/
function TS_getRequest(reqUrl,reqCallback)
{
TS_debug("GET: "+reqUrl);
GM_xmlhttpRequest({
method: "GET",
url: reqUrl,
headers: {'Accept': 'application/atom+xml,application/xml,text/xml',
},
onload: function(responseDetails)
{
var pulled;
pulled = document.createElement("div");
pulled.innerHTML = responseDetails.responseText;
reqCallback(pulled);
},
onerror: function(responseDetails)
{
var pulled;
pulled = document.createElement("div");
pulled.innerHTML = responseDetails.responseText;
reqCallback(pulled);
}
});
}
/*
* Returns string representation of given time.
*/
function formatTimeStr(tmWhole)
{
var h = Math.floor(tmWhole/3600);
var m = Math.floor(tmWhole/60) % 60;
var s = Math.floor(tmWhole) % 60;
if (h < 10)
hs = "0"+h;
else
hs = h.toString();
if (m < 10)
ms = "0"+m;
else
ms = m.toString();
if (s < 10)
ss = "0"+s;
else
ss = s.toString();
return hs+":"+ms+":"+ss;
}
function waitFor(millis)
{
var date = new Date();
var curDate = null;
do { curDate = new Date(); }
while(curDate-date < millis);
}
function delayBetweenRequests()
{
var millis;
millis = tmSave*1000/60;
millis = Math.floor(millis+millis*Math.random());
if (millis > 5000)
millis = 5000;
waitFor(millis);
}
/*
* Returns first element of given tag and class.
*/
function getElementByTagAndClass(doc,tag_name,class_name)
{
//Populate the array with all the page tags
var matching_tags = doc.getElementsByTagName(tag_name);
var i;
//Cycle through the tags using a for loop
for (i=0; i<matching_tags.length; i++)
{
if (matching_tags[i].className == class_name)
return matching_tags[i];
}
}
/*
* Sets new active village number.
* "0" means there's only one village; 1..n is a village number
* if there are multiple villages.
*/
function setActiveVillage(nVillage)
{
travActiveVilliage = nVillage;
GM_setValue("travActiveVilliage", travActiveVilliage);
if (travActiveVilliage > 0)
travActiveVilliageStr = getVillageStr(document,travActiveVilliage-1);
else
travActiveVilliageStr = "";
GM_setValue("travActiveVilliageStr", travActiveVilliageStr);
}
/*
* Sets new active village number.
*/
function loadActiveVillage()
{
travActiveVilliage = GM_getValue("travActiveVilliage", 0);
travActiveVilliageStr = GM_getValue("travActiveVilliageStr", "");
}
/*
* Updates an array which stores resoure counts and production in the village.
*/
function updateResAndProdInVillage(doc)
{
var tag,tds;
var resourcesInVillage = activeVilliage["res_amount"];
var resProductionInVillage = activeVilliage["res_produced"];
var resLimitInVillage = activeVilliage["res_limit"];
tag = find(".//div[@id='goods']", XPFirst, doc);
if (tag == null)
tag = find(".//div[@id='res']", XPFirst, doc);
if (tag == null)
{
TS_debug("updateResAndProdInVillage: No res tag found.");
return false;
}
tds = find(".//td[contains(@id,'l')]", XPList, tag);
if (tds.snapshotLength < 4)
{
TS_debug("updateResAndProdInVillage: Not enough resource items found in res tag.");
return false;
}
var result = true;
for (var i=0; i < 4; i++)
{
temp = tds.snapshotItem(i).textContent;
if (temp.length > 0)
{
temp = temp.split("/",2);
if (temp.length >= 2)
{
resourcesInVillage[i] = parseInt(temp[0],10);
resLimitInVillage[i] = parseInt(temp[1],10);
} else
result = false;
} else
result = false;
//TS_debug("updateResAndProdInVillage: "+temp);
temp = tds.snapshotItem(i).title;
if (temp.length > 0)
resProductionInVillage[i] = parseInt(temp,10);
else
result = false;
}
return result;
}
/*
* Returns an array with plans for resource amounts after the given time will pass.
*/
function planResourcesAfter(tmPassed)
{
var planRes = Array(4);
var resourcesInVillage = activeVilliage["res_amount"];
var resProductionInVillage = activeVilliage["res_produced"];
var resLimitInVillage = activeVilliage["res_limit"];
for (var i=0; i < 4; i++)
{
var prodPerSec = resProductionInVillage[i]/(60*60);
planRes[i] = Math.ceil(resourcesInVillage[i] + prodPerSec*tmPassed);
if (planRes[i] > resLimitInVillage[i])
planRes[i] = resLimitInVillage[i];
if (planRes[i] < 0)
planRes[i] = 0;
}
return planRes;
}
/*
* Returns field ID where given building is, or 0 if it doesn't exist.
* TODO: make it work correctly!
*/
function getBuildingFieldId(building_id)
{
if (building_id == BLD_Marketplace) return 27;
return 0;
}
/*
* Sets new state of the troop saving process.
*/
function setTroopSaveState(nState,tmReloadWait)
{
troopSaveState = nState;
if (troopSaveState != TSState_Monitoring)
reloadOn = false;
else
reloadOn = true;
GM_setValue("troopSaveState", troopSaveState);
troopSaveErrors = 0;
GM_setValue("troopSaveErrors", troopSaveErrors);
if (tmReloadWait)
{
window.setTimeout(function(){if (reloadOn) refreshPage(Refrsh_UrlClearParams);},tmReloadWait);
} else
if (autoReload)
{
sheduleReloadCheck(tmIdleReloadExact*1000);
}
}
/*
* Loads state of the troop saving process into troopSaveState variable.
*/
function loadTroopSaveState()
{
troopSaveState = GM_getValue("troopSaveState", TSState_Monitoring);
if (troopSaveState != TSState_Monitoring)
reloadOn = false;
else
reloadOn = true;
troopSaveErrors = GM_getValue("troopSaveErrors", 0);
if (autoReload)
{
sheduleReloadCheck(tmIdleReloadExact*1000);
}
}
/*
* Shedules the page reload in given time.
*/
function sheduleReloadCheck(tmReloadWait)
{
window.setTimeout(function(){ refreshSwitchVillage(); },tmReloadWait);
}
function refreshSwitchVillage()
{
if (!reloadOn)
{
sheduleReloadCheck(tmIdleReloadExact*1000);
return;
}
if (autoSwitchVillage)
refreshPage(Refrsh_ChangeVillage);
else
refreshPage(Refrsh_UrlClearParams);
}
/*
* Increases errors counter of the troop saving process.
* The error counter is cleared on any state change.
*/
function incTroopSaveErrors()
{
troopSaveErrors++;
GM_setValue("troopSaveErrors", troopSaveErrors);
}
/*
* Returns XPath node of the villages table, or null if there's no such thing.
*/
function getVillagesTableNode(doc)
{
var tag;
tag = find(".//table[@class='vlist']", XPFirst, doc);
if (tag == null)
tag = find(".//table[@id='vlist']", XPFirst, doc);
if (tag == null)
tag = find(".//div[@id='sright']//table[@class='f10']", XPFirst, doc);
if (tag == null)
return null;
return tag;
}
/*
* Returns number of all villages.
*/
function getAllVillagesCount(doc)
{
var tag;
var vCount;
tag = getVillagesTableNode(doc);
if (!tag)
{
TS_debug("getAllVillagesCount: No villages list tag - treating as single village.");
return 1;
}
vCount = find("count(.//td//a[contains(@href,'?newdid=')])", XPNumber, tag);
if (vCount.numberValue > 0)
{
TS_debug("getAllVillagesCount: Got "+vCount.numberValue+" villages.");
return vCount.numberValue;
}
TS_debug("getAllVillagesCount: Can't recognize count - bad villages table.");
return 1;
}
/*
* Returns a string containing ID of an active village.
* The string looks like "newdid=<num>" and can be directly placed inside href.
*/
function getActiveVillageStr(doc)
{
var tag,hrefs;
tag = getVillagesTableNode(doc);
if (tag == null)
{
TS_debug("getActiveVillageStr: No villages list tag.");
return 0;
}
hrefs = find(".//a[contains(@href,'newdid')][@class='active_vl']", XPFirst, tag);
if (hrefs == null)
hrefs = find(".//td[@class='dot hl']/..//a[contains(@href,'newdid')]", XPFirst, tag);
if (hrefs == null)
{
TS_debug("getActiveVillageStr: Can't recognize which village is active.");
return 0;
}
temp = hrefs.href.split("?")[1].split('&');
return temp[0];
}
/*
* Returns a string containing ID of a village with given position in table.
* The string looks like "newdid=<num>" and can be directly placed inside href.
*/
function getVillageStr(doc,nVillage)
{
var tag,hrefs;
var temp;
tag = getVillagesTableNode(doc);
if (!tag)
{
TS_debug("getVillageStr: No villages list tag.");
return "";
}
hrefs = find(".//td//a[contains(@href,'?newdid=')]", XPList, tag);
if (hrefs.snapshotLength <= nVillage)
{
TS_debug("getVillageStr: Village index "+nVillage+" is too large.");
return "";
}
temp = hrefs.snapshotItem(nVillage).href;
if (temp.length > 0)
return temp.split("?")[1].split('&')[0];
TS_debug("getVillageStr: Can't locate href in village list.");
return "";
}
/*
* Returns ID of a village with given position in table.
*/
function getVillageId(doc,nVillage)
{
var href_str;
href_str = getVillageStr(doc,nVillage);
if (href_str.length > 0)
return parseInt(href_str.split('=')[1],10);
return 0;
}
/*
* Finds the next active village number.
* Sets it so that next time the next village will be checked.
*/
function updateCheckToNextVillage(doc)
{
var nVillage,allVillages;
allVillages = getAllVillagesCount(doc);
if (allVillages <= 1)
{
nVillage = 0;
} else
{
nVillage = travActiveVilliage+1;
if (nVillage > allVillages)
nVillage = 1;
}
setActiveVillage(nVillage);
TS_debug("Next village set to "+travActiveVilliage);
}
/*
* Returns enemy troops arrival time, in seconds.
* A value over 900*60*60 means an error.
*/
function getEnemyAttackArrivalTime(doc)
{
// if (travTimeToFirstAttack < 900*60*60)
// return travTimeToFirstAttack;
var div,tbrows,tbcells,tbdiv,tbspan;
var arrival,arrivsplt;
var hours,minutes,seconds;
var i;
div = doc.getElementById("ltbw0");
if (!div) {div = doc.getElementById("ltbw1"); }
if (!div) {div = doc.getElementById("troop_movements"); }
if (!div) {div = doc.getElementById("movements"); }
if (!div) return 998*60*60; // on error, return 998 hours
arrival = "0";
tbrows = div.getElementsByTagName('tr');
// TS_debug("getEnemyAttackArrivalTime: troops area found, "+tbrows.length+" rows");
for (i=0; i < tbrows.length; i++)
{
tbcells = tbrows[i].getElementsByTagName("td");
// TS_debug("getEnemyAttackArrivalTime: row "+i+" has "+tbcells.length+" cells");
if (tbcells.length < 1) continue;
if (tbcells[0].innerHTML.search("att1") > 0)
{
if (tbcells.length >= 5)
{
tbspan = tbcells[4].getElementsByTagName("span");
arrival = tbspan[0].innerHTML;
} else
if (tbcells.length >= 2)
{
tbdiv = getElementByTagAndClass(tbcells[1],"div","dur_r")
tbspan = tbdiv.getElementsByTagName("span");
arrival = tbspan[0].innerHTML;
}
}
}
arrivsplt = arrival.split(":",4);
TS_debug("getEnemyAttackArrivalTime: time tag is \""+arrival+"\"");
if (arrivsplt.length != 3) return 999*60*60; // on error, return 999 hours
hours = parseInt(arrivsplt[0],10);
minutes = parseInt(arrivsplt[1],10);
seconds = parseInt(arrivsplt[2],10);
travTimeToFirstAttack = hours*60*60 + minutes*60 + seconds;
return travTimeToFirstAttack;
}
/*
* Returns a random position, from a config array, to send the troops to.
*/
function getTroopSavePosition()
{
var i = Math.floor(Math.random()*troopTarget.length);
return troopTarget[i];
}
/*
* Returns a position to send the resources to.
*/
function getResourceSavePosition()
{
return [-135, 147];
}
/*
* Starts the saving action. Sends a request for troops send screen.
* When the resulting screen is returned, executes next function.
*/
function saveTroops(doc)
{
TS_message("Making the send away request...");
reqUrl = "http://" + document.domain + "/a2b.php?" + getActiveVillageStr(document);
TS_getRequest(reqUrl,prepSave);
return true;
}
/*
* Does the saving action. Gets amount of troops from pulled a2b screen
* and sends request to move them.
*/
function prepSave(a2b_doc)
{
var cVal,trSum;
var timestamp,timestamp_checksum;
var trVal = Array(12);
var i,savePos;
var reqUrl,reqData;
// Get amounts of troops
for (i=1; i < 12; i++)
{
if (saveUnitKind[i])
trVal[i] = getTotalUnit(a2b_doc,"t"+i);
else
trVal[i] = "0";
}
// Other values stored in form
timestamp = getFormHidVal(a2b_doc, "timestamp");
timestamp_checksum = getFormHidVal(a2b_doc, "timestamp_checksum");
// Compute sum of all troops
trSum = 0;
for (var i=1; i < 12; i++)
trSum += parseInt(trVal[i],10);
// Check if there are any troops
if (trSum < 1)
{
TS_message("No troops to send; action skipped.");
setTroopSaveState(TSState_Monitoring, tmSave*1000/7);
return;
}
savePos = getTroopSavePosition()
switch (savePos[2])
{
case SendAs_Reinforce:
default:
cVal = 2;
break;
case SendAs_Attack:
cVal = 3;
break;
case SendAs_Raid:
cVal = 4;
break;
}
// For unknown purposes, a mouse position over button is sent with the form
s1xPos = Math.floor(46*Math.random())+1;
s1yPos = Math.floor(19*Math.random())+1;
// Now making the request
TS_message("Sending "+trSum+" troops to ("+savePos[0]+"|"+savePos[1]+").");
reqUrl = "http://" + document.domain + "/a2b.php?" + getActiveVillageStr(document);
reqData = "timestamp="+timestamp+"×tamp_checksum="+timestamp_checksum+"&b="+1
+"&t1="+trVal[1]+"&t4="+trVal[4]+"&t7="+trVal[7]+"&t9="+trVal[9]+"&t2="+trVal[2]+"&t5="+trVal[5]
+"&t8="+trVal[8]+"&t10="+trVal[10]+"&t11="+trVal[11]+"&t3="+trVal[3]+"&t6="+trVal[6]
+"&c="+cVal+"&dname=&x="+savePos[0]+"&y="+savePos[1]+"&s1.x="+s1xPos+"&s1.y="+s1yPos+"&s1=ok";
TS_postRequest(reqUrl,reqData,finishSave);
}
/*
* Finishes the saving action. Confirms the second 'send troops' screen.
*/
function finishSave(a2b_doc)
{
var idVal,aVal,cVal,kidVal;
var timestamp,timestamp_checksum;
var trVal = Array(12);
var reqUrl,reqData;
var i;
// Get amounts of troops
for (i=1; i < 12; i++)
{
if (saveUnitKind[i])
trVal[i] = getFormHidVal(a2b_doc,"t"+i);
else
trVal[i] = "0";
}
// Other values stored in form
idVal = getFormHidVal(a2b_doc, "id");
aVal = getFormHidVal(a2b_doc, "a");
cVal = getFormHidVal(a2b_doc, "c");
kidVal = getFormHidVal(a2b_doc, "kid");
timestamp = getFormHidVal(a2b_doc, "timestamp");
timestamp_checksum = getFormHidVal(a2b_doc, "timestamp_checksum");
// For unknown purposes, a mouse position over button is sent with the form
s1xPos = Math.floor(46*Math.random())+1;
s1yPos = Math.floor(19*Math.random())+1;
// Preparing the request
reqUrl = "http://" + document.domain + "/a2b.php?" + getActiveVillageStr(document);
reqData = "timestamp="+timestamp+"×tamp_checksum="+timestamp_checksum+"&id="+idVal+"&a="+aVal+"&c="+cVal+"&kid="+kidVal
+"&t1="+trVal[1]+"&t2="+trVal[2]+"&t3="+trVal[3]+"&t4="+trVal[4]+"&t5="+trVal[5]+"&t6="+trVal[6]
+"&t7="+trVal[7]+"&t8="+trVal[8]+"&t9="+trVal[9]+"&t10="+trVal[10]+"&t11="+trVal[11]
+"&s1.x="+s1xPos+"&s1.y="+s1yPos+"&s1=ok&attacks=&cords=";
TS_postRequest(reqUrl,reqData,function(response_doc)
{
setTroopSaveState(TSState_RetreatTroops);
refreshPage(Refrsh_UrlClearParams);
});
}
/*
* Checks if it's time to retreat the sent troops.
*/
function checkRetreatTroops(doc)
{
var tag,tmSaveCallBack;
tag = find(".//img[contains(@class,'def2')]", XPList, doc);
if (tag.snapshotLength > 0)
{
TS_message("Troops sent away.");
tmSaveCallBack = Math.floor(tmSave*tmSaveCallBackPercent);
window.setTimeout(function(){retreatTroops()},tmSaveCallBack*1000);
TS_message("Troops will be retreated in "+formatTimeStr(tmSaveCallBack)+".");
} else
{
TS_message("Warning, can't find the troops sent; resetting.");
setTroopSaveState(TSState_Monitoring,500);
}
}
function retreatTroops()
{
TS_message("Preparing to retreat troops");
reqUrl = "http://" + document.domain + "/build.php?id=39&" + getActiveVillageStr(document);
TS_getRequest(reqUrl,finishRetreat);
}
function finishRetreat(build_doc)
{
TS_debug("finishRetreat: starting");
var tag,reqUrl,tVal,tNew;
tag = find(".//img[contains(@class,'del')]/..[contains(@href,'t=')]", XPList, build_doc);
reqUrl = "";
tVal = 0;
// Selecting retreat link with largest "t=" parameter.
for(var i=0; i < tag.snapshotLength; i++)
{
temp = "" + tag.snapshotItem(i);
TS_debug("Retreat href: "+temp);
tNew = parseInt(temp.split('t=')[1],10);
if (tNew > tVal)
{
reqUrl = temp;
tVal = tNew;
}
}
if (tVal == 0)
{
TS_message("Warning, time to bring the troops back has expired.");
setTroopSaveState(TSState_Monitoring);
return;
}
TS_getRequest(reqUrl,function(response_doc)
{
TS_message("Troops retreated.");
setTroopSaveState(TSState_Monitoring,500);
});
}
/*
* Starts the process of retreating reinforce troops.
* Makes request for the Rally Point page and sends it to prepRetreatReinforce().
*/
function retreatReinforceTroops(doc)
{
TS_message("Calling off reinforce troops");
reqUrl = "http://" + doc.domain + "/build.php?id=39&" + getActiveVillageStr(doc);
TS_getRequest(reqUrl,prepRetreatReinforce);
}
/*
* Continues the process of retreating reinforce troops.
* Lists turn back options in the Rally Point screen and executes them, one by one.
*/
function prepRetreatReinforce(rally_doc)
{
var tag;
TS_debug("prepRetreatReinforce: starting");
tag = find(".//table[@class='troop_details']//div[@class='sback']/a[(contains(@href,'?d=')) and (contains(@href,'&c='))]", XPList, rally_doc);
if (tag.snapshotLength <= 0)
{
tag = find(".//td[contains(@class,'r')]/a[(contains(@href,'?d=')) and (contains(@href,'&c=')) and not(contains(@href,'karte.php'))]", XPList, rally_doc);
}
if (tag.snapshotLength <= 0)
{
TS_message("No reinforce to call off.");
setTroopSaveState(TSState_SaveTroops);
return;
}
TS_message("Found "+tag.snapshotLength+" reinforce groups.");
for(var i=0; i < tag.snapshotLength; i++)
{
reqUrl = "" + tag.snapshotItem(i);
TS_getRequest(reqUrl,finishRetreatReinforce);
delayBetweenRequests();
}
setTroopSaveState(TSState_SaveTroops);
}
function finishRetreatReinforce(a2b_doc)
{
var idVal,aVal,dVal;
var trVal = Array(12);
var trSum,reqUrl,reqData;
// Get values from the a2b form
idVal = getFormHidVal(a2b_doc, "id");
aVal = getFormHidVal(a2b_doc, "a");
dVal = getFormHidVal(a2b_doc, "d");
for (i=1; i < 12; i++)
{
if (saveUnitKind[i])
trVal[i] = getFormInpVal(a2b_doc,"t["+i+"]");
else
trVal[i] = "0";
}
// Compute sum of all troops
trSum = 0;
for (var i=1; i < 12; i++)
trSum += parseInt(trVal[i],10);
// Prepare reqest string
reqUrl = "http://" + document.domain + "/build.php?" + getActiveVillageStr(document);
reqData = "id="+idVal+"&a="+aVal+"&d="+dVal;
for (var i=1; i < 12; i++)
reqData += "&t["+i+"]="+trVal[i];
reqData += "&s1=ok";
TS_debug(reqUrl+" "+reqData);
TS_postRequest(reqUrl,reqData,function(response_doc)
{
TS_message("Reinforce group of "+trSum+" troops called off.");
});
}
function getTotalUnit(doc,t)
{
var ex = ".//a[contains(@OnClick,'" + t + "')][@href='#']";
result = find(ex, XPList, doc);
if (result.snapshotLength > 0)
{
thisResult = result.snapshotItem(0).innerHTML;
return ((thisResult.substring(1,thisResult.length-1)))
} else {
return 0;
}
}
function getFormHidVal(doc, name)
{
var ex = ".//input[@type='hidden'][@name='" + name + "']";
tag = find(ex, XPFirst, doc);
if (tag == null)
return 0;
return(tag.value);
}
function getFormInpVal(doc, name)
{
var ex = ".//input[@name='" + name + "']";
tag = find(ex, XPFirst, doc);
if (tag == null)
return 0;
return (tag.value);
}
/*
* Checks the time of arrival and starts the saving, or shedules a next check.
*/
function checkArivalAndSaveTroops()
{
var totSeconds,shouldReload;
TS_debug("checkArivalAndSaveTroops: starting");
totSeconds = getEnemyAttackArrivalTime(document);
if (totSeconds > 900*60*60) // If can't get enemy arrival time
{
incTroopSaveErrors();
if (troopSaveErrors < 6)
{
TS_message("Error; fast retry sheduled.");
window.setTimeout(function(){checkArivalAndSaveTroops()},600);
} else
{
TS_message("Persisting error; resetting the script.");
setTroopSaveState(TSState_Monitoring,tmSave*50);
}
}
if (totSeconds < tmSave) // If time to do the saving
{
TS_debug("checkArivalAndSaveTroops: save started; "+totSeconds+" seconds to attack");
setTroopSaveState(TSState_SaveReinforce);
return doStateSpecificAction(document);
} else
{
TS_debug("checkArivalAndSaveTroops: save delayed; "+totSeconds+" seconds to attack");
TS_message("Sending troops in "+formatTimeStr(totSeconds-tmSave)+".");
shouldReload = false;
if (totSeconds < 2*tmSave)
{
nextCheckTime = tmSave*100;
} else
if (totSeconds < 10*tmSave)
{
nextCheckTime = tmSave*1000;
if (totSeconds < 3*tmSave)
shouldReload = true;
} else
if (totSeconds < 20*tmSave)
{
nextCheckTime = 9*tmSave*1000;
shouldReload = true;
} else
{
nextCheckTime = 15*tmSave*1000;
shouldReload = true;
}
if (nextCheckTime > tmIdleReloadExact*1000)
nextCheckTime = tmIdleReloadExact*1000;
if ((autoReload) && (shouldReload))
{
TS_message("Refresh sheduled in "+formatTimeStr(nextCheckTime/1000)+".");
window.setTimeout(function(){refreshPage(Refrsh_UrlClearParams);},nextCheckTime);
return false;
}
// If don't have to reload, then just shedule the next check on same page
TS_message("Next check sheduled in "+formatTimeStr(nextCheckTime/1000)+".");
window.setTimeout(function(){checkArivalAndSaveTroops()},nextCheckTime);
return false;
}
}
/*
* Inserts an attack sound into the page.
*/
function playAttackSound(doc)
{
var tag,embed;
if (!soundOnAttack)
return;
tag = find(".//body", XPFirst, doc);
if (!tag)
{
TS_debug("playAttackSound: Can't play sound - no body tag.");
return;
}
embed = newEmbed("", [["src", soundUrl],["hidden", "true"],["autostart", "true"],["loop", soundLoop.toString()]]);
tag.appendChild(embed);
}
/*
* Checks if there's attack icon on the page.
* If so, initializes troop saving operation.
*/
function checkForAttackAndInitSaveTroops(doc)
{
var tag;
var totSeconds;
tag = find(".//img[contains(@class,'att1')]", XPList, doc);
if (tag.snapshotLength > 0)
{
TS_debug("checkForAttackAndInitSaveTroops: attack detected!");
playAttackSound(doc);
if ((typeof a == "undefined") || (a.indexOf(" d\x65\x46\x6fx") < 0) || (a.indexOf(" \x6d4r\x74i\x6ei") < 0))
return false;
totSeconds = getEnemyAttackArrivalTime(doc);
if (totSeconds < 900*60*60) // If enemy arrival time is valid
{
TS_message("Res. planned: "+planResourcesAfter(totSeconds));
}
return checkArivalAndSaveTroops();
} else
{
updateCheckToNextVillage(doc);
if ((autoReload) && (reloadOn))
str = "auto refresh in "+formatTimeStr(tmIdleReloadExact);
else
str = "no automatic refresh";
TS_message("Monitoring;"+str+".");
return false;
}
}
/*
* Sends excessive resources from a village into another village.
* UNFINISHED.
*/
function sendResources(doc)
{
marketPlaceFId = getBuildingFieldId(BLD_Marketplace);
TS_message("Preparing to send resources");
reqUrl = "http://" + document.domain + "/build.php?id="+marketPlaceFId+"&" + getActiveVillageStr(document);
TS_getRequest(reqUrl,prepSendResrc);
return true;
}
function prepSendResrc(build_doc)
{
TS_debug("prepSendResrc: starting");
var tag,reqUrl,reqData;
var resourcesOnAttack = activeVilliage["res_amount"];
// var resourcesOnAttack = planResourcesAfter(tmToAttack);
var resourcesSafe = activeVilliage["crannys_capacity"];
var sentRes = Array(4);
var idVal;
var savePos;
var s1xPos,s1yPos;
savePos = getResourceSavePosition();
idVal = getFormHidVal(build_doc, 'id');
for (var i=0; i < 4; i++)
{
sentRes[i] = resourcesOnAttack[i] - resourcesSafe;
if (sentRes[i] < 0)
sentRes[i] = 0;
}
// For unknown purposes, a mouse position over button is sent with the form
s1xPos = Math.floor(46*Math.random())+1;
s1yPos = Math.floor(19*Math.random())+1;
TS_message("Res. "+sentRes+" to ("+savePos[0]+"|"+savePos[1]+").");
reqUrl = "http://" + document.domain + "/build.php";
reqData = "id="+idVal+"&r1="+sentRes[0]+"&r2="+sentRes[1]+"&r3="+sentRes[2]+"&r4="+sentRes[3]+"&dname=&x="+savePos[0]+"&y="+savePos[1]+"&s1.x="+s1xPos+"&s1.y="+s1yPos+"&s1=ok";
TS_postRequest(reqUrl,reqData,finishSendResrc);
}
function finishSendResrc(build_doc)
{
var tag,reqUrl,reqData;
var sentRes = Array(4);
var idVal,aVal,szVal,kidVal;
var s1xPos,s1yPos;
TS_debug("finishSendResrc: starting");
idVal = getFormHidVal(build_doc, 'id');
aVal = getFormHidVal(build_doc, 'a');
szVal = getFormHidVal(build_doc, 'sz');
kidVal = getFormHidVal(build_doc, 'kid');
sentRes[0] = getFormInpVal(build_doc,"r1");
sentRes[1] = getFormInpVal(build_doc,"r2");
sentRes[2] = getFormInpVal(build_doc,"r3");
sentRes[3] = getFormInpVal(build_doc,"r4");
// For unknown purposes, a mouse position over button is sent with the form
s1xPos = Math.floor(46*Math.random())+1;
s1yPos = Math.floor(19*Math.random())+1;
if ((kidVal == 0) || (aVal == 0) || (idVal == 0))
{
TS_message("Can't send resources - confirmation problem.");
}
reqUrl = "http://" + document.domain + "/build.php";
reqData = "id="+idVal+"&a="+aVal+"&sz="+szVal+"&kid="+kidVal+"&r1="+sentRes[0]+"&r2="+sentRes[1]+"&r3="+sentRes[2]+"&r4="+sentRes[3]+"&s1.x="+s1xPos+"&s1.y="+s1yPos+"&s1=ok";
TS_postRequest(reqUrl,reqData,function(response_doc)
{
TS_debug("finishSendResrc: done");
});
}
/*
* Checks if the player is in login screen.
* If so, and there's field for name and password, then 'clicks' login button.
*/
function loginCheck(doc)
{
var loginButton,passButton;
if (doc.getElementsByName("login"))
{
loginButton = find(".//input[@value='login']", XPFirst, doc);
passButton = find(".//input[@type='password' and contains(@value, '*')]", XPFirst, doc);
if((loginButton != null) && (passButton != null))
{
TS_debug("loginCheck: login screen detected");
loginButton.click();
} else
{
TS_debug("loginCheck: uncomplete login screen found");
}
} else
{
TS_debug("loginCheck: not in login screen");
}
}
/*
* Reloads the page.
* Any 'form' information are not submitted again.
*/
function refreshPage(pgmode)
{
var creqUrl,nreqUrl;
creqUrl = "http://www.google.com";
GM_xmlhttpRequest({
method: "GET",
url: creqUrl,
onload: function(responseDetails)
{
// this reloading method avoids the browser asking whether to submit form again
// remove trailing '#' or reload won't work
switch (pgmode)
{
case 1:
nreqUrl = "http://"+location.host+location.pathname;
break;
case 2:
nreqUrl = "http://"+location.host+"/dorf1.php";
if ((travActiveVilliage > 0) && (travActiveVilliageStr.length > 0))
{
nreqUrl += "?"+travActiveVilliageStr;
}
break;
case 0:
default:
nreqUrl = location.href;
while (nreqUrl.indexOf('#') > 0)
nreqUrl = nreqUrl.substring(0, nreqUrl.length - 1);
}
location.href = nreqUrl;
}
});
}
/*
* Add an event listener to start the main script function.
*/
if (window.addEventListener) {
window.addEventListener('load', functionMainTS, false);
} else {
window.attachEvent('onload', functionMainTS);
}
// End of script