There are 2 previous versions of this script.
the source is over 100KB, syntax highlighting in the browser is too slow
// ==UserScript==
// @name Travian ModKit 2.0
// @author Hikari (http://Hikari.ws)
// @version 1.00.03
// @description http://hikari.ws/dev/javascript/677/travian-modkit-20/
// @source http://userscripts.org/scripts/show/57667
// @license Creative Commons Attribution-Noncommercial-Share Alike 3.0
// @namespace travmodkit
// @include *travian*
// ==/UserScript==
/**
* The author of original Travian ModKit is IRoll11!~s from http://userscripts.org/users/IRoll11s
* Original code as fixed for Travian 3.5 by underke from http://userscripts.org/users/91268
*
* I, Hikari, rebuild the whole code, using some code and resources from original one and adding
* a lot of new features, with the help of underke to understand some parts
*
* Travian ModKit 2.0 is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0
* To view a copy of this license, please visit http://creativecommons.org/licenses/by-nc-sa/3.0/
*
/*****************************************************************************
*© Copyright Hikari (http://Hikari.ws), 2009
* If you want to redistribute this script, please leave a link to
* http://hikari.ws/dev/javascript/677/travian-modkit-20/
*
*Parts of this code are provided or based on ideas and/or code written by others
*Translations to different languages are provided by users of this script
*IMPORTANT CONTRIBUTIONS TO THIS SCRIPT (listed in alphabetical order):
* IRoll11!~s, underke
*Please send a message to the address specified on the page of the script, for credits
*
* Other contributors' (nick)names may be provided in the header of (or inside) the functions
* SPECIAL THANKS to all contributors and translators of this script !
*****************************************************************************/
//alert("begin ok");
//=================================
// global variables definitions
// villagesTableLeftCoord global variable stores villages table X coord, its default is for 1680x1050 monitor, change it as needed
var villagesTableLeftCoord = '1515px';
var debugMode=true;
var Prefs = '';
var vInfo = new VillagesData();
var core = new Core();
var getReferenceData = new GetReferenceData();
var getResourceInfo = new GetResourceInfo();
var showTotalProduction = new ShowTotalProduction();
var getBuildInfo = new GetBuildInfo();
var addListener = new AddListener();
var allVillagesEvents;
var showEvents = new ShowEvents();
var showCPSuggestions;
var createMenu = new CreateMenu();
var cps = new Array();
var cpSkipList = new CPSkipList();
// xLang is based on Travian Beyond code, it is used by CP Buildings Suggestions
// it is defined on the end of the fice
var xLang = new Array();
// images
var Xnull = "data:image/gif,GIF89a%0A%00%0A%00%E6R%00%07.f%F5%F6%F9%EF%F1%F5Zt%99)K%7F%0B2i%89%9C%B7%0B1i%0E4k%0A0i%09%2Fg%5Bu%9B%1DBy%138p%EE%F0%F4%0E3k%20Dx7Z%8E%03%2Bd%08.g%85%98%B4%138o'M%85%F8%FA%FB.S%89%5Bt%9ATr%9E%08%2Fg%B1%BC%CF%0E4l%3B_%94%3Fb%97%F7%F8%FA%19%3DrNo%9F%C2%CE%DD%0B1h%AC%BB%D2%080i3U%88%88%9E%BD%AC%B9%CC%C3%CE%DC%07-f'L%82%1DBw%BC%C8%D9%05-e%00%25_%24Hy%AD%BA%CD%0F5k%1A%3Ft%06.hCe%96%3Ea%95%116l'L%81%00'a%0A1i3W%8C%137nCd%952V%8C4Y%8F%0E3j%06-f%091h%18%3Ds%AB%B8%CC%B2%BD%D0Mn%9Dx%90%B2%07.g%0D3j%20E%7C%24Gy(L%81%03)c%1B%40wz%92%B3%5Ey%A1%FF%FF%FF%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00!%F9%04%01%00%00R%00%2C%00%00%00%00%0A%00%0A%00%00%07e%80R%20*(QGH.%0ER%17%25%1A%3E%1E%3FK%10%06%01%23%22%1F7%3CM-%07%3D)P%40%11%189O%1D%000%036%16%2C%0C%15%26%2B%13%1BL'4%0D%095%00%0A%3B%071%03%3A%00B%0AC%05%08%2F%0BEAN%24%05J3%09!2%01%148%12%0F%08ID%94R%02%1C%19%04%04%0BF%02R%81%00%3B";
var Xdone = "data:image/gif,GIF89a%0A%00%0A%00%E6W%00%DD%C5%24%D8%BB%06%D8%BC%07%FD%FB%EC%D8%BC%06%E5%D3Z%FE%FC%F5%F2%EB%B2%D9%BE%0F%FC%F6%CE%D7%BB%04%FD%F6%CB%FD%E6N%FE%E48%FA%EA%7F%D6%BA%03%FD%E7R%D8%BC%0A%D8%BB%04%DA%BE%12%F7%DD-%FE%FD%F5%D6%B9%00%D8%BB%03%F1%D5%1F%D9%BD%0E%E5%D3X%D8%BC%08%F2%E9%AA%FE%E47%D7%BA%07%E3%C6%07%E7%CE.%DD%C0%06%D7%BB%03%D9%BC%00%D7%BB%02%FE%E7I%FF%FE%F9%FB%E0*%D9%BB%00%DA%BF%12%E4%C8%0D%D9%BC%01%D7%B9%00%F2%E9%AE%D8%BD%09%FD%E47%F2%D6!%D9%BD%0B%EE%DF%7F%EE%E1%83%E6%C9%0D%F4%ED%B5%D5%B8%00%FD%FB%EB%DD%C5%23%F2%E9%AD%EA%D9j%DD%C1%05%ED%DF~%D8%BA%03%E5%D3%5B%F0%D4%1F%DD%C0%04%D8%BC%0E%E5%D3Y%FE%FD%F3%F7%E1N%F4%D9%25%F1%DB%3D%E2%C9)%D8%BD%0A%EF%D2%1B%DA%BD%03%E5%C9%12%DA%BC%01%E2%C9%1E%F7%DD%2B%FD%EF%8C%FC%E35%F0%D81%E5%CB%22%FD%E5%3C%FD%F3%AB%E7%CC%14%D8%BD%0B%FF%FF%FF%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00!%F9%04%01%00%00W%00%2C%00%00%00%00%0A%00%0A%00%00%07e%80W%15%09O%10D%3A5%03W%26T%0C%1D%2FQRG3%06%0B%25S%0DN%18M%1E%199%0E'P%14%3FU!%0F6%1AFE0I4%3B%23%22%178%20K*%1F%40L%12%04%02%00B(J%2B%0A%01%1BH%24%3E%1CA%16%BB.1%01%13-C2%08%2C%11V%3D)%3C%06W%03%07%05%00%00%05%077W%81%00%3B";
var Xon = "data:image/gif,GIF89a%0A%00%0A%00%E6%00%00%FF%FF%FF%F5%FA%F5%EF%F6%EF%13%87%13U%AAV%B1%D7%B1%01~%01%0A%82%0A%25%93%25%00%7B%00%02~%02%04~%04%2F%9C%2F%EE%F6%EE%10%85%10%04%84%04%02~%01.%A4.w%C2w%15%8F%156%AA6%AC%D5%AC%2B%A2%2B%0F%8A%0F%06%80%05%06%81%06%AB%D4%AB%06%80%07%10%84%10%07%81%09S%B6Su%BFu1%A11%83%C0%83W%AAW%3F%AF%3F%C0%E4%C0%01%7D%01%C3%E5%C3%19%8D%193%A93%1D%91%1D%04%7F%04%0B%81%0CV%AAWV%ABW%1E%8F%1E%86%CC%86%3C%A8%3C%F7%FB%F7%03~%03%0F%8C%0F%05%7F%06%06%7F%06%07%81%08P%AAP%86%C1%86%1B%8D%1B%13%91%13%07%80%08%1D%8F%1D%1F%99%1F%06%80%06%07%81%07%AB%D5%AB%00y%00%19%94%19%84%C1%84%26%9D%26%00%7D%00%01%7F%01%03%81%03%3C%AC%3C%1C%97%1C%02%81%02%F9%FC%F9%3C%AE%3C%AC%DC%AC.%A2.(%9B(I%B3I%BB%DF%BBM%B5M%0A%82%0B%0A%84%0A%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00!%F9%04%00%00%00%00%00%2C%00%00%00%00%0A%00%0A%00%00%07f%80%001%26%2F%1E7%1FQ%0D%00KMR%23H%20)9C%01%24PL%14NO'%19%1C%40%12%11(%16I%3AT%0AA%040D%3DB3G%062%0B%3C%0C%13%17%0FJ%06*5%1B.%04EF%10%0B4%3B%07%25-%1A%2B%09%3E%3F%1DS%18%03%15%01!%0E%096%07%0A%038%01%00%02%05%2C%08%08%22%05%02%00%81%00%3B";
var XonX = "data:image/gif,GIF89a%0A%00%0A%00%E6%00%00%00%00%00%FF%FF%FF%F5%FA%F5%EF%F6%EF%25%93%25U%AAV%B1%D7%B1%13%87%13%04~%04%0A%82%0A%00%7B%00%02~%02%04%7F%04%BB%DF%BB%2F%9C%2F%10%85%10%3C%A8%3CS%B6S%0A%82%0B%0A%84%0A%86%CC%86%07%81%09%06%7F%06%00y%00%06%80%07%AC%DC%AC%19%8D%19%06%81%06%1E%8F%1E%10%84%10V%ABW%86%C1%86%07%81%08%02~%01%AB%D4%AB%C0%E4%C0%AB%D5%AB%00%7D%00M%B5M%3F%AF%3Fw%C2w1%A11(%9B(%01%7F%01P%AAP%EE%F6%EE%1F%99%1F%03~%03%13%91%133%A936%AA6%04%84%04%1C%97%1C%05%7F%06%07%80%08%0B%81%0CV%AAW%84%C1%84%06%80%05u%BFu%3C%AE%3CW%AAW%06%80%06%1B%8D%1B%07%81%07%1D%8F%1D%01~%01%AC%D5%AC%0F%8A%0F%19%94%19%1D%91%1D%15%8F%15%83%C0%83%C3%E5%C3%3C%AC%3C%26%9D%26I%B3I.%A4.%F7%FB%F7%F9%FC%F9%01%7D%01.%A2.%2B%A2%2B%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00!%F9%04%00%00%00%00%00%2C%00%00%00%00%0A%00%0A%00%00%07e%80%01NI%14%11%2C%3B%0D-%01O%19%26'J)F%3F9%02%23L%3C2Q*%1A%1B%1D%24(M1R40%13%0B%17%05%10K.E%00%00B%2F%08A%0EGD3%AE%0C%16%18%1C%05%25%2B!%0856%09P%1E%227%0A%3E%40%15%12%3A%07C%02H%0F%0A%20%09%0B%07%1F%02%01%03%068%04%04%3D%06%03%01%81%00%3B";
var XRed = "data:image/gif,GIF89a%0A%00%0A%00%E6S%00%C4%04%04%FD%F5%F5%E5..%C8%15%15%FB%EF%EF%C4%01%01%C5%0D%0D%C4%06%06%D8ZZ%C2%00%00%EDJJ%D7%17%17%C4%07%07%D3%14%14%C6%0A%0A%D1((%F3%88%88%C6%02%02%C4%00%00%C3%02%02%E1%82%83%C5%09%09%EA%40%40%C5%07%07%CF%26%26%CC%22%22%DC%26%26%CF%1B%1B%D8Z%5B%E6%8A%8A%C4%08%08%EBNN%F9%C5%C5%F6%AC%AC%C6%0E%0E%D2%10%10%C5%08%08%C1%00%00%FE%F9%F9%EE%B1%B1%CA%05%05%CB%09%09%EC%AB%AC%EDSS%ECyy%DA%1F%1F%E4nn%C9%02%02%EC%AE%AE%EE%B2%B2%CC%04%04%C5%0B%0B%EA%3C%3C%E9%3A%3A%FC%EF%EF%D8%1D%1D%DA%2C%2C%D7UU%C4%05%05%CB%20%20%D1%18%18%D0%1A%1A%C5%06%06%C5%01%01%C5%0A%0A%C3%01%01%C4%03%03%C4%02%02%EF%B3%B3%E877%E8AA%E2..%C3%06%06%D7%25%25%ECMM%FA%C3%C3%D2%0D%0D%EC%AC%AC%FD%F6%F6%D6YY%CC!%22%E7%2C%2C%E3%89%89%FF%FF%FF%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00!%F9%04%01%00%00S%00%2C%00%00%00%00%0A%00%0A%00%00%07f%80SN%20%10%2B%1F.D6S%26!J%164%02%3D%0F%1D%01K%0A5EGI%1BH%06M%2CQ%02%027%3C)C%259F%1A-%0BL(%05B%00%3B8%0D%232%2F%05%00%3E%17PO%12%3F%11%00%07%1E%0EA%1C*%06%09%07%0C%153%3A%030%01%14%22%09%24%40%13%03R%01S%04'%08%19%18%081%04S%81%00%3B";
var Xarrow = "data:image/gif,GIF89a%07%00%0A%00%D5%00%00%FF%FF%FFG%3E%3ERIIC99E%3C%3C%3E55JBB%F4%F4%F4%F4%F3%F3%BE%BA%BA%FB%FB%FBB88%84~~g__ULL%E7%E6%E6%B5%B2%B2%FD%FD%FDMDDvppC%3A%3AF%3D%3D%DE%DC%DC%4066G%3D%3DaYYKBB%97%92%92%C9%C8%C8%E6%E5%E5%BC%B8%B8%A2%9D%9Dyrr%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00!%F9%04%00%00%00%00%00%2C%00%00%00%00%07%00%0A%00%00%060%40%80p%08%98p%0ED%03%05%F4%88%08%05%95%81a%D3%01%08%02%01%C2%C5%01%B9%060%8B%02%E3J%18d%3C%0AIA%93%40%08%1B%1F%0Bq.%0C%02%00%3B";
var XarrowUp = "data:image/gif,R0lGODlhCwAHAPcAAP///0c+PlJJSUM5OUU8PD41NUpCQvT09PTz8766uvv7+0I4OIR+fmdfX1VMTOfm5rWysv39/U1ERHZwcEM6OkY9Pd7c3EA2Nkc9PWFZWUtCQpeSksnIyObl5by4uKKdnXlycgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAACwAHAAAIPwABCBQIgYGCgQg7OCjgAaHACBsuLMiAwOEDAwQwDEiA8ACIAQECENBgYSAHChVCBijwYeAEAwJiCpDQAEBAAAA7";
var Xg0 = "data:image/gif,GIF89a%2F%00%3F%00%B3%00%00%19%16%0D%FB%F4%C9%9E%9D%7F%CF%CB%AA%83%84m%DB%F5%FD%FA%FA%E3%E3%EE%D1%CC%D4%C3fdR%AE%AE%94%C0%BF%A4GC0%A8%B8%B9%CE%E6%F7%E2%E3%C4!%F9%04%00%00%00%00%00%2C%00%00%00%00%2F%00%3F%00%00%04%FF%90%9D9%CD%23H%09%13%BA%7F%09!2D%970%1A%C1%00%8Ca%01%40%E2%22%0C%93TK%96%08G%C0%05%0FO%87%90(%92%024%80F%A1H%00z%83gb!%C0%3CxD%81f%23%F4u%2F%A7%C4c%E1D%09%B4E%97%80%81%98%0A%06%88%C1%E0%BA%F0%BA%82%1D%7C7px%0CB%08%04J%5BE%08%02%2C%22D*%04%03%5Ez%7B%90%01%03%3C%08%07%06%0B%88%0A%0B%2B0%83%18%0A%93%0Fx%8F%91%5D%07%3B%14%96%2B6N1dl%06%07%04%06%08%08%3F%A5%90%1A%0F%A9%13%0E6%0A*Jj%12T%8C6g%7B%A4x%0B%A7%3C%BC%7D%00%04K%00%0B.%0Dl%22U%06%0A5%90ck%99%04%3D%7D%CF%07%00gZ%D1%96%022%02%08%D5%07%0CU%5DU%ABD06%CC%BC%BB%07%08%D1L%87f%19(%82I%01%ADh%EC%3C%18%88%02C%DA%82%05%03%80%C1%A8Dn%02%3Fyg%14%9C%8Bu.%83%80%071%FF%0E%B0%D3%A3%B1F'y'%60l%B0H%B1%D6%0Et%1B%0550%10L%DC%95)%1EFV%E9%C4%A2%01%26%19%7D%1E%D4%82%B3i%07%95%1A%9C0%C0P%D0o%80%08%05%1E%88%3C%94%E3%C4%9D%8F%15%8Cj1ar%AD%A1%A0%18%06%0E%ADp'g%00F%0FE%06%2C%00u%82%C3%01L%8A%D6n%91%88%CF%89%8C%00%0DXhy(%60%93%08%20%01lD%84%D8%F6%C1%25%00%B6%E2l9S%A3A%93%15%D5%0E%13%C88%D9A%B4%12%1DH%C8yh%C3B%00L%8D.%60%04%C7%C0%B0F%00%A2D%FD%AB%22%C0A%81%CB%1E%1A%82%FA3%CB%07%E8%0E%11%D9%7D%8D%91%12%B5%0B%8DU%084pmy%CD%94%92%0D%C9%18%3C%C0%0D5%10%3F%0B%26%2B!%C2%F4%1A%01%A15D4(%C0%FD%F5%BD%86%11W%9D%23%93%3C%CF%F3%82%93BX%A8%A9%A0%01%82%02%AE%B9%B38%81%B4%06%FD%22!B%B0%0A%A2%C7%A8Z%15%06%BD%B2%1D%FF%7C%DD%BD%96%1F~%F5%25%D8I%11%98y%20%0F0%9A%90%91%80-*%08P%20w%BF%A0%A3%E1%86U%EC%A0%DF-%0F%A0%90H_N%C9CK!%DD9%F0%CAe%22%E0%87%60J%F6%85%80G%19%2C%20%02%D1%1FS%9CH%80%03%AE%FD1%96%10D%D8%97%C7%7C%B3%B0%B3%06%09'h%A2%C2%2F%93%1CQ%C0%1AJ%D1%07%C2%25%3BpS%83%0B*L%A1%02%02!*qB%03%D2%D4%13%C6%1B'T%23%1A%11meiKQ2%FC4Ex%E2h4%99tZ%B0%A1%03%03k%A18%13%7D%16p%A9%89Xl4%E7%10a%0C%CC%01%60%02%06%B1S%83%16%B4%95X%1B%9F%7D%240%D3n-%80%C4H%84M%16%89h%90%D2d)RZ%12%3EV%DA%40%1B%0C%14%02b%071R%96Z%DC%DC%00%02%01%0B40!%0D%8A%86%85%A8S%F4%8D%AA%00%974%E5%17%8B%3Fh2%F8F%89%03%F4%FA%9D%04%17%B8%03%60%B1H%F9%40%84%FFa%FA%01%05W%08-%DA%00%2B7%B3%B4%E1F%11%60%1E%B3%89AH%A5%F6F%60%C6%DD%11%CD%3B%0D%A4%0Bf%85%3EN%EAa1%EFl%80%ADI%16p%10%0B%09%9D%25q%ADc%02%A8%DB%AAS%60%91%C1)%06R%AD%B2B%99%5C%C6%03%E5!%E7%A0%D3%9Ec%EA%CAz%5C%0D%95%C4%20%C8%819%1C)O%22.p%92It%FC%BA%17q%BA*%3Ct%C2%1A%D5%E4U%0D%AC%1D_y%ED%05%D14%16%08%11%3C%D6%8C%00%C4%EA.%DB%84W%1D-b%80Ic%C8%02C%03%7D%C0%91B%02%DC%11%C7%E3%C8%DD%3ED%9EI%D1%E1i%0B%BD%25%7D%24%14%AB%EF%EDx!%7C7%8F%5C%B2%1CY%BA%A2%89A%16c%C5%A5%1F%11!%EA%1A%03%5B'%5D%CB%C8%F2%A8%85%89%7D%BB%C2%20K%18%13%40%14%A1p%3C%16%C06%01%5B%DB%1C%F1%1AJ%FE%FD%D1%09%99Vc%C8%1B~%B4%D6%B7%2F*%14%18%1F%7CL%EFP%22MK%1AF%8D%FF(ji%81%40%DF%F0%D5%CCZ%E0n%3B%D0u%C9D%0C%14%12%10%5C%82%1D%C2%02%F1%D5%5Cs%DBI'%BDt%D7x%A6q%04%60h%B3%F6y%E8%B2%138y%DB%B2%AB%AB%9F8%85%DE%22%87%06%EF%01%3F%3B%ED%A4%DB%DC%17%BE%0A%84%F8H%15%ED%C9%FE%3C%F4%17%C6%CE%A3!'%A80Fi%40%0E%A7%FD%F0%DC%A7%98%A2%E93%DB%C0%C6%1A%8F(%0Dz%FA%F4%3F%C0%04%E0_%D9%20D%10%A1%D3O%3Fq%E0s%C6%3Bb%60%98.p%CF%05%B6%A3%DF%CD%F6%C2%8FX%AC%25%16%06%AC%1D%F1%E6G%BB~%00%C3%19%E5p%8A%00%3E%80%BE%02%18%C0%83%C0%E3%5E%11%82%A3%89%7DP%C0~%A0%F8H%00%B6%F6%C1%DAu%B0%3BaP%82%3BxQ%8B%B3Q%80J%06%B9P%0B%B5%B7%B5%E3%05cB'L%85P(B%81%0C(%A0%3B-t%5E%DBh%B0%24%064%C083%E1%87%10%CB%F1%0E%10%DA%8E%82%F1%A9E%3DxS%06'x%92C%8A%E5%90%E2%15%B7%D7%9D6%D4%C0%01%B2%B2%D6*%F0%F3%0C~%B81%15%3C%94%5Cw%60%80%20%1B%98%B1%06%1A(%0D%18%CB%01G%0A%B6-%1A%D4%1A%C1%A2.%16%BE%8ALq%1F%F3Kb%8A%EAa%9F%EC%7C%C9C%2C%F0%22%0D%17%B0%C7%03%80%10%81%92%ABE%B5%843%96E!%C5b6%F9b%0D%F5qC%2Bv%E7%00%E9%E2L%90%60d%04%24%8D%A5%0D%7B%E4%07%11'%10%01%00%3B";
var Xg1 = "data:image/gif,GIF89a%2F%00%3F%00%B3%00%00x%AA%3E%F9%F8%C9%94%CFK%D9%E6%C8Is%1D6Z%11%9F%A7%8A%60%863%16.%06%BF%CD%A8%89%60%1Bfo%AA%7C%84b-D%105%3ClR%604!%F9%04%00%00%00%00%00%2C%00%00%00%00%2F%00%3F%00%00%04%FFPI9F%08%CC%06k%A6W%CD%C3%18%86e%26Y%B5UCb0%DE%C3%0E%C6u6%D3%A30L%92%5C%AB%84%25%F1%B0%B16%24%18(%F4%5B%D14%06%9FP%B5%09%F8%9C%1CY%25%B3%1A%F1%24%A5%20%23%D4c%3C%1E%B5j%EB2Ro%1E%0E%5BC%95%2Ci%A8%8CC%01%40h%1C%08gBl%0C%17%0Bi3%0DsV%08C(a%2B%5D%0D%00%93%05%07%93%00%05%22%16%0B%84%03%0D%0E%15%82%9E%0D%19%06%0DB5%23-w-%0F%04%97%B0%972%01g%1B%89%15%0E%3F%06%08%0D%8C%A6%255%03%0FD4%0E)%0C%B1%B1%07s%03%99-%BDQ%08%3F%0C%08%05%08%22!%03%5C-%80%C3%1Ay%C9%B02%09%BC%DA%BC%0F%CB5%D6%89%08%D5%0D%01%2Fl%7Fh%2F%CB%96%93%96%AF%94%84%0C%05%0D%06%0F%D8U%EB%C1%CB_%AF%3E5H%60%00%A0'%0A%BA%7B%94zY%D2C(%11%01%5E%0D%D6%CDs%D7%AB%80G%04%09%FF%851D%87%02%22%AC%89%7D2d%F4W%B0%9A%1E%8E%1D%09%F4)be%0FE%0C%95%18bZVi%D9%B8%95%EDx!%90%B9.cA%02%1E%1B%2C%D0%26%E9%E6%86%03.1%06%CC%E6%A9%80L%81%0Dd%22%C5X%ADO%D6%5E%092%1E8p%26%8AC%11Jx%A8%08k%D5%DF%C7JH%2F%F6%1A*w%EB%83%B6%01%85%3A%B0c%E5%13%8F1%242%12%DD*S%8F%CC%A0I%ABYC%F0gn%08%AF%3Fh%DC%FDz%C0A%A2%B6D%ADj%D5%DA%CE%EA%C1DY%E7%11%18K%14%CD%5D%01%02%00%A4%C6%D4%15s%D7%3FZ%AD%11%EDu9%ABV%D8%A3%2F%1E%40%CD%FB%D2E%C5%9E%BB%C6%5Efq%5DA%DB%B0%FFlT%DD%5BV%88%80g%EE%BA%3AL%40%C0%E8v%97y!%0D%1D%82tc%E6%BC%F5d%E2q%08%C5%19%7D%BBQ%03%A0%1D%B3%A8%F6%D1d%11%80%9F%14%3D%0D%90%FB%06%C82%40%3D%96%3F%BB%B8%D6%D8%04%D7%FF%03%ED%A47%DA%19%5C%DC%A7%A0%15f%B4%25%DFz%B4%B9uQu%17e%D2Y%5C%DD%24%B8%A0%82%DA%044V%01%02%B0d%94U%0F6%E6%D1XzH%12%C8%86%2C%12%F1%00C%08%84%88%5DF%2B%5D%02%D5%1E%93%A46%16%1A%2C%F6H%84%25%7B%B0%E3Qf%BEeb%23Cc%F5%A8%A4%02%1F%CA%98%95GC%DA%A8%C7%3D)%8A%A0d%8F%F9%01%E0JGm%7D%24%25%8E%E24q%E5%82Dh%89%DDl%A9%95%88TN%E2h0%A6%82D%D0%D6N%5CCQ%C2%D35H%5D%92%C9%9B%2C%DE%15%94%3BV%F1%E6N%8E%EBU%92%C90%7Cr%F8%40%9A%D8Y%93%9E%001%CE%C7PV%7C%88%99%A8%15%8BZ%C7%CB%8E9%09%D0%40o%EA%AD%A7%DA%01%F6%5Dj%06suN%E2%07Q%EA%05%AA%E3D%07%5C%0A%C4%18%A8%F9%01%E6%1E!%EE%86%E4h%7C%F4%A7e%A9o%02%84%CEh%D6M%12%97%00%E91%87%0Ffc%F5%90h%FF%9CI%A1F%94%7C%BCU%BB%EC%2B%CA%E9%E7%A6%92((%40%A0a!N%05js%80(%A3%A5%02%96nh%1Et%5D%3D%87B%22zT%3BS2%D6%B8B*%96dEG%E9z%08dp%06)%E8%2C%BB%AF%8D%F0%F1%A0C%0F'%C0p%06l%DA%8DD%8D%B02%10h%11%1F%60%E2%23%09%C1%F9Fw%E8C%17%05%FC%CF%00%BC%00%E6%22%92%C6%CAdc%C5%BC%E2C%96%AD%7D%5C%F7%22%00%D7%8C%81%80%03%20%11%A8%8F%8D%8A%E5S%B12S%19iU%40%99%10%A7%F05%961p3%3E%2F%F6%F1!D%C9%F5%23VO%86JL%CA'8x%0B%92'%E1PR%F1%90%83%F9alcwY%03F%40%12P%83.9T%C2%82%2C%98%D8%EAy%10%3E%98%24b%A6%B7.%80%20%C10%3Ex%DD%F2%D1l%A6%3Ci%D0%B0X%88%24%18B%E8%B0C%0B%09%1C%89%14DV%E1%93r%8AG%97%8C4%1A-(%81w%E2%CA%98%04%E6%FFX%A0e%E2%D1I'%E3%80%B0%C2%19%F8p%12n%0CU%92Zu%3AY%92Z%E3%A9%A3%F7o%01%3E%C0%90%8D%E9%8EK8%1A%8D6%2B%7B%F2%CD9%7D%C8D%B7%A4%AC%A2%B2Uc%AD%C7.%81%AE%F2%84%92o%AB%06%22D%B7%87W%B0%AB%DF%A3%D9%F4%C7%18%AAIn%B2%94%7F%D0.%85%E1)%24%90%5BF%99%AB%2C%5Es0%1A%E98YR%8Cq7%0D%EE0%E6%16%2C%DF%93V%5D%B5%CB%D4%D9Sn%3D%A8%DD%0B%A6%F7%AF%3F%F4%8AM%A4%F9%1Fcz%B38%5E%E9%06l%AB0%C1%10%3Ea%12%E2%9C%A40%C7%B2%8EW%08%D6%8Dk%CC%60%06(p%C0%02t%B2%AC%9D%A9%ECb%9FK%9E%D6%A0%82%14o%84%C2%0C4%13%E1%02%16%87%8Fk%84%23%7B(%BA%A1%60%F0A%9EO8%E0%87%0B%10a~%A6%04!%AF%1D%A91%AF3%D7%A4xU%80%05%04Q%86Ntb%09%F4%94%40%CD%B0%0EE%AFx%DD%FF%FA%C6%18%B2%208%11%88%0B%F0%C6%050%F7%3E%A8%D4%88%0F%87%E1O%EA%D0G)%AD%60b%04S%B0B%EDF%10%01%00%3B";
var Xg4 = "data:image/gif,GIF89a%2F%00%3F%00%B3%00%00%F1%F5%D3%E7%98Z%8EP%0E%FA%EB%8D%3F!%0B%B6%8BQ%9D%A0x%D2%DF%BF%E7%BB_JT%83%8EyD%99%A0%E7%C9j%14rZ0%B9%BF%9Eov%BA!%F9%04%00%00%00%00%00%2C%00%00%00%00%2F%00%3F%00%00%04%FFp%18%A3*%ADV%CD%8CkQ%85%11~%88%81%0Ch%AAJ%A0%88Q%8D%F6*%F1L%15%DF-%2B%E7%9A%82-YcB!%3A%1C%86%A3%82%D0%18%C6%8A2%5C%CE%E4%03~%5E%C9%A3%E3%C0%EDj%89%3B%DD%C8%A5%E9%A1d%97%EC%B6%CBn%7B'%CE4%D03%E9%01'%C76%60%CF%EF%1F%00l%0Eh%19W%1E%16!%1A%06l~%7F%80%7C%07H%5B%7BoI%83%2F%1F%05CI%5D%80%7F%8D%93%5C%06MM%04%0E%8E%9DZh5s%14y%5C%7D%A8%174%02%0A%02%0C%0C%0D%A6%B0%5CG%1BO%87%15%AF~%0D%09%A3%02%C7%B7%C7%B6%B4%0D%BCy%93%B1%1B%1D%0A%8E%C2K%0D%B7%C9%B4%CB%CB%0C%04%0F%0B%09%E2%04%E2%0A%09%1A%BC%D2%18%D0%7B%0B%04%08%05%CA%DB%C81%CB%0D%E0%E2%0F%09%04%FC%E2%E3%5Dph%C0r%C0%04%01%82%06%CAj-S%C8%C0V%B3G%E9%16%3C%D0%97%A0%13%A4%23%09%8E%2CpP%CC%20%82Z%08%FF%132%A8%D5p%24%ADH%00%264%92(%0E%E2%1E%7F%E3%02xD%90pa%B2%0A%B6%08%80%F8%20%A0%C9%16%03%E0%C8%AD%E9%A2o%22%81%023i*%E4Fk%24%81%9E%B6%02%04X%A6S%01Gp%14a2%F9%40%40%A6L%83%F1%14%8C4%26%80%DF%BB%06R%03%94%2C%8B%C1A%D6%AC%09%0A%A4%05%A2%D3%E3%D3%06f%F1%06%C0%DB%E0%A3%DC%A9%D9%CAf2%00hB%82%07%13%1EH%ADu%14%AF%00%B08%CC%9A%3D%C8d%80%00%B9%24%93%F1%0BP%0A%16%9F%00%05%9E%5E%BE%E6Q%01%E7%C9%04D%C4%98*%D5V%E0%86RDh%894%F5i%D5%BA%F0%22%F3%C3%FB%EE%04%CD%9E%8E%B5!K%2B%15%93%87%BD%F5%96%3CF%A0%16%C1d%03G%CB%22%2C%19O%DE-%E2%D8%8B%13%07%DE%00%E9G%E8%FC%80%2BW%88%16%BB%DC%BF%D9%D3%A2%07%0DO%A1%07%B3%0E%0EJ1Oc%D4(%1C%E9%F3%17%97%97%17avQOH%02%00%FF%12M%80%20%15l%FA1%80%DD%12G%C9G%5C%26V%C12%00%1F%82%D4%D0%DD1%FAa%C7%1BN%0Fv%F7%09%00%13%EE%02aq%E5eH%A2N%990p%DE%10%8D%84%C8G%88%13%1E%40%83%14%F1%98(%CFe%99%D8%93%CB%1E.%BA%B8K%05*%C6%B3%5Eu%CAd%D3Pc%AE%0D%C1%A3g%13%C2%B8%87%03%DD%15%B7%5E%91F%26%83T%3C%0DQ%E3%23%88%12%C2%12ezU%BE%C6%0FN%0D%11%B6%A4%8F%5Br)JzX%26sdx%3C%84%D6%13%02%5CvYg%9D%03%1CP%E2%83%E1%95%D5%A7%9F1%DC%F5a%9AK%F61%C0%9E%C4yc%D6%8D%C70%07%1C%A1N%1A%CAGy%F8%11%C7%98m%FC%5D%26(%97%91%F6(%E9%9E%EB%A9%17%8Fh%FC%C8%C5%17%9D%9E%A5z'%94%26%AA'%D9%AB1H%DA%E5%96%1F%80%C9%A6%9F%AF2Q%E8%99%B3%02P%01%9B%26Vw%97%92%2F29%D0%97l%86%9A%DD_%C1%DC%E9l%FF%9Dz%22%DA%AA~%99%14%80%E6%AE%3C%D2%60%E0%B4%AD%0E%06)%972%C6%A0%A0v%A0%E5G%23%0E*%9A%F7%04%A1%03j%BB%60!%E7a%A7%60%01A*%FBA%801%12%D8%84%B2%D5x%E2%40%A5%A2%8E%DA%D5%B28%D9W%60~%1F6r%40~k%09%C0mu%CA%06PM%1F%BF%9A%87%0C%5B%0F3%7CJ%23%ACfWRC%18r%CB%265%1B%03%22-%60%C2%95*%B2y~%F0%F1%40%81-%B4%A9%CDn%2Bcw%0A%3B%80%20%F1%076U%22C%C0%B85%07p%C0%02%9E%E0%CC%87%01%AE%85yLW%00s%FB%A4%C2%9D8%E2%40%D2a%DE%A2%13%80%D3J%A1%EA%23%82T%7D%23%3A%82%B4%DA%C1.%8FL%22%8AX%20%ABX%B0%22%5Clk%DE%15I(Bv%D9o%CC%B6H%D4n%17W%C1P%5BO%5C%B6gP%1F%DD%C4-W%E8%D2%F2%D6D%B7%1C8%D4%0A%23a%C09%86%17%DD%F7%93%25O%2C%B9%AA%9F0.L%1F%DF%89%F7%5D%F4%2B%97%07%3E9%E07%83n9%E9%93%ACq%F3%E8%A0l%FE%E1%E1%9F%EB%01%40%04%00%3B";
var Xg2 = "data:image/gif,GIF89a%2F%00%3F%00%B3%00%00%FE%FE%FE%23%3E%10%9D%A2%A3%FD%F8%C2%D6%DF%B0%CD%D2%D7%D7%DB%E3%3Ei%11%B0%B3%B9%8A%8F%8CX%5DY%E5%E9%ED%B8%C0%99%BF%C3%C9%E5%EE%D3szs!%F9%04%00%00%00%00%00%2C%00%00%00%00%2F%00%3F%00%00%04%FF%F0%C8%13%AA%0C%13'%C0%81r%5D(%8Ed%86a%13Um%5C%11%14d%2C%03We%A5(%0B%08%01%D3-%82%C5Lf%BA%14)B%DAA%F7H(%0C%C9a%A8F%AD%06%0C%80%82D!4%24%0A%0A%81tdEQ2%20%C1E%9C%40%14%9C%D11%C0%96%CA%D4%15%CA%09%E2%E1%15%3C%F0r%1Ct8*F%01%0Fv%2F%40%0F%02%0A%0D%81%00%0F%888%83T%09%13%7F%0B%0B%7B%7B0%81%97f%85G7%14%08%9A%0D%09%09%8C%90%A4Gug%07%88%05%9A%5EN%01%08%9Ft%16%AD%86fP%9A%02%7B%0A%0F%81%93('%A1f7%C4%B4%0D%05%8C%5Cr%B1%B0E%15%0A%CA%18%A6%B4%06%B5%0Fq3%12%0F%A15%8E%CF%C8%87%9A%E9%0D%06%02pr%93F%26A%0D%08%D76%08P%BF%EB%08%8D%815%AD%01%B8%BC%F1c%E3%09%B7_%05%F6y%7Bw%E6D%06%01%DC%F6%F0%A0%10dA%01%7Dn%F6%3C%1A%C3%2BC%03Mo%FF%10%D8h%82%EF%E26%04%09%C4p%ECx%E0%C9%02%03%09%EB)%90%F9%E0%E2An%0D%FC%C8%A9%94!%C1%CB%97%A8%04%5C%94%E8%86%5B%81%8B%09%89%8D%11g%A3i%00%88%10%8F%B6%B18%B0%E8M%03%0D%94J%91%A4%E0%DA5I_%5E%C2l%B0%0E%E6%A6%07%08%CA%3A%C1g%A0I%B4%19b%1C%A4j%E7%20%EB%D1%83%1F%C5%0EE%80%2F%AB%93%8F%22%D1%0E%09%E3%A0%B0%03%02%87%7D%E2%FBi%F1*%BDg%09%82rK%A95%86%9F%26%AA%1E0%40k%60q%BE%C66%B1%D6%23%9Bsl%A3o%22%140%20%C0%60%F5%00%02%DE%C4%DE%0C%3D%B9%09%DA%B4lQ)%F0%14c%F30F%0C%DA%CC%A2j%F1%8FO(%0D%BA%06%7C%40%F6%CBQ%3F%3AH8%18p%98%BA%9F%C67%DB%25o%E7'-%D7%20%FC%16%D0%DB3%C3%B0a%E6%DBp%CE%7C%13%B0%02sz%92%B0%AEK%A8%AA%BC%F9g%B4%C5%87%C9%D9%F5%0F*%DC%8D%945T%FF%7D2%98%B7%03Dfe5LZ%0B8%91%09%3F%05%08%D0NIF5Q%DE%02%048S%13%5E%8C%A8RTf%3E%DD%85%9BUdI%12D%0C%0E%3CsM%10w%05%C3M0%FCt%25%E30)%F1%E3%CCE%1A%AA%06%82ta%5C%87%14%3D%07%F9A%A3%1B%87%B1%F6%07%23%19%B5AOW%3E%90%D0%0E%10%02%16%E0%C6%3A%9710%C0%95Xb%E9%5B%020EF%96%8C%04%90%C0%07%3F%B3%D9%D4H%02%04d%A9%E6%95%048%81%60L%8C%B4%89%1A%97%ED%5C%15%91%02h%AE%A9g%9B%1Dz%99%C0!%0C%14%B0c%07%10%E54%DCMM%A4%A9%E7%9EM%00IO%23%AA%250(%00%A6D%F8%CBA%F5X%B9%E8%A2%0C%A8%26%803%7C5%D2Z%93Y%7C%84J%3E%07%A92%DD%A6%8B2%E2b%84%999%C0%C0%23%0DB%81R%3AG-%A0%19%AB%9Bn%26%DB%1E%AA%10%00%1B%03%B5%C2%A4%0DV%82%AA%C6%2B%A7%5Cp%A8%CA%FFj%AC%ED%91N%17Xi%A2%C0%B2%9B~%F0%92T%8D%08%BBY%7C%D3%8E%B5%80%03%D7b%AB%A7%B68%A5t%00%B4%0C%04%C0ez%DC%BC%A4%80%A2%E6bI%C0n%DB%8Aw%99%B0%7F%F2%A1%D7l%CA%D6%AB%E5n%07%1D%C5%CF%01%02%B4%2B%01%AA%B4%B5%25%80%C0X%AA%82%23%14p%0Es%02%C3W%A9%02%F1%95%92%E4%0A%13N%F5%DC%60%D4%5D%05w%AAi%BDjD%F51L%09M%B4%F0UwI%D9%15%BD%CB%F2Y%94M%5D%7D*%CE%04%CE%18%15%AFhg%D2%BC%A9%03%7F%F0e%D4%22%0E*%90Ah%B3%7C%9C%10%3B%89%F2J%40%23B%B1%C5M%A3%7F%86%C22RN%24%B4%CE%22%9A%09%AD%E5%1F%81v%C5%25L%12B%83%C3x%25%FE%F6%E7%BB%C1%D1%E8%1AkBj%06F%1BaXDO*%7F%A6pd%8C%7C%05%E4%87I%60%0C3%A3%DC%B3%98%D8%9F%B1%25%8Ad%C60B%CD%84%CA-%C9%DD%84g%3B%05%10p%F4%97K%7Btf%F8%C49%A9%7B%82%B0S%7B%A3%9Bw%95%B6%95%0A%1F%2BK%F8F%88%5C%B1%C5yZ%3C%04%E4-%C1%BA%D5%C4H%3E%26~%91%AA%8C%1BF(%89g%8C%F3%C7%C0%01%C3%D2%92JZN%40%F1%87%8C%C7u'L%3E%7Bp%06RR%B6M%EDk%3A(%C5%D4%23s%B6%F0%91%15i%92%A8%A3JEF9%F1%15%03DW%04%94Pd%F1%B0%DB%97%01%E1F%95%60%9C%DB%F6%13L%B7%0D%D3ZM%E9%18%0B%5E%CA%C1%88%23%7D%CD%00u%F1%C6%C7P%A1%8Am%B1%8C%1Fd%8B%00%00%3B";
var Xg3 = "data:image/gif,GIF89a%2F%00%3F%00%B3%00%00%FD%ED%8B%FD%F9%C2%E4%D6%7F%A8%9BW%F4%E7%9DS%3D%12%C9%B3_xe-%F1%E1%83%CC%DA%AF%A9%AE%7F%DC%C8p%B6%C5%9C%E0%ED%CF%8F%83I%C5%C0%85!%F9%04%00%00%00%00%00%2C%00%00%00%00%2F%00%3F%00%00%04%FF%B0%B1F%93M%8C%BD%E1%FA8%07%93Pd%83)%0E%CA%7D%DD%E1%1C%DF%A1%1CRP%DE%26%A3(%838%8E7K%26%93%F28%06%ACO%C3%05%C4%05%2F%D0f%053%CC%CCV%83%99m%D7P4%BF%89%DDQ%E3%B5%3C%2C%26%92%90*F%CD%12%01%5BW%A7%A8%3C%18%03%82%80%80%40%00%04%02%00%08%02Y%0AC%86%88%3B%18P%192pq%01a%3B%0B%0B%00%96~%96%99%9A%99%02%08%0B%04%0F%80%0F%1B)R%5D%0E%3A%22%A1%7C%9B%AD%AE%9B%98%96z%3Ca%3A%25%09%0F%04%99%B1%AF%BA%AE%BC%9B%01%3B%1Cu%24%0C%82%AF%BB%C9%C8%9A%C0%08%04%03%15%12%0A%C0%CB%9A%9D%BE%D6%9A%0B)u%0F%06%DA%AF%06%06%9D%E1%99%04%5E%0D%04%AC%D5%C9%BA%04%0B%7B%EB%F3%E1%0B%18%E6%00%F3%FA%FB%FC%D6%08(%EDd%F1%1BHP%19%2CK%0F%1C%1C%CC%F7%8E%A0%C3u%98%0C%0C%08%E4%8A%D2%9Fj%0F3%0A%0A%00%00I%C0A%D0%FF%02%F1%12%60%60%C1%B3%8C%EBz%25C%40%CE%405%03%A3%1E%F6%E9%23(%E0%2B%04%03%FE%B4Z%A0%40%1E%C1%04z%F8%CC%B4%D9%0C%40%00%8A%CCj~%9A'o%03%88%A7.%1C%18%E0%D3%89W%ACX%84z%3D%93'%20%A1%0BC%C6P%B8xP%93%A8%25%A4%CDf%EE%110%23%05%A4%B76%BCN%BCH3)%A6jC%B1%7D%18%F0%08.%24%13%7B%FB%88%1CJ%B8%DDP%02%06%3A4%F0%CB%B8A%07j%85%23%AF%EC%F3b1%E3%C6%1D%3Ai%8E%5Cn%D9%83%10%97C%7FVPv%90%E9%AAu%05%98%DC%C4!th%C7%A4%FDD%9Ey%B6C%A5%5Dn%5D_%06xi%F6%5Dr%AD%0E%3C%D0%7D9%C1%81%DE%85%AB%22%C3%F4.%1F%0D%E2%8C%09%1C%F0%A5%D6%B4%E9M)%E7%1D%80%DE%F88r%C9%07%B5%F7%E5%1EG%FA%D5%D9*%A5%8F'%CF%C0%7BRm4)%2B%20%FF%16%85.%C3%BF%04%0F%FA%40%1F%D2%11%7C%DF%F5%01%0A%FFh%F4%CD%90%CB%25%00%9ED%40%02%1D%AC%E7%1A%83%D3%01%88%1D%20%03F%E3%1A%01q0X%40%01%F3%F9%E3%0Ab%DF%00r%C5p%AE%25T%00%08%05%F8%91%0D%2C%B7%ED%E2%C9%00%E3%98%04%0D%0C%0FX%E6%D7%0CP%15%A0%D0%8A%08%EA%04%0B%3C%A8%F5%C1%C0%0B4%C2%01%CA%07'B%E5%40%01-%86%23%5Ba%82H%E7%C2%01I%26%09U%8EdI(%CED%25%09%B0!THZY%00ZZnB%C9%02%25%19%20%E6%86%2F%B4%09NQeZ%82%26%95%0E%A0%F9%A5%0B0%C6(%91%8F%AD%98%B5%93%9A%1B%26%96g%8C%03l8'%12%9D%5D%E3%A4j%12%15j%A8T%0B%7C%C9%CD%860%9E%88%E8%2F%DA%90D%24%8A%05HT%D2%97%E3%B0%F9%02%12%03%B4C%A6%2B%24%C1%04%A3%A3%E3%1CA%E7%11c%B2T%89Mu%F2%08%CB%20%F1%C4%23%C0%A80H%14%15%0Ch%D9j%C9%01%06%04%40%94leI%A4Z%3E%0B%20%01%A6%AEA%ADdv%9BM%C8%D6%D4%23bW%3E%40T%07%0E%24%1Ag%3EH%BCpb%B7%C9pK%AE%9F7%5D%23%AE%8E%09%BC%C2-%0C%C2j%E9%C7%1D_%8E%89Z%26%ED%81%F0%C2%A9%D0%F6%B6%89f%9F%200V%AF%25%C5%A2C%9B%2F%AC%D6gi%7D%E4%1A%CF%5E%0B%84%E8%8B%B0%18l%FA%C1%B4%B2%08%06%08%25%84%8C%E31%8C%B4i%23%02%8E%FA%8Er%09%20%8Cz%5C%92%AEfM%9CO%269%EC%40e%92H%8C3%A8%AE%F7%F6%CBPC%FB%00P%C1%C1K%CA%B0lYp%F6%82%D2%3Aj%E8%E0lN%3D%E2%F3%10P%FA%DC%A2%C83%DF%3A%F4M.%10E%00%00%3B";
var Bulldozer1 = "data:image/gif;base64,R0lGODlhMgAuAMQfAPPcGgUEA2peDIp1Dv%2F%2F%2F7KcFdW8GI2amGqfzk10lY6EVeXki1xdXvDgTMfHyFQ0CH%2FA8ffxvefn45i704GFgvr44LWtWLm1oNra28nf9e3t8Dw8O%2Fr59wtjvqTBogAAACH%2FC05FVFNDQVBFMi4wAwEAAAAh%2BQQFZAAfACwAAAAAMgAuAAAF%2FyAhjmRpnmiqrmzrvnAsz3Rt33hecvrMLY1gYxHh9VgSgwGwBDgBxKPqQLEomU9nI1KR7hJgxMF6zTa6rugLA26Lrc%2FhYvFSFBZoVAaRIUwYbW4eAEMZEBATLxcPAwARKQgdiQeBgQhzh4eJLhUbDwIGZyeRiRSVgR4emYgwCg%2BvA1smB5ILBQqnCQgeExAIvxAwDq%2BvoKIjtBRPBriWE8C%2FBzAaAg%2BesI4iCwwdCllMzboHvggUFAYLRi0MxMTGCwYF599OzAlj5gVKS48uFp%2FXiOn71qRJHCb79vVroUCAQ08BBxisRy9LQiV5WFgY4LBdwIEVCS27aECdCg4YCv8M4NiR2LVGZkTWI2lgAAUJLSwU2LmyY0BPAujVfKBvX4FqAZIGuHlyp9OePtvBXPaqAJOjSrMmlYbCVjyeUD9ZsyYApBJYSLWq1XCCg9OvYB1Wk7qk6Cu1eJNeOOEV7lOWcz9JtArgQd6s1jYkxWCCg1GjTlXKnTuAsOHDAwwrOMAgwAaTI8jA9bsSsMOzhwME%2FUThgOK9JzTsTKgvskrTKg8Tq9xaMQMVKZXUjge3tNzcWjMzMteagm%2B2wIsK9wt2ZU21AxQwN9c5wO8WF4oOr%2F1X4gClhgVYMEel%2BwYHMMLTpv5WgNKd69srpQCaBQf5xIkXGWqebcZdUhscgNNkDBroNB95RWXFAAOKJcXfDQ2KFyBxAKyn1gYUMNafDBg4uCFIEmBwgFIbXMDBiDUE99gVdLwogQOMeSGCA9JxCEBGOpbA40VQBJnCf9I5AaORBCDZxEJMxgZHA1GuoAEGRRwRAgAh%2BQQFCgAfACwEAAsAGAAjAAAF%2F%2BD3WU0knmiqfpdQLNUqo9r3DIA5Z5xKKDZXIzZbXU43g66IkmyQQiLz07M9bQPDYipSCD5f0UMI4H4fnyvWwD0JBGixq1gpfAZg8Ca%2BXhGOdnh5YXIrHHYqcGFoYypbKIgiilcubCIcFpYiiHiLcDcoj2yagZJhYWwVBpofpHdukgVsEYiWsimCpiIGVSert5siuR%2BRGK3BBsDBgsMfDr4ynK%2BRzimjx8Eyva2y3ZDEhirJq6wfAHwnGpm7t9QnASsSMqOrAO4oxpaj3ZZHMw7AxmFrUKPIMxTJzH2Q0maXiAUEuHDwd6IMQyYFRZSB2PCDOoUNInb8IOHIkJE0OASIRBECACH5BAUKAB8ALAQACgAaACQAAAX%2F4PdFSyWeaKqezmBEa7xqn1A0pqwT1Pe4C46MILuIHrYGTLeSCE5IA46Z4jyfvkfhRT0RFDXkUSDtogTiJ9JlPgnQKGSByhkMzlefgC1bfOZ3alhjBjEcFiKAIlhvYzFLiR93NW5hfCeHHwaFiZNhg54nC3MinKSTb2lbiRqbppx%2FkpU1pAAfDSibq5GBlLkfF7Clu7GoKQEfNCcGc5ymIqEFyCIOv5rXJ4qRbc%2BywlTMsHOkMbDm2LEAgygaFt%2Bvyx%2FT4H%2BbmpsA5CocGejo5OtWVCv3AUCDgW3Q2YoghEnDFJwaEOnCwUgKWznMKDtha8HENhKu2ZKY8AQGbJBKDX44WeKjyg8cCLhMEQIAIfkEBQoAHwAsAwAJABsAJQAABf%2FgJ37VaJ5oyhVNmb6qIhiLC9%2Fc8QiDEd1Ah0ggYP2AKQnxs%2BvVkCfOUMAsAo7QD0ExWj4GrAoi%2B6EKHuVqz5KgIC3D8u68NCA5ikGXmi73PgB2ACgRBQUDel07TDsFgHYocCOJZmVEjS8VjiKOiX19MykWBqScH4hxJkUoC6UFkCKoaUtFsCSlH7aGp4p8I3aSv7kjnV0pFbYiBq%2FEp54oHAspdrCdz8sjGCfJxNbPIlI3uB%2FFKijUKI6bKRrD0%2B7kN%2B3n28pMLxgXMOgGgTfa9HKt84VPHKAPDICECzhIWkIcH4KZGNSAAAEo81AMwoIR3sEFF8l8kCBiEEUbIrUYFRj0gaNIKfpahhQ5goMEDBxm0jShM0UIACH5BAUKAB8ALAMACQAbACQAAAX%2F4Cd%2By8KNaKqmxDEY0SqvxPUIRRPPPCEJN4GhUeHNOALgR%2FBaGGmMJTCZ2z1FBIXgE7wNcsXrx7LdLqUFgyVxtYySZy7OYHgqPoN3ivmpzyQFeHkicEpUHwB9KRxOH4GDhGdTeYmLgY4iA5BmSzeXKQ19fo%2BQnWZpKRGXqJh4kWV4fokcfoqjpCqlHKEqtZmDnH2BC74otbgjeXUFVil1x7%2BuIoE1iDJ008jSRn7FI95ulSvHgd4aY9cio60rF0%2B1BgDBIxIj4t%2FfzwFi6ewy7jPqJNrHw4GIeygSueG3IhERDE%2FOHVwR44SYhYkAJDKB5Uq9hB%2BIMBQBceKHCARGE36w6GdBSpUoFqCEiUIDh5cyQgAAIfkEBQoAHwAsAwAIABsAJQAABf%2FgJ4rVaJ5oihVNmb6qMBiLC9%2BV8MhGxN0wjkIgErAiJwjwQ1B8iE9jAzmaLC2PYnFWW44O2me0YLAklN4TVEa2eAcDtVj2Mdw4hTjcBB3bX0gFInFyW3YAKG4ignCEWkR0KAsGfwWCH458mH8jEpQilYOOfQMFAA2IHJ91Jpd7dwspnK6ZH2Qikyh2lbSioLcws76ZBhIfiC%2Bzrig%2FIsiyI8tiHxwOQAbAlrZAz7qtrDfdoODOtR8SDm7iJ5R%2FWSgYIwbr5PQv9scf7ynN3NtLF0aIQxYQiAYUyJAt6JdGYL4GBBoac8bpQ4WIDTGkO4YsAsaGzRR9WPCxoQk3JE0LqtBQUqUIAjCBhAAAIfkEBQoAHwAsAgAIABwAJAAABf%2FgJ4rcEo1oqq7cMDTnKq%2BEIgwFPO9iLXw3Q6PCkxEsqOCCWExdVDhDhNMkXX6pWw5ZfQ5WWgum%2BnWpBIKCwVD9lMFp9kzyKaDM54F8tRDZ3V9ueXsoEWojf4KBSYcoHHJ7f2aLiIQlKXKJkyoADSJ9mIiSb1%2BNHxGEKJEjbykVcgArqyJ4fgYanrEfuqqZkimJBryyKIkfexojwrvEiDNPO2yrbA8zy8PKhMacx9FrbbHYKOIpDkgAqSuUKVQOIujhKboBTefjzLRFySLCy%2B8iDdw1wQAtlr8PQ9rQgbbLX4w23D4sIDCCCkQUEy%2BiEIjQosYRDi5EoPgRhQQNJGcChAAAIfkEBQoAHwAsAgAIABsAJAAABf%2FgJ4rEZSxjqq4qYQmFEbH0yl2fMBTNXP84kY5X%2BdEcKp2hUfwgjCLMZ5ASKBeHTwaKmnqFO0MW6qWKzLkdoEE2D9CjIflMh08HBpqvQK9X8SwWIwV8dyNwMCsLeXkihV9UbnY%2BIo0fj25nAioVliONhIeGlSKdLJ4pAzqcbB8AriqWoVOrlT4AqJ8pj44fjbivIsEpsjQaFsA0nny8IhI0w7qX0zXRsMQq1h84BtorjN7bI8Hanptk3dexAWThsOc1gt3zr%2FW9RkjJpNcMZA4F%2BqJ1gYIEYB59CwjM%2BSCFj70PDRQulMItWAMOC1UEKZVxhQkmEjumyIBRpAoOIWkChAAAIfkEBQoAHwAsAgAHABsAJQAABf%2FgJ45cNJ5oqmKDYaqw6nxD0bxxTGCiUN%2B5GO%2F0qwRTvMGAaGgYj6OBgEYVtSwIyDFJ7NUKC05wEV1avQWDAdpdmmmFmLgQt%2Fp85%2BkbRRbVz2dveyIVajFKeFQtKBYja35dgB9pI32OI3%2BKVnuWMZmSIn0AH6OOj5mDHxFrAGsGpZeYoB9kraOwJ6c1KhwLr7%2B2KY%2BTcZkSH8AjuCLDu2cYM6%2B5y8go1My3McPVIxpDrSnU2yfH4dIqow8wF8LBypNspNbyH%2BoqBCfgMVNQ59kjDTawsSAt2YcG5aA4IFgKVgUxbBxEQ4Ej3jsRFS3ygahxhIMLEfB1PIFBg8iRIggEnIwRAgAh%2BQQFCgAfACwBAAcAHAAkAAAF8OAnjl%2B1VGSqrmlxsrAqiYPxxrE0jPWNy7vdyIb6kXQfgVDwKdiMI4lyoFQmm4ZD5kf4CINT2scQga6sQbNKOGLW1F5SWlRYcVopNnOoKo9HdSsDbIEjFQYshTR7IogjHI4kkU15kiIcDSIAKZMsbJiSmysFiikcCx%2BiqZ1wIwAGm6qNdCSllrCsKgVsIhqurrCWgLwkFo2ir7KzyykOmpO5f6kBzc6ryddmvpTJuMpGGNzBY9hqF%2BSIyOQj1Cx3H%2BepnKoPcLiarfP5LK8jDQRdoGwzlqKImhkOCjWoEDCfA2MNIjTc98HBDIok3sEIAQAh%2BQQFMgAfACwCAAcAHAAkAAAFvOAnjtwXjWiqrmNzsrA6CF%2FRxPhq56wm8yvfZzCajRxAEVFAnBFRmKSIxqR9rJ%2FFQTpUVkUFXnjlVFlY43HKyI01r%2B0V7WmIK2EVXOGpA4iEAAZ%2BaDoiAHkigh91LANqKHU3hiODI4xDjygvi5ApmWF8KpUfoz%2BZEpZSmTGXMKswg6UGBa0kqYG4tUl1gr2BbUiUiqJ3UsOkQAQ4v3G%2BiSNnbX7HCxpRbccfJUJ2H5J20d0siOIiJeUiyjghACH5BAUKAB8ALAEABwAdACQAAAX%2F4CeOYkSQaKqmhrm%2BqiMMRePCOCaM9Y2rus9OVKucfqigcDQwNCoZ5AizrM4%2BBgsCguRUUTvaZ8GhSElD0bBgkA5Su1n4UwB8FC%2BL6K0eDdN2KkdMYGoDc4EoFUSEKn9YiSIEeip8figFKAQLKZl7cCNtI5tYpTwklioNH6QfAAaRKG%2BpI3YEEaVtsKKnRLQknCKvrzB8vyvDvCoFxyu7JJ6fL6LEwsqMOBcisKF215mZBg8oGhja1duu1zgSZ%2B656cnpdD96w%2BmivOP18ytpUrFIrHrXjVcDCQ4IqgBQgYMXKe3okQCAiyCVC7woPlT4AaMrMhxRXKgYkoSGHyEAACH5BAUKAB8ALAIABwAbACUAAAX%2F4CeOBDGeaJpyS1SqsMoNQ%2BOacf4p31DYL52KJxoYGpWgcGT5CARFwyJpgiwvUKfTZ4hwEJ2J8OKEmns%2FSxgXw5bPUJ8FsygIs0%2F4p2AwAGImNFp6Wnx%2FKhJFA1pljXF%2BKQR1iiJPjpVGhyMRdgV2PYuDZmaGIxwnnpSiZ58iLCmfNKGjWYeSHwa4I56xI2cnBBG6Irm7sYK%2FHwAVw83GRT0nuQUaDSN%2BucXPoIuh19%2FEuyJ2od52GmQA2uGo5NHrKNns2zIOTTDwvPAfGh%2F3uvJQhfOG4p%2BIPwHDAXiwpE88XLkInjjVTJ06gAfHfFuXC4BEGBeKYRsGwNoSDCE3KYpAsmREyIvFAAhr%2BSHRvZgLaBYcASCnzoIASlL8OcLBhZlETUnolyMEACH5BAUKAB8ALAIACAAaACUAAAX%2F4CeKRDmeaIouC2eqMHoMRlQScX49X9HYrxxKIuB9DI3KTXjiCD5G2uKGYxIYI6MPiGB%2BFJ%2BiiDfwVQ6dCfMpeEJFBYMlQQEI2%2BzxO24A2FUECmyDbyI0fX9DHwMDYW0iT0Y9fgAGTQsFhgN4eTxklCMEHAWki4yOeXoFfiQEDZk9maechT1IJBGwmbCMm3hhwH0foiqlpqjARwCiDUcnu7KznLAEC87XI6TRvo8jESKWxT3HmyN2VeDY2byLbo0EGBY50KaMmQEwluHPxo0x%2Byh2xYoDa4SGC%2FqcAYRDypKbExIQzhthYCGJDxfSJTxRcRwgjRwVfkikgsMHeZWwP3UEIC8HBwctwyUEkISJhpMUj1gC8M3LTXApR7a4KCSivp01vVy8AMtPT6UnEPqxBhUFhgsLnlYdwUGDSRghAAAh%2BQQFCgAfACwDAAkAGwAlAAAF%2F%2BAnfkQ5nmiKRktlqnDqDEZUEnH%2BacJXNK7XCaH7UB4P2oIjHGV0F%2BTD17A1ixIB8jM1AG9FEUfLlRZqpUMnrJi6kQLvgtFRhD%2Fkt4BWoHwAOQQWAoRlUg8CBQCLBjAEHAMDhD0iejSMKgQLIgN4hG9SHwaLKhwWBQUfkZNcla2LgCcEEag%2BqpKFW26XIo2PpyK1qpN5U7wiJQuptraRnj1uIwAGBQQaKKnCq7nBtgYEDSnZy9uFlKInjSfjqeWU0yPX6yPL7Z2sy8jeKqjkksyyANrK1i2Ss0wO8mHzQe5MpxQcRqhjVq8fgHMoNFiIwW5UDo3iuqFTqOIJOnEGRkBhzAQjVUoADRz4CbQv3Z8IdyIua5RyVLgPEYvolDgKQIU78Xql%2FLMJKTIJvf78dKrPQlGcVEcQwHChRVaIOkIAACH5BAUKAB8ALAQACgAaACQAAAX%2F4PcRpGieaGpaTUSosHp9xVK9MBR%2F2vMNABcuNdkpRIJC47aDXXyigUHYREk2H2hyOaxyBNkNVLroVrMCn28LOJ8eD6xJ2m4SFGATPPtJAuowFT99fGIndDAEM4N5UIZ9gCgch4R8ImoCfygECzQFc3locjQpHBYmn4OVcGk%2FBnUGnAWpBqmMelEGIrqCqAW1c4RqKG0RtiK%2FtgOrKD6TqLqpqcuVu1AfGCfSpMGh1G7TSNzgwFGqMLbp48sG3yccF8fc5aTXTZ%2B1n7O%2FuokS4%2BP6AVSRDd2HV4vcIDOhq4GGKmYWfgDQC6KDFLo6KXzGcGJFNw%2FxTdSoUERIEQ1KDFo5uEQlCg0aOKYIAQA7";
var Bulldozer0 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAABmJLR0QA%2FwD%2FAP%2BgvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1wITDBAoje5u6QAAAAh0RVh0Q29tbWVudAD2zJa%2FAAAADUlEQVR42mNgYGBgAAAABQABeqhXUAAAAABJRU5ErkJggg%3D%3D";
var Xadd = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn%2FAACA6AAAdTAAAOpgAAA6lwAAF2%2BXqZnUAAABFElEQVR4nGL8%2F%2F8%2FAzJI2FiDIrDAv4URmQ8QQEwMWECj6WswxgYAAogFXeDvn38Mv%2F4ALQGa%2Bw%2FIRgcAAYRhw5%2Fff%2BDs30hsGAAIIMbQRYX%2FQf5gBEKQ42usPqEoaDnGh8IHCCCW3z9%2BM5TafIHw%2FjMyfP0FcQ6IDTKiyPQ9AywUuo7wMAAEEMuvn38YXnz8DdXwH6SOgRGkghFiIyMDItB%2B%2F%2FzNABBALL9%2B%2FGKYcYQDqoqBIdrkG8QCqKKlZ7ggHEaQ6B8GgABiRI8Hx7b4%2F2Em38FmrzrDwbC%2FaiFKPAAEEEaw%2FgE68ftvkCH%2FgE7ADCWAAMIM1j9%2F4ey%2Fv%2F%2BiSzMABBCWiPvLsOIQAwMkqDA1AAQYAACIahTU1BszAAAAAElFTkSuQmCC";
var XCancel = "data:image/gif;base64,R0lGODlhDgAOAPcAAAAAAIAAAACAAICAAAAAgIAAgACAgICAgMDAwP8AAAD/AP//AAAA//8A/wD//////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMwAAZgAAmQAAzAAA/wAzAAAzMwAzZgAzmQAzzAAz/wBmAABmMwBmZgBmmQBmzABm/wCZAACZMwCZZgCZmQCZzACZ/wDMAADMMwDMZgDMmQDMzADM/wD/AAD/MwD/ZgD/mQD/zAD//zMAADMAMzMAZjMAmTMAzDMA/zMzADMzMzMzZjMzmTMzzDMz/zNmADNmMzNmZjNmmTNmzDNm/zOZADOZMzOZZjOZmTOZzDOZ/zPMADPMMzPMZjPMmTPMzDPM/zP/ADP/MzP/ZjP/mTP/zDP//2YAAGYAM2YAZmYAmWYAzGYA/2YzAGYzM2YzZmYzmWYzzGYz/2ZmAGZmM2ZmZmZmmWZmzGZm/2aZAGaZM2aZZmaZmWaZzGaZ/2bMAGbMM2bMZmbMmWbMzGbM/2b/AGb/M2b/Zmb/mWb/zGb//5kAAJkAM5kAZpkAmZkAzJkA/5kzAJkzM5kzZpkzmZkzzJkz/5lmAJlmM5lmZplmmZlmzJlm/5mZAJmZM5mZZpmZmZmZzJmZ/5nMAJnMM5nMZpnMmZnMzJnM/5n/AJn/M5n/Zpn/mZn/zJn//8wAAMwAM8wAZswAmcwAzMwA/8wzAMwzM8wzZswzmcwzzMwz/8xmAMxmM8xmZsxmmcxmzMxm/8yZAMyZM8yZZsyZmcyZzMyZ/8zMAMzMM8zMZszMmczMzMzM/8z/AMz/M8z/Zsz/mcz/zMz///8AAP8AM/8AZv8Amf8AzP8A//8zAP8zM/8zZv8zmf8zzP8z//9mAP9mM/9mZv9mmf9mzP9m//+ZAP+ZM/+ZZv+Zmf+ZzP+Z///MAP/MM//MZv/Mmf/MzP/M////AP//M///Zv//mf//zP///yH5BAEAABAALAAAAAAOAA4AAAhUAP8JHEiwYDFcxgoq9PVO3K+Fvgb+Sofr4UBcEQuqQyjwl0WF/zBWBDlw40eQ4xD+yqhQnS+LIwume0kwpkB16H5tKohL3EBi4iiBxDUwJcmjIAMCADs=";
//alert("global variables ok");
//=================================
// Controller (core/logic)
//General Classses definitions
/* better merging/splitting way
var merger = '|sepA|';
var arrayThree = new Array( "John", "Paul", "George", "Ringo" );
var lineUp=arrayThree.join( merger );
var members=lineUp.split( merger );
document.write( "|"+merger+"|" + "<br><br>" );
document.write( arrayThree + "<br>" );
document.write( lineUp + "<br>" );
document.write( members + "<br>" );
*/
function Village(){
this.id = 0;
this.name = "raw village";
this.link = "#";
this.coords = "(0|0)";
this.coordX = 0;
this.coordY = 0;
this.lastUpdated=getCurrentTime();
this.resProduction = new Resources();
this.resStock = new Resources();
this.resCapacity = new ResourcesCapacity();
this.resFilled = new Resources();
this.resLeft = new Resources();
this.resFull = new ResourcesFull();
this.getLastUpdatedAgo = function(formatString){
var seconds = getCurrentTime()-this.lastUpdated;
if(formatString) return formatTime(seconds);
return seconds;
}
this.getCurrentStockWood = function(formatString){
var updatedStock = this.resStock.wood + Math.floor( this.resProduction.wood * (this.getLastUpdatedAgo(false)/60/60) );
if(formatString) return addSeparatorsNF(updatedStock,",",",",".");
return updatedStock;
}
this.getCurrentStockClay = function(formatString){
var updatedStock = this.resStock.clay + Math.floor( this.resProduction.clay * (this.getLastUpdatedAgo(false)/60/60) );
if(formatString) return addSeparatorsNF(updatedStock,",",",",".");
return updatedStock;
}
this.getCurrentStockIron = function(formatString){
var updatedStock = this.resStock.iron + Math.floor( this.resProduction.iron * (this.getLastUpdatedAgo(false)/60/60) );
if(formatString) return addSeparatorsNF(updatedStock,",",",",".");
return updatedStock;
}
this.getCurrentStockCrop = function(formatString){
var updatedStock = this.resStock.crop + Math.floor( this.resProduction.crop * (this.getLastUpdatedAgo(false)/60/60) );
if(formatString) return addSeparatorsNF(updatedStock,",",",",".");
return updatedStock;
}
this.toString = function() {
var output = "Village '"+this.name+"'\ncoords "+this.coords+"\nLast updated: "+this.getLastUpdatedAgo(true)+" ago";
output += "\n"+this.id;
output += "\n\nProduction: "+this.resProduction;
output += "\nCurr Stock: "+this.resStock;
output += "\n"+this.resCapacity;
return output;
}
this.storeData = function() {
var persistence = this.resProduction.merge()+":"+this.resStock.merge()+":"+this.resCapacity.merge()+":"+this.lastUpdated;
GM_setValue(this.id + '.Resources',persistence);
return persistence;
}
this.loadData = function(){
//alert("Village before parsing data:\n"+this.toString());
// loads GreaseMonkey persistent data about this village
var rawGMValue = GM_getValue(this.id + '.Resources');
//alert("rawGMValue:\n"+rawGMValue);
// if it wasn't found, store raw data and move on
// if it was found, parse the string
if(!rawGMValue){
this.storeData();
}else{
var rawData = rawGMValue.split(":");
//alert("rawData:\n"+rawData);
this.resProduction.parseRes(rawData[0]);
this.resStock.parseRes(rawData[1]);
this.resCapacity.parseRes(rawData[2]);
this.lastUpdated=rawData[3];
}
//alert("Village after parsing data:\n"+this.toString());
this.resFilled.wood = this.getCurrentStockWood(false) / this.resCapacity.warehouse * 100;
this.resFilled.clay = this.getCurrentStockClay(false) / this.resCapacity.warehouse * 100;
this.resFilled.iron = this.getCurrentStockIron(false) / this.resCapacity.warehouse * 100;
this.resFilled.crop = this.getCurrentStockCrop(false) / this.resCapacity.granary * 100;
this.resLeft.wood = this.resCapacity.warehouse - this.getCurrentStockWood(false);
this.resLeft.clay = this.resCapacity.warehouse - this.getCurrentStockClay(false);
this.resLeft.iron = this.resCapacity.warehouse - this.getCurrentStockIron(false);
this.resLeft.crop = this.resCapacity.granary - this.getCurrentStockCrop(false);
this.resFull.wood = this.resFilled.wood > vInfo.maxcap;
this.resFull.clay = this.resFilled.clay > vInfo.maxcap;
this.resFull.iron = this.resFilled.iron > vInfo.maxcap;
if(this.resProduction.crop >=0)
this.resFull.crop = this.resFilled.crop > vInfo.maxcap;
else
this.resFull.crop = this.resFilled.crop < 100-vInfo.maxcap;
//alert("resFull.crop: "+this.resFull.crop+"\n\nresProduction.crop: "+this.resProduction.crop+" resFilled.crop: "+this.resFilled.crop);
this.resFull.any = false;
if(this.resFull.wood) this.resFull.any=true;
if(this.resFull.clay) this.resFull.any=true;
if(this.resFull.iron) this.resFull.any=true;
//if(this.resFull.crop) this.resFull.any=true;
//alert(this.toString());
//alert("Village after parsing data:\n"+this.toString());
}
}
function VillagesData(){
this.count=0;
this.productionFactorBase = 1000000000;
this.maxcap=75;
//deprecated
this.vTableStatus = 1;
this.totalProduction = new Resources();
this.totalStock = new Resources();
this.totalCapacity = new ResourcesCapacity();
this.totalFilled = new Resources();
this.productionFactor = new Resources();
this.vList = new Village(125);
// general data related to current page
//unique ID, used to differentiate user & server accounts
this.uniqueID = 0;
//array with all villages ID, it is different from vInfo.vList[].id
this.rawVillageIDs = new Array();
//active village raw ID
this.activeVillageID=0;
//active village's position (index) among villages list, that's necessary in some places to relate active village with villages array
this.activeVillageIndex=0;
// default language is br
this.serverLang="br";
this.setTableStatus = function(status){
GM_setValue(vInfo.uniqueID+"TableStatus",status);
return status;
}
this.getTableStatus = function(){
var statusRaw = GM_getValue(vInfo.uniqueID+"TableStatus");
if(statusRaw){
return parseInt(statusRaw);
}else{
this.setTableStatus(2);
return 2;
}
}
this.toString = function(){
var output = "[VillagesData] count: "+this.count;
output += "\nTotal Production: "+this.totalProduction;
output += "\nTotal Stock: "+this.totalStock;
output += "\nTotal Capacity: "+this.totalCapacity;
for(var i=0;i<this.count;i++){
output += "\n\n"+this.vList[i];
}
return output;
}
this.reloadData = function(){
this.resetTotals();
//alert("before villages loadData()");
for(var i=0;i<this.count;i++){
this.vList[i].loadData();
this.sumTotals(i);
}
//alert("after villages loadData()");
this.totalFilled.wood = this.totalStock.wood / this.totalCapacity.warehouse * 100;
this.totalFilled.clay = this.totalStock.clay / this.totalCapacity.warehouse * 100;
this.totalFilled.iron = this.totalStock.iron / this.totalCapacity.warehouse * 100;
this.totalFilled.crop = this.totalStock.crop / this.totalCapacity.granary * 100;
this.productionFactor.wood = 1/(this.totalProduction.wood*this.totalFilled.wood)*this.productionFactorBase;
this.productionFactor.clay = 1/(this.totalProduction.clay*this.totalFilled.clay)*this.productionFactorBase;
this.productionFactor.iron = 1/(this.totalProduction.iron*this.totalFilled.iron)*this.productionFactorBase;
this.productionFactor.crop = 1/(this.totalProduction.crop*this.totalFilled.crop)*this.productionFactorBase;
}
this.resetTotals = function(){
this.totalProduction.resetValues();
this.totalStock.resetValues();
this.totalCapacity.resetValues();
}
this.sumTotals = function(index){
this.totalProduction.wood += this.vList[index].resProduction.wood;
this.totalProduction.clay += this.vList[index].resProduction.clay;
this.totalProduction.iron += this.vList[index].resProduction.iron;
this.totalProduction.crop += this.vList[index].resProduction.crop;
this.totalStock.wood += this.vList[index].getCurrentStockWood(false);
this.totalStock.clay += this.vList[index].getCurrentStockClay(false);
this.totalStock.iron += this.vList[index].getCurrentStockIron(false);
this.totalStock.crop += this.vList[index].getCurrentStockCrop(false);
this.totalCapacity.warehouse += this.vList[index].resCapacity.warehouse;
this.totalCapacity.granary += this.vList[index].resCapacity.granary;
}
}
//Resources class stores and deals with the 4 basic resources, its objects are used in many places
function Resources(){
this.wood = 1;
this.clay = 1;
this.iron = 1;
this.crop = 1;
this.woodf = function(){
return addSeparatorsNF(this.wood.toFixed(0),",",",",".");
}
this.clayf = function(){
return addSeparatorsNF(this.clay.toFixed(0),",",",",".");
}
this.ironf = function(){
return addSeparatorsNF(this.iron.toFixed(0),",",",",".");
}
this.cropf = function(){
return addSeparatorsNF(this.crop.toFixed(0),",",",",".");
}
this.toString = function() {
var output = "Resources [wood: "+this.wood+"; clay: "+this.clay+"; iron: "+this.iron+"; crop: "+this.crop+"]";
return output;
}
this.merge = function() {
var output = this.wood+"/"+this.clay+"/"+this.iron+"/"+this.crop;
return output;
}
this.parseRes = function(rawString) {
var data = rawString.split("/");
this.wood = parseInt(data[0]);
this.clay = parseInt(data[1]);
this.iron = parseInt(data[2]);
this.crop = parseInt(data[3]);
}
this.resetValues = function(){
this.wood = 0;
this.clay = 0;
this.iron = 0;
this.crop = 0;
}
}
//ResourcesCapacity class stores and deals with Warehouse and Granary capacities, its objects are used in many places
function ResourcesCapacity(){
this.warehouse = 800;
this.granary = 800;
this.toString = function() {
var output = "Capacity [warehouse: "+this.warehouse+"; granary: "+this.granary+"]";
return output;
}
this.merge = function() {
var output = this.warehouse+"/"+this.granary;
return output;
}
this.parseRes = function(rawString) {
var data = rawString.split("/");
this.warehouse = parseInt(data[0]);
this.granary = parseInt(data[1]);
}
this.resetValues = function(){
this.warehouse = 800;
this.granary = 800;
}
this.warehousef = function(){
return addSeparatorsNF(this.warehouse.toFixed(0),",",",",".");
}
this.granaryf = function(){
return addSeparatorsNF(this.granary.toFixed(0),",",",",".");
}
}
//ResourcesFull class stores boolean values, reporting if each resource is near to be full; if any of them is full this.any sould be true
function ResourcesFull(){
this.wood = true;
this.clay = true;
this.iron = true;
this.crop = true;
this.any = true;
}
//ResourceField class stores info about 1 construction (resource field or building) of 1 village
function Construction(){
//construction
//from 0 to 17: resource field
// > 17: building
this.position=0;
/* resource type:
* g0: raw data
* g1: wood
* g2: clay
* g3: iron
* g4: crop
* g9: building
*/
this.type='g0';
// field level
this.lvl=0;
// field name string
this.name="";
//tag used to separate elements for merging then into a unique string
this.merger='|ctrtmerge|';
this.setLvl = function(source){
var lvlString = ""+source;
var parsedString = parseInt(lvlString);
if(parsedString == "NaN"){
this.lvl=-1;
}else{
this.lvl=parsedString;
}
}
this.merge = function(){
var mergeArray = new Array(this.position,this.type,this.lvl,escape(this.name));
var output = mergeArray.join(this.merger);
//var output = this.position+'/'+this.type+'/'+this.lvl+'/'+escape(this.name);
return output;
}
this.parse = function(rawString) {
//var data = rawString.split("/");
var data = rawString.split(this.merger);
this.position = parseInt(data[0]);
this.type = data[1];
this.setLvl(data[2]);
this.name = unescape(data[3]);
}
this.toString = function() {
var output = "Ctruct [p: "+this.position+"; t: "+this.type+"; lvl: "+this.lvl+"; name: "+this.name+"]";
return output;
}
}
//VillageResourcesLayout class stores a village's resources fields layout
function VillageResourcesLayout(vIndex){
this.count=18;
//index of the village this object represents, relative to vInfo.vList[] array
//when creating an object, if you want it to represent the active village, use vInfo.activeVillageIndex
this.villageIndex=vIndex;
// creates a ResourceField array and instantiates all objects
this.list = new Array();
for(var i=0;i<this.count;i++)
this.list[i] = new Construction();
this.getVillageResourcesLayoutID = function(){
var output = vInfo.uniqueID+ this.villageIndex + '.Dorf1';
return output;
}
this.merge = function(){
var stringArr=new Array();
for(var i=0;i<this.count;i++){
stringArr[i] = this.list[i].merge();
}
var output=stringArr.join(':');
return output;
}
this.parse = function(rawString) {
var data = rawString.split(":");
for(var i=0;i<this.count;i++){
this.list[i].parse(data[i]);
}
}
this.toString = function(){
var output="[VillageResourcesLayout]: index="+this.villageIndex+" name: "+vInfo.vList[this.villageIndex].name;
for(var i=0;i<this.count;i++){
output += "\n"+this.list[i].toString();
}
return output;
}
this.storeData = function(){
var presistance = "";
persistance = this.merge();
GM_setValue(this.getVillageResourcesLayoutID(),persistance);
return persistance;
}
this.loadData = function(){
var rawData = GM_getValue(this.getVillageResourcesLayoutID());
if(!rawData) return false;
this.parse(rawData);
return true;
}
}
//VillageBuildingsLayout class stores a village's buildings layout
function VillageBuildingsLayout(vIndex){
this.count=22;
//index of the village this object represents, relative to vInfo.vList[] array
//when creating an object, if you want it to represent the active village, use vInfo.activeVillageIndex
this.villageIndex=vIndex;
//creates a Building array and instantiates all objects
this.list = new Array();
for(var i=0;i<this.count;i++){
this.list[i] = new Construction();
}
this.getVillageBuildingsLayoutID = function(){
var output = vInfo.uniqueID+ this.villageIndex + '.Dorf2';
return output;
}
this.merge = function(){
var stringArr=new Array();
for(var i=0;i<this.count;i++){
stringArr[i] = this.list[i].merge();
}
var output=stringArr.join(':');
return output;
}
this.parse = function(rawString) {
var data = rawString.split(":");
for(var i=0;i<this.count;i++){
this.list[i].parse(data[i]);
}
}
this.toString = function(){
var output="[VillageBuildingsLayout]: index="+this.villageIndex+" name: "+vInfo.vList[this.villageIndex].name;
for(var i=0;i<this.count;i++){
output += "\n"+this.list[i].toString();
}
return output;
}
this.storeData = function(){
var presistance = "";
persistance = this.merge();
GM_setValue(this.getVillageBuildingsLayoutID(),persistance);
return persistance;
}
this.loadData = function(){
var rawData = GM_getValue(this.getVillageBuildingsLayoutID());
if(!rawData) return false;
this.parse(rawData);
return true;
}
}
// Miscelaneous element used for Events that are not based on Constructions
function MiscElement(){
this.element="";
//tag used to separate elements for merging then into a unique string
this.merger='|mcemerge|';
this.merge = function(){
return escape(this.element);
}
this.parse = function(rawString) {
this.element = unescape(rawString);
}
this.toString = function(){
return "[MiscElement]: "+this.element;
}
}
// Event structe, as Construction and MiscElement
// used for Barrack, Stable and Workshop trainings
function Training(){
//string data to distinguish between buildings
this.name="";
this.troopName="";
//tag used to separate elements for merging then into a unique string
this.merger='|trainmerge|';
this.merge = function(){
var mergeArray = new Array(escape(this.name),escape(this.troopName));
var output = mergeArray.join(this.merger);
//var output = this.position+'/'+this.type+'/'+this.lvl+'/'+escape(this.name);
return output;
}
this.parse = function(rawString) {
//var data = rawString.split("/");
var data = rawString.split(this.merger);
this.name = unescape(data[0]);
this.troopName = unescape(data[1]);
}
this.toString = function(){
var output = "[Training] building: "+this.name+" troopName: "+this.troopName;
return output;
}
}
/* old event + construction merging/parsing structure
0 type
1 duration
2 start
3 position
4 type (g2)
5 x.gif
6 lvl
7 name
*/
/* Event types:
1: resource field (Dorf1)
2: building (Dorf2)
3: Demolish
4: Blacksmith & Armoury upgrades & Town Hall celebrations
5: Barrack, Stable & Worksop troops training
6: troops & mercants movements
dots:
1: event 1
2: events 2, 3
3: event 4, 5
4: event 6
*/
// events are constructions, they may be of resource fields or buildings, construction of new structures or upgrading of existing ones
function Event(){
// event type
this.type=0;
// when the construction started, in seconds
this.start=getCurrentTime();
// how much time it takes for the event finish, in seconds
this.duration=0;
//event info, if this.type=1 it is a ResourceField object, if this.type=2 it is a Building object
this.structure = new Construction();
//tag used to separate elements for merging then into a unique string
this.merger='|evtmerge|';
this.setUnformattedDuration = function(unformatted){
this.duration=getSeconds(unformatted);
return this.duration;
}
this.getTimeLeft = function(){
var seconds=this.start+this.duration-getCurrentTime();
return seconds;
}
this.getEndingTime = function(){
var date=new Date();
date.setTime((this.start+this.duration)*1000);
//alert("date: "+date);
return date.getHours()+':'+date.getMinutes()+':'+date.getSeconds();
}
this.isConstructionEvent = function(){
if(this.type==1 || this.type==2 || this.type==3) return true;
else return false;
}
this.isTrainingEvent = function(){
return this.type==5;
}
//events expire after their duration, this method tests if this event has expired or not
// returns true if it is a valid event (green dot), false if it has expired (yellow dot)
this.evaluateOldEvent = function(){
return this.getTimeLeft() > 0;
}
this.merge = function(){
var mergeArray = new Array(this.type,this.start,this.duration,this.structure.merge());
var output = mergeArray.join(this.merger);
//var output = this.type+'|'+this.start+'|'+this.duration+'|'+this.structure.merge();
return output;
}
this.parse = function(rawString) {
//alert(rawString);
//var data = rawString.split("|");
var data = rawString.split(this.merger);
//alert(data);
if(data.length==4){
this.type = parseInt(data[0]);
this.start = parseInt(data[1]);
this.duration = parseInt(data[2]);
if(this.type!=1 && this.type!=2 && this.type!=3 && this.type!=5) this.structure = new MiscElement();
if(this.type==5) this.structure = new Training();
this.structure.parse(data[3]);
}else{
alert("Error: Something went wrong. I was trying to parse an Event, and Event.parse.data should have 4 elements, but it has "+data.length);
return false;
}
//alert("parsed event: "+this);
return true;
}
this.toString = function() {
var output = "Event [type: "+this.type+"; duration: "+formatTime(this.duration)+
"; time left: "+formatTime(this.start+this.duration-getCurrentTime())+
"] "+this.structure;
return output;
}
}
// deals with all events of a village
// Note: valid and real data must always be persistently stored, these classes are only used to deal with data for a short period of time, so make sure to always reload before doint anything and re-storing after any change
// loadData() automatically calls removeOldEvents(), so removeOldEvents() should not be needed to be used by code outside the class, if you feel it may be needed, give preference to realoding the data instead of using removeOldEvents()
function VillageEvents(){
this.events = new Array();
this.villageEventID=0;
this.count = function(){
return this.events.length;
}
this.sortEvents = function(){
this.events.sort(function(eventA,eventB){
return eventA.getTimeLeft() - eventB.getTimeLeft();
});
}
this.purge = function(){
this.events = new Array();
this.storeData();
}
this.hasEventType = function(type){
for(var i=0;i<this.count();i++){
if(this.events[i].type==type) return true;
}
return false;
}
this.hasExpiredEventOfType = function(type){
for(var i=0;i<this.count();i++){
if(this.events[i].type==type && !this.events[i].evaluateOldEvent()) return true;
}
return false;
}
//returns an array storing requred events index
this.getEventOfType = function(type){
var indexes=new Array();
for(var i=0;i<this.count();i++){
if(this.events[i].type==type){
indexes.push(i);
}
}
return indexes;
}
this.storeData = function(){
var presistance = "";
persistance = this.merge();
GM_setValue(this.getVillageEventID(),persistance);
return persistance;
}
this.loadData = function(){
var rawData = GM_getValue(this.getVillageEventID());
//alert("VillageEvents.loadData.rawData:\n\n"+rawData);
if(!rawData){
this.events = new Array();
return null;
}
if(!this.parse(rawData)){
this.storeData();
}
// if(this.removeOldEvents()){
// this.storeData();
// }
return this.count();
}
this.pushEvent = function(event){
//alert("pushEvent: "+event);
this.loadData();
//if(event.evaluateOldEvent()){
//this.events.push(event);
this.events[this.count()]=event;
this.sortEvents();
this.storeData();
//}
}
// removes an event, must call loadData() just before call it!
this.removeEvent = function(index){
this.events.splice(index,1);
this.storeData();
}
this.removeDemolishEvent = function(){
this.loadData();
var newEvents = new Array();
var hadDemolish=false;
for(var i=0;i<this.count();i++){
if(this.events[i].type!=3){ // if it is a demolish event
var nelength=newEvents.length;
newEvents[nelength]=this.events[i];
}else{
hadDemolish=true;
}
}
if(hadDemolish){
this.events=newEvents;
this.storeData();
}
return hadDemolish;
}
this.removeTrainingEvents = function(building){
this.loadData();
var newEvents = new Array();
var hadTraining=false;
for(var i=0;i<this.count();i++){
//alert("event "+i+": "+this.events[i]);
if(this.events[i].type==5 && this.events[i].structure.name==building){ // if it is a training event and its building matches
hadTraining=true;
//alert(i+" removed");
}else{
var nelength=newEvents.length;
newEvents[nelength]=this.events[i];
}
}
if(hadTraining){
this.events=newEvents;
this.storeData();
}
return hadTraining;
}
this.findEvent = function(baseName){
for(var i=0;i<this.count();i++){
if(this.events[i].structure.name.slice(0,5)==baseName && this.events[i].isConstructionEvent()){
return i;
}
}
return -1;
}
// DEPRECATED!! this method should not be used
//events expire after their duration, this method tests all events inside its object and updates events array
// returns true if any event was removed and false if otherwise, if it returns true you SHOULD call storeData() immediately to update persistent data
this.removeOldEvents = function(){
var newEvents = new Array();
var eventRemoved=false;
for(var i=0;i<this.count();i++){
if(this.events[i].evaluateOldEvent()){
var nelength=newEvents.length;
newEvents[nelength]=this.events[i];
}else{
eventRemoved=true;
}
}
//alert("internal list: "+this.events.length+"\nnewEvents: "+newEvents.length+"\neventRemoved: "+eventRemoved);
this.events=newEvents;
return eventRemoved;
}
this.getVillageEventID = function(){
var output = vInfo.vList[this.villageEventID].id + '.TimedEvents';
return output;
}
this.merge = function(){
var stringArr=new Array();
for(var i=0;i<this.count();i++){
stringArr[i] = this.events[i].merge();
}
var output=stringArr.join(':');
return output;
}
this.parse = function(rawString) {
var data = rawString.split(":");
var newEvents = new Array();
for(var i=0;i<data.length;i++){
var event = new Event();
event.parse(data[i]);
newEvents.push(event);
}
this.events=newEvents;
}
this.toString = function(){
//this.loadData();
var output="[VillageEvents]: "+this.getVillageEventID()+" "+vInfo.vList[this.villageEventID].name+" "+this.count()+" events";
for(var i=0;i<this.count();i++){
output += "\n"+this.events[i].toString();
}
return output;
}
}
// stores all events of all villages
// caution: //AllVillagesEvents requires vInfo data that are gathered inside getReferenceData.get() to be instantiated
function AllVillagesEvents(){
this.villages = new Array();
for(var i=0;i<vInfo.count;i++){
this.villages[i]=new VillageEvents();
this.villages[i].villageEventID=i;
//alert("VillageEvent created:\n"+this.villages[i]);
}
this.count = function(){
var counting=0;
this.loadData();
for(var i=0;i<vInfo.count;i++){
counting+=this.villages[i].count();
}
return counting;
}
this.purge = function(){
for(var i=0;i<vInfo.count;i++){
this.villages[i].purge();
}
}
this.addNewEvent = function(evt){
this.villages[vInfo.activeVillageIndex].pushEvent(evt);
}
this.removeDemolishEvent = function(){
this.villages[vInfo.activeVillageIndex].removeDemolishEvent();
}
this.getNextEvents = function(){
//alert("entering AllVillagesEvents.getNextEvents()");
var nextEvents = new Array();
// i loops throu villages list, j loops throu each village's events list
for(var i=0;i<vInfo.count;i++){
//alert(vInfo.vList[i].name+" events: "+this.villages[i].count());
for(var j=0;j<this.villages[i].count();j++){
//alert("this.villages["+i+"].events["+j+"].evaluateOldEvent(): "+this.villages[i].events[j].evaluateOldEvent()+"\n\n"+vInfo.vList[i].name);
// get current village (i) 's current event (j) and verify if it has expired
if(this.villages[i].events[j].evaluateOldEvent()){
// if it hasn't expired, add it to nextEvents and exit j loop
//nextEvents.push(new NextEvent(i,villages[i].events[j]));
nextEvents.push(new NextEvent(i,this.villages[i].events[j]));
break;
}else{
// if it has expired, continue to next (j) event
continue;
}
}
}
nextEvents.sort(sortNextEvents);
return nextEvents;
}
this.storeData = function(){
for(var i=0;i<vInfo.count;i++){
this.villages[i].storeData();
}
}
this.loadData = function(){
var eventCount=0;
for(var i=0;i<vInfo.count;i++){
eventCount+=this.villages[i].loadData();
}
return eventCount;
}
// DEPRECATED!! this method should not be used
// AllVillagesEvents.removeOldEvents() loops thru all VillageEvents and call their VillageEvents.removeOldEvents()
// when an event is detected as expired on a VillageEvents, its storeData() is automatically called, making sure persistent data is kept valid
// returns true if any event inside any VillageEvents had expired, false otherwise, but it is only an aditional info (loggin/debugging meant) since all measures had already been done
// anyway, all removeOldEvents() methods are meant to be used only internally on event classes, if you feel any of them may be needed, give preference to realoding the data instead of using them
this.removeOldEvents = function(){
var eventRemoved=false;
for(var i=0;i<vInfo.count;i++){
if(this.villages[i].removeOldEvents()){
eventRemoved=true;
this.villages[i].storeData();
}
}
return eventRemoved;
}
this.toString = function(){
this.loadData();
var output="[AllVillagesEvents]: "+this.count()+" events";
for(var i=0;i<vInfo.count;i++){
output += "\n\n"+this.villages[i].toString();
}
return output;
}
}
function NextEvent(village,evt){
//village index according to vInfo.vList[index]
this.village=village;
// Event object
this.event=evt;
this.toString = function(){
output = "[NextEvent] village:"+vInfo.vList[this.village].name+" "+this.event;
return output;
}
}
function sortNextEvents(nxevt1,nxevt2){
return nxevt1.event.getTimeLeft() - nxevt2.event.getTimeLeft();
}
function BmArmTable(){
this.troopName="";
this.lvl=-1;
this.duration=0;
this.upgradeLink="";
this.setUnformattedDuration = function(unformatted){
this.duration=getSeconds(unformatted);
return this.duration;
}
this.toString = function(){
output = "[BmArmTable] troopName: "+this.troopName+"; lvl: "+this.lvl+"; duration: "+formatTime(this.duration);
return output;
}
}
function TrainTable(){
// train button's DOM element
this.btnLink;
// verifying flag
// if true, this builging training event is being logged by user and should be updated
// if false, user removed this building training and doesn't want it being logged, ignore it until he adds it back manually
this.isTraining=false;
//internal string data to distinguish between buildings
this.building="";
this.troopName="";
this.duration=0;
// DOM element where Xadd button is added
this.addCell;
this.setUnformattedDuration = function(unformatted){
this.duration=getSeconds(unformatted);
return this.duration;
}
this.toString = function(){
var output = "[TrainTable] isTraining: "+this.isTraining+"; building: "+this.building+"; troop: "+this.troopName+
"; duration: "+formatTime(this.duration);
return output;
}
}
function Movement(){
this.name="";
this.time="";
this.cell;
this.start=getCurrentTime();
this.toString = function(){
var output="[MercantMovement] name: "+this.name+" time: "+this.time+" cell: "+this.cell;
return output;
}
}
function CP(building,rank,lvl,cp,eff){
this.rank = rank;
this.building = building;
this.lvl = lvl;
this.cp = cp;
this.eff = eff;
this.getFormattedEff = function(){
return addSeparatorsNF(this.eff,",",",",".");
}
this.toString = function(){
var output = "[Culture Point] rank: "+this.rank+"building: "+this.building+"; lvl: "+this.lvl+"; CP earn: "+this.cp+"; raw efficiency: "+this.getFormattedEff()+".";
return output;
}
}
function VillageCPRank(vIndex,cpIndex){
this.vIndex=vIndex;
this.cpIndex=cpIndex;
this.toString = function(){
var output = "[VillageCPRank] village: "+vInfo.vList[vIndex].name+"; building: "+cps[cpIndex].building
+" "+cps[cpIndex].lvl+"; efficiency: "+cps[cpIndex].getFormattedEff();
return output;
}
}
function sortByEfficiency(up1,up2){
return cps[up1.cpIndex].rank - cps[up2.cpIndex].rank; //the one with higher efficiency goes up to the begin of the array
}
function sortByVillage(up1,up2){
return up2.vIndex - up2.vIndex;
}
function VillagesCPArray(){
this.list=new Array();
this.count = function(){
return this.list.length;
}
this.sortBy = function(sort){
if(sort!="efficiency"){
this.list.sort(sortByVillage);
}else{
this.list.sort(sortByEfficiency);
}
return this.list;
}
this.toString = function(){
var output="[VillagesCPArray]: "+this.count()+" elements\n";
for(var i=0;i<this.count();i++){
output+="\n"+this.list[i];
}
return output;
}
}
function getCPRank(pervillage){
//alert("entering getCPRank()");
var cpArray=new VillagesCPArray();
var vbl;
cpSkipList.loadData();
// for every village...
for(var vil=0;vil<vInfo.count;vil++){ // debug loop, replace it by vInfo.count
vbl = new VillageBuildingsLayout(vil);
vbl.loadData();
var villageEntries=0;
// look throu cps
for(var cpsi=0;cpsi<cps.length;cpsi++){ // debug loop, replace it by cps.length
//alert("vil="+vil+" cpsi="+cpsi+"\n\n"+cps[cpsi].building+" "+cps[cpsi].lvl);
var buildingFound=false;
// for every village building...
for(var vbli=0;vbli<vbl.count;vbli++){
//alert("vil="+vil+" cpsi="+cpsi+" building="+vbli+"\n\n"+cps[cpsi].building+" "+cps[cpsi].lvl+"\n"+vbl.list[vbli].name+" "+vbl.list[vbli].lvl);
// do "it" until we have found a maixmum of 'pervillage' entries
// if current cps rank building matches current village building
if(cps[cpsi].building == vbl.list[vbli].name){
//alert("building name matched!\n\nvil="+vil+" cpsi="+cpsi+" building="+vbli+"\n\n"+cps[cpsi].building+" "+cps[cpsi].lvl+"\n"+vbl.list[vbli].name+" "+vbl.list[vbli].lvl);
buildingFound=true;
// if it is <= it was already built, but if it is > then it wasn't built yet and it is one of the most efficient upgrades to increase CP production
if(cps[cpsi].lvl > vbl.list[vbli].lvl){
//alert("lvl matched, this one wasn't built yet!\n\n vil="+vil+" building="+vbli+" cpsi="+cpsi+"\n\n"+cps[cpsi].building+" "+cps[cpsi].lvl+"\n"+vbl.list[vbli].name+" "+vbl.list[vbli].lvl);
if(cpSkipList.canSuggest(vil,cpsi)){
cpArray.list[cpArray.count()] = new VillageCPRank(vil,cpsi);
villageEntries++;
//alert("cpArray:\n\n"+cpArray);
}
}
//alert("building found, no need to loop vbli anymore\n\nvil="+vil+" cpsi="+cpsi+" building="+vbli);
break; // continue not working? ;/
}
}
if(!buildingFound){
if(cpSkipList.canSuggest(vil,cpsi)){
//cps building not found, it must not be built yet, add it to cpArray
cpArray.list[cpArray.count()] = new VillageCPRank(vil,cpsi);
villageEntries++;
//alert("building not found, this one wasn't built yet!\n\n vil="+vil+" cpsi="+cpsi+"\n\n"+cps[cpsi].building+" "+cps[cpsi].lvl);
//alert("cpArray:\n\n"+cpArray);
}
}
if(villageEntries>=pervillage){
//alert("pervillage was matched, this means that we have enought CP suggestions entries for this village, we can skip to next village now...");
//alert("cpArray:\n\n"+cpArray);
break;
}
}
}
// ok, we are done and our list is complete... almost
//alert("Full cpArray:\n\n"+cpArray);
// now we must sort it by efficiency
//cpArray.sortByEfficiency(); // now it is sorted after getCPRank() returns
//alert("Sorted cpArray:\n\n"+cpArray);
return cpArray;
}
function CPSkip(){
// vID must match vInfo.vList[].id
this.vID="rawvillage";
this.cpIndex=999;
this.toString = function(){
var output="[CPSkip] vID: "+this.vID+" cpIndex:"+this.cpIndex+".";
return output;
}
this.merge = function() {
var output = this.vID+"/"+this.cpIndex;
return output;
}
this.parse = function(rawString) {
var data = rawString.split("/");
this.vID = data[0];
this.cpIndex = parseInt(data[1]);
}
}
function CPSkipList(){
this.list=new Array();
this.list[0]=new CPSkip();
this.count = function(){
return this.list.length;
}
this.add = function(cpskip){
//alert("CPSkipList.add()\n\n"+cpskip);
this.list[this.count()]=cpskip;
this.storeData();
return this.count();
}
this.resetSkips = function(){
this.list=new Array();
this.list[0]=new CPSkip();
this.storeData();
//alert("CPSkipList reseted:\n\n"+this);
}
this.canSuggest = function(vil,cpsi){
//alert("entering CPSkipList.canSuggest()");
for(var i=0;i<this.count();i++){
if(vInfo.vList[vil].id == this.list[i].vID && cpsi==this.list[i].cpIndex) return false;
}
return true;
}
this.toString = function(){
var output="[CPSkipList]: "+this.count()+" entries\n";
for(var i=0;i<this.count();i++){
output+="\n"+this.list[i];
}
return output;
}
this.storeData = function() {
//alert("entering CPSkipList.storeData\n\n"+this);
var persistence = this.list[0].merge();
for(var i=1;i<this.count();i++){
persistence += ":"+this.list[i].merge();
}
GM_setValue(vInfo.uniqueID + '.CPSkip',persistence);
return persistence;
}
this.loadData = function(){
//alert("CPSkipList before loading data:\n"+this.toString());
// loads GreaseMonkey persistent data about this village
var rawGMValue = GM_getValue(vInfo.uniqueID + '.CPSkip');
//alert("rawGMValue:\n"+rawGMValue);
// if it wasn't found, store raw data and move on
// if it was found, parse the string
if(rawGMValue){
var rawData = rawGMValue.split(":");
this.list=new Array();
for(var i=0;i<rawData.length;i++){
this.list[i]=new CPSkip();
this.list[i].parse(rawData[i]);
}
}
//alert("CPSkipList after loading data:\n"+this.toString());
}
}
//alert("classes definition ok");
// ›› Event listener starts things off once the page is done loading.
window.addEventListener("load",init,false);
function init() {
//alert("entering init()");
if (GM_getValue("InActive")){
inactivestub();
return;
}
//alert("passed inactivestub()");
if (!(/travian/.exec(document.domain))) {
offsitestub();
return;
}
//alert("passed offsitestub()");
core.run();
}
function Core(){
this.run = function(){
//alert("entering Core.run()");
//debug();
getReferenceData.get();
//alert("getReferenceData.get() ok");
getResourceInfo.get();
//alert("getResourceInfo.get() ok");
makeDefaultCSS();
showTotalProduction.show();
//alert("showTotalProduction.show ok");
getBuildInfo.get();
//alert("getBuildInfo.get() ok");
//these classes require vInfo data that are gathered inside getReferenceData.get() to be instantiated
allVillagesEvents = new AllVillagesEvents();
if (!GM_getValue(vInfo.uniqueID+"Prefs")){GM_setValue(vInfo.uniqueID+"Prefs",'0.1.1.0.0.T.S');}
Prefs = GM_getValue(vInfo.uniqueID+"Prefs").split('.');
//alert("Prefs() ok");
addListener.get();
//alert("addListener.get() ok");
createMenu.show();
//alert("createMenu.show() ok");
showEvents.show();
//alert("showEvents.show() ok");
setInterval(timerCooldown,1000);
//alert("timerCooldown() ok");
//addRemoveEvent();
//alert("addRemoveEvent() ok");
showCPSuggestions = new ShowCPSuggestions();
showCPSuggestions.show();
//alert("showCPSuggestions.show() ok");
//getCPRank(5);
debug();
//alert("That's it, everything working!!");
}
}
function timerCooldown(){
//alert("entering timerCooldown()");
var timers=TM_searchDOM('//span[@id="TMcooldown"]');
//alert(timers.snapshotLength+" timers found");
for(var i=0;i<timers.snapshotLength;i++){
var timeleft=timers.snapshotItem(i).getAttribute("timeleft");
var yellow=timers.snapshotItem(i).getAttribute("yellow");
//alert("timeleft: "+timeleft);
if(timeleft){ // if it was found
timeleft=parseInt(timeleft);
timeleft--;
timers.snapshotItem(i).setAttribute("timeleft",timeleft);
timers.snapshotItem(i).innerHTML=formatTime(timeleft);
//if(timeleft>10 && timeleft<-30){
if(timeleft<0){ // if it is negative
timers.snapshotItem(i).setAttribute("yellow","true");
if(yellow!="true"){
showEvents.buildEventsTable(false);
//alert("showEvents.buildEventsTable(false) was called, timeleft: "+timeleft+" yellow: "+yellow);
}
}
}
}
}
function removeEvent(vlg,evt){
//alert("village: "+vlg+"; event: "+evt);
allVillagesEvents.villages[vlg].removeEvent(evt);
//window.location.href=window.location.href;
showEvents.buildEventsTable(false);
}
function addRemoveEvent(){
//alert("entering addRemoveEvent()");
var removeIcons=TM_searchDOM('//a[@id="TMRemoveEvent"]');
//alert(removeIcons.snapshotLength+" icons found");
for(var i=0;i<removeIcons.snapshotLength;i++){
removeIcons.snapshotItem(i).style.cursor='pointer';
removeIcons.snapshotItem(i).addEventListener('mousedown', function(){
var village=parseInt(this.getAttribute("village"));
var event=parseInt(this.getAttribute("event"));
//alert("village: "+village+"; event: "+event);
removeEvent(village,event);
}, true);
}
}
function addResortCP(){
//alert("entering addRemoveEvent()");
var resortIcons=TM_searchDOM('//a[@id="TMResortCP"]');
//alert(resortIcons.snapshotLength+" icons found");
for(var i=0;i<resortIcons.snapshotLength;i++){
resortIcons.snapshotItem(i).style.cursor='pointer';
resortIcons.snapshotItem(i).addEventListener('mousedown', function(){
var sort=this.getAttribute("sort");
//alert("sort: "+sort);
showCPSuggestions.resortCPTable(sort);
}, true);
}
var skipIcons=TM_searchDOM('//a[@id="TMSkipCPEntry"]');
//alert(skipIcons.snapshotLength+" icons found");
for(var i=0;i<skipIcons.snapshotLength;i++){
skipIcons.snapshotItem(i).style.cursor='pointer';
skipIcons.snapshotItem(i).addEventListener('mousedown', function(){
var cpskip = new CPSkip();
cpskip.vID=this.getAttribute("vid");
cpskip.cpIndex=parseInt(this.getAttribute("cpsid"));
cpSkipList.add(cpskip);
showCPSuggestions.buildCPTable();
}, true);
}
var resetIcons=TM_searchDOM('//a[@id="TMResetSkips"]');
//alert(resetIcons.snapshotLength+" icons found");
for(var i=0;i<resetIcons.snapshotLength;i++){
resetIcons.snapshotItem(i).style.cursor='pointer';
resetIcons.snapshotItem(i).addEventListener('mousedown', function(){
cpSkipList.resetSkips();
showCPSuggestions.buildCPTable();
}, true);
}
}
//=================================
// Model (gathers info from the game)
function GetReferenceData(){
//refers to vlist table, it is the table on the right that lists all villages
this.vlistTable;
//refers to logout URL
this.logoutLink;
//logged user's ID
this.userID;
//server domain
this.server;
//current URL page (in address bar)
this.page;
this.get = function(){
//alert("entering GetReferenceData.get()");
// old SS1
this.vlistTable = this.getVlistTable();
//alert("GetReferenceData.vlistTable: "+this.vlistTable.snapshotItem(0));
//old SS2
this.logoutLink = this.getLogoutLink();
//alert("GetReferenceData.logoutLink: "+this.logoutLink.snapshotItem(0));
if (this.vlistTable.snapshotItem(0) && this.logoutLink.snapshotItem(0)){
// old X1, X1b, X1PlaceEqual
var tempuser1 = TM_searchDOM('//p/a[3]');
var tempuser2 = tempuser1.snapshotItem(0).toString();
var tempuser3PlaceEqual = tempuser2.indexOf("=");
// old User
this.userID = tempuser2.substring(tempuser3PlaceEqual,tempuser2.length);
//alert('Active User ID: '+ this.userID);
//old X2, X2b, X2PlaceEqual
var tempvillage1 = this.getActiveVillage();
//alert("Active Village URL:\n"+tempvillage1.snapshotItem(0));
var tempvillage2 = tempvillage1.snapshotItem(0).toString();
var tempvillage3PlaceEqual = tempvillage2.indexOf("=");
//alert('ok');
// old ActiveVillage
vInfo.activeVillageID = tempvillage2.substring(tempvillage3PlaceEqual+1,tempvillage2.length);
//alert('Active Village ID: '+ vInfo.activeVillageID );
// now we find active village ID
var tmpLocation = vInfo.activeVillageID.indexOf("&");
if (tmpLocation>2) { //alert('cut village number voor:' + vInfo.activeVillageID);
vInfo.activeVillageID = vInfo.activeVillageID.substring(0,tmpLocation); //alert('cut village number na :' + vInfo.activeVillageID);
}
//alert('Active Village ID: '+ vInfo.activeVillageID );
//now we must find out what's the active village's position (index) among villages list, that's necessary in some places to relate active village with villages array
vInfo.activeVillageIndex = this.getActiveVillageIndex();
//alert("vInfo.activeVillageIndex: "+vInfo.activeVillageIndex);
this.server = document.domain;
//alert("Server domain: "+this.server);
var splitDomain=this.server.split(".");
vInfo.serverLang=splitDomain[splitDomain.length-1];
//alert("vInfo.serverLang: "+vInfo.serverLang);
vInfo.uniqueID = this.server + '.' + this.userID + '.';
//alert("Unique ID:\n"+vInfo.uniqueID);
this.page = window.location.href;
//alert("Page URL (address bar):\n"+this.page);
switchLanguage();
//now let's count how many village this account has
//old SS3
var tempvillage10=this.getVillageCount();
vInfo.count = tempvillage10.snapshotLength;
//alert('You have '+vInfo.count+' villages' );
//now let's loop thru all village table's tr and get some info from all villages
for ( var i=0 ; i < vInfo.count; i++ ) {
//old X3, X3b, X3PlaceEqual
var tempvid1 = tempvillage10.snapshotItem(i).getAttribute("href");
//alert('villageID: ' + tempvid1);
var tempvid2 = tempvid1.toString();
var tempvid3PlaceEqual = tempvid2.indexOf("=");
//alert('tempvid3PlaceEqual: '+tempvid3PlaceEqual);
// old X4
var xcoord = this.getXcoord(i);
//alert('xcoord = '+xcoord.snapshotItem(i).innerHTML);
var ycoord = this.getYcoord(i);
//alert('ycoord = ' + ycoord.snapshotItem(i).innerHTML);
vInfo.rawVillageIDs[i] = tempvid2.substring(tempvid3PlaceEqual,tempvid2.length);
//alert('villageID: ' + vInfo.rawVillageIDs[i]);
vInfo.rawVillageIDs[i] = vInfo.rawVillageIDs[i].substring(1,vInfo.rawVillageIDs[i].length);
var tmpLocation = vInfo.rawVillageIDs[i].indexOf("&");
if (tmpLocation>2) {
vInfo.rawVillageIDs[i] = vInfo.rawVillageIDs[i].substring(0,tmpLocation);
}
//alert('vInfo.rawVillageIDs['+i+']: ' + vInfo.rawVillageIDs[i]);
// The following 2 lines instantiates a Village object, stores it in vInfo.vList[i], then add the village ID to that object
vInfo.vList[i]=new Village();
vInfo.vList[i].id=vInfo.uniqueID+vInfo.rawVillageIDs[i];
//alert("vInfo.vList["+i+"].id:\n"+vInfo.vList[i].id);
vInfo.vList[i].link = tempvillage10.snapshotItem(i).getAttribute("href");
//alert("vInfo.vList["+i+"].link = "+vInfo.vList[i].link);
vInfo.vList[i].name = tempvillage10.snapshotItem(i).innerHTML;
//alert("vInfo.vList["+i+"].name = "+vInfo.vList[i].name);
vInfo.vList[i].coords = xcoord.snapshotItem(i).innerHTML + '|' + ycoord.snapshotItem(i).innerHTML;
//alert("vInfo.vList["+i+"].coords = "+vInfo.vList[i].coords);
//alert("vInfo.vList["+i+"]info:\n\n"+vInfo.vList[i].toString());
}
}
}
this.getVlistTable = function(){
var lVlistTable = null;
//alert("GetReferenceData.getVlistTable()\nbrx, single village, Beyond 3.8.8.2 required");
lVlistTable = TM_searchDOM('//table[@class="vlist"]');
if(!lVlistTable){ return lVlistTable; }
//alert("GetReferenceData.getVlistTable()\nbrx, multiple village, Beyond 3.8.8.2 supported");
lVlistTable = TM_searchDOM('//table[@id="vlist"]');
if(!lVlistTable){ return lVlistTable; }
//alert("GetReferenceData.getVlistTable()\nvlistTable not found");
return lVlistTable;
}
this.getLogoutLink = function(){
var lLogoutLink=null;
lLogoutLink = TM_searchDOM('//a[@href="logout.php"]');
if(lLogoutLink.snapshotItem(0)){ return lLogoutLink; }
//alert("GetReferenceData.getLogoutLink()\n lLogoutLink not found");
return lLogoutLink;
}
this.getActiveVillage = function(){
var av = null;
//alert("GetReferenceData.getActiveVillage()\n brx, single village, Beyond 3.8.8.2 required");
av = TM_searchDOM("//td[@class='dot']/parent::tr/td[@class='text']/a[1]");
if(av.snapshotItem(0)){ return av; }
//alert("GetReferenceData.getActiveVillage()\nbrx, multiple village, Beyond 3.8.8.2 supported");
av = TM_searchDOM("//td[@class='dot hl']/parent::tr/td[@class='link']/a[1]");
if(av.snapshotItem(0)){ return av; }
//alert("GetReferenceData.getActiveVillage()\nbrx, multiple village, Beyond 3.8.8.2 supported, v2");
av = TM_searchDOM("//td[@class='dot hl']/parent::tr/td[@class='link']//a[1]");
if(av.snapshotItem(0)){ return av; }
//alert("GetReferenceData.getActiveVillage()\n activeVillage not found");
return lVlistTable;
}
this.getActiveVillageIndex = function(){
var index=null;
//alert("GetReferenceData.getActiveVillageIndex()\n brx, single village, Beyond 3.8.8.2 required");
index = TM_searchDOM('//table[@class="vlist"]/tbody/tr');
if(index.snapshotLength>0){
for(var i=0;i<index.snapshotLength;i++){
for(var j=0;j<index.snapshotItem(i).childNodes.length;j++){
//alert("index.snapshotItem("+i+").childNodes["+j+"].innerHTML:\n"+index.snapshotItem(i).childNodes[j].innerHTML);
if(index.snapshotItem(i).childNodes[j].className == "dot"){
return j;
break;
}
}
}
}
//alert("GetReferenceData.getActiveVillageIndex()\nbrx, multiple village, Beyond 3.8.8.2 supported");
index = TM_searchDOM('//table[@id="vlist"]/tbody/tr');
if(index.snapshotLength>0){
for(var i=0;i<index.snapshotLength;i++){
for(var j=0;j<index.snapshotItem(i).childNodes.length;j++){
//alert("index.snapshotItem("+i+").childNodes["+j+"].innerHTML:\n"+index.snapshotItem(i).childNodes[j].innerHTML);
if(index.snapshotItem(i).childNodes[j].className == "dot hl"){
return i;
break;
}
}
}
}
//alert("Active Village Index not found");
return 0;
}
this.getVillageCount = function(){
var count=0;
var villages;
//alert("GetReferenceData.getActiveVillageIndex()\nbrx, single village, Beyond 3.8.8.2 required");
villages=TM_searchDOM('//table[@class="vlist"]/tbody/tr/td[@class="text"]/a');
count=villages.snapshotLength;
if(count>0){ return villages; }
//alert("GetReferenceData.getActiveVillageIndex()\nbrx, multiple village, Beyond 3.8.8.2 supported");
villages=TM_searchDOM('//table[@id="vlist"]/tbody/tr/td[@class="link"]/a');
count=villages.snapshotLength;
if(count>0){ return villages; }
//alert("GetReferenceData.getActiveVillageIndex()\nbrx, multiple village, Beyond 3.8.8.2 supported v2");
villages=TM_searchDOM('//table[@id="vlist"]/tbody/tr/td[@class="link"]//a');
count=villages.snapshotLength;
if(count>0){ return villages; }
//alert("GetReferenceData.getActiveVillage()\n count not found");
return villages;
}
this.getXcoord = function(i){
var xcoord=null;
//alert("GetReferenceData.getXcoord()\nbrx, single village, Beyond 3.8.8.2 required");
xcoord = TM_searchDOM('//table[@class="vlist"]/tbody/tr/td[@class="x"]');
if(xcoord.snapshotItem(i)){ return xcoord; }
//alert("GetReferenceData.getXcoord()\n old T3 string");
xcoord = TM_searchDOM('//table[@id="vlist"]/tbody/tr/td[@class="aligned_coords"]/div[@class="cox"]');
if(xcoord.snapshotItem(i)){ return xcoord; }
//alert("GetReferenceData.getXcoord()\nbrx, multiple village, Beyond 3.8.8.2 supported");
xcoord = TM_searchDOM('//table[@id="vlist"]/tbody/tr/td[@class="aligned_coords"]//td[@class="cox"]');
if(xcoord.snapshotItem(i)){ return xcoord; }
//alert("GetReferenceData.getXcoord()\nvlistTable not found");
return xcoord;
}
this.getYcoord = function(i){
var ycoord=null;
//alert("GetReferenceData.getycoord()\nbrx, single village, Beyond 3.8.8.2 required");
ycoord = TM_searchDOM('//table[@class="vlist"]/tbody/tr/td[@class="y"]');
if(ycoord.snapshotItem(i)){ return ycoord; }
//alert("GetReferenceData.getycoord()\n old T3 string");
ycoord = TM_searchDOM('//table[@id="vlist"]/tbody/tr/td[@class="aligned_coords"]/div[@class="coy"]');
if(ycoord.snapshotItem(i)){ return ycoord; }
//alert("GetReferenceData.getycoord()\nbrx, multiple village, Beyond 3.8.8.2 supported");
ycoord = TM_searchDOM('//table[@id="vlist"]/tbody/tr/td[@class="aligned_coords"]//td[@class="coy"]');
if(ycoord.snapshotItem(i)){ return ycoord; }
//alert("GetReferenceData.getycoord()\nvlistTable not found");
return ycoord;
}
}
function GetResourceInfo(){
//refers to resources table, it is the horizontal list
this.resourcesTable;
this.activeVillage = new Village();
this.get = function(){
//alert("entering GetResourceInfo.get()");
var VillageResources = new Array();
// browses DOM for resources table (below icons)
// that path was the only one that worked, it goes directly to resources tds, but Travian Beyond brokes it, so we must browse back to the table and find the right one
this.resourcesTable = TM_searchDOM('//div[@id="res"]//tr/td').snapshotItem(0).parentNode.parentNode;
//alert("this.resourcesTable = "+this.resourcesTable);
var resourcesRow;
for(var i=0;i<5;i++){
if( (this.resourcesTable.childNodes[i].childNodes[3].getAttribute("title")) != null ){
//alert("it has, break");
resourcesRow = this.resourcesTable.childNodes[i];
break;
}else{
//alert("it doesnt have, continue");
}
}
this.resourcesTable=resourcesRow;
//alert("this.resourcesTable:\n\n\n"+this.resourcesTable.innerHTML);
//ok, now this.resourcesTable has the tr with all data we need, let's gather it! :D
this.activeVillage.id = vInfo.uniqueID + vInfo.activeVillageID;
//alert("Active Village ID:\n"+this.activeVillage.id);
this.activeVillage.resProduction.wood = parseInt(this.resourcesTable.childNodes[3].getAttribute("title"));
//alert("this.activeVillage.resProduction.wood = "+this.activeVillage.resProduction.wood);
this.activeVillage.resProduction.clay = parseInt(this.resourcesTable.childNodes[7].getAttribute("title"));
//alert("this.activeVillage.resProduction.clay = "+this.activeVillage.resProduction.clay);
this.activeVillage.resProduction.iron = parseInt(this.resourcesTable.childNodes[11].getAttribute("title"));
//alert("this.activeVillage.resProduction.iron = "+this.activeVillage.resProduction.iron);
this.activeVillage.resProduction.crop = parseInt(this.resourcesTable.childNodes[15].getAttribute("title"));
//alert("this.activeVillage.resProduction.crop = "+this.activeVillage.resProduction.crop);
//production is ready, now let's go to stock and capacity
var stockcapacityRaw = "";
var stockcapacity = "";
stockcapacityRaw = this.resourcesTable.childNodes[3].innerHTML;
stockcapacity = stockcapacityRaw.split("/");
this.activeVillage.resStock.wood = parseInt(stockcapacity[0]);
this.activeVillage.resCapacity.warehouse = parseInt(stockcapacity[1]);
stockcapacityRaw = this.resourcesTable.childNodes[7].innerHTML;
stockcapacity = stockcapacityRaw.split("/");
this.activeVillage.resStock.clay = parseInt(stockcapacity[0]);
stockcapacityRaw = this.resourcesTable.childNodes[11].innerHTML;
stockcapacity = stockcapacityRaw.split("/");
this.activeVillage.resStock.iron = parseInt(stockcapacity[0]);
stockcapacityRaw = this.resourcesTable.childNodes[15].innerHTML;
stockcapacity = stockcapacityRaw.split("/");
this.activeVillage.resStock.crop = parseInt(stockcapacity[0]);
this.activeVillage.resCapacity.granary = parseInt(stockcapacity[1]);
this.activeVillage.lastUpdated=getCurrentTime();
//alert("Active village info:\n\n"+this.activeVillage);
//we did it!! now we must store it inside GreaseMonkey to make it persistent
//alert(vInfo.uniqueID);
//alert(this.activeVillage);
var tempdata = this.activeVillage.storeData();
//alert(tempdata);
//alert(this.activeVillage);
//this.activeVillage.resStock.wood=-10; this.activeVillage.resProduction.wood=-10; this.activeVillage.resCapacity.warehouse=-10;
//alert(this.activeVillage);
// this.activeVillage.loadData();
//alert(this.activeVillage);
}
}
function GetBuildInfo(){
this.villageResourcesLayout;// = new VillageResourcesLayout(vInfo.activeVillageIndex);
this.villageBuildingsLayout;// = new VillageBuildingsLayoutvInfo.activeVillageIndex);
////this.resourcesFieldMap stores resources map, which has each field name, level, URL, etc
this.resourcesFieldMap;
//this.buildingsMap stores buildings map, which has each buildings name, level, URL, etc
this.buildingsMap;
this.get = function(){
//alert("entering GetBuildInfo.get()");
//alert("vInfo.activeVillageIndex: "+vInfo.activeVillageIndex);
this.villageResourcesLayout = new VillageResourcesLayout(vInfo.activeVillageIndex);
this.villageBuildingsLayout = new VillageBuildingsLayout(vInfo.activeVillageIndex);
//var ResourceIdentifiers = [2,3,14,15]; // wood/iron/crop/clay These are the build spots that are always the same regardless of village fields (4446,5346,9,15 cropper etc.)
var ResourceIdentifiers = [2,15,3,14]; // wood/clay/iron/crop These are the build spots that are always the same regardless of village fields (4446,5346,9,15 cropper etc.)
//old SS1
this.resourcesFieldMap = TM_searchDOM('//map[@name="rx"]//area');
//alert('this.resourcesFieldMap.snapshotItem(0):\n'+this.resourcesFieldMap.snapshotItem(0));
//alert('this.resourcesFieldMap.snapshotLength: '+this.resourcesFieldMap.snapshotLength);
//if the map is found (if we are on dorf1.php page), browse it and gather all info
if (this.resourcesFieldMap.snapshotItem(0)) {
//this code searches each kind of resource field, its objective is get their names to be able, using the strings created here, to identify later which is the resource type of each field
for (var i=0 ; i < this.resourcesFieldMap.snapshotLength - 1; i++) {
for (var j=0 ; j < ResourceIdentifiers.length; j++) {
if(i == ResourceIdentifiers[j]){
//alert("i="+i+" j="+j);
//ResourceIdentifiers stores part of resource fields names
ResourceIdentifiers[j] = this.resourcesFieldMap.snapshotItem(i).getAttribute("title").slice(0,8);
//alert("ResourceIdentifiers["+j+"]: "+ResourceIdentifiers[j]);
}
}
}
// if iron is clay 4,5,3,6 village fix
if(ResourceIdentifiers[2]==ResourceIdentifiers[1]){ResourceIdentifiers[2]=this.resourcesFieldMap.snapshotItem(10).getAttribute("title").slice(0,8);}
//alert("ResourceIdentifiers ok");
//alert("ResourceIdentifiers:\n"+ResourceIdentifiers);
// here we will loop thru all resource fields, and get position, lvl, name and type of each one
for (var i=0 ; i < this.resourcesFieldMap.snapshotLength - 1; i++) {
this.villageResourcesLayout.list[i].position=i+1;
var xTITLE = this.resourcesFieldMap.snapshotItem(i).getAttribute("title");
var ResourceIdentifier = xTITLE.slice(0,8);
//alert("i="+i+" xTITLE: "+xTITLE);
//alert("ResourceIdentifier: "+ResourceIdentifier);
this.villageResourcesLayout.list[i].setLvl( /(\d+)/.exec(xTITLE)[0] );
//alert("this.villageResourcesLayout.list["+i+"].lvl = "+this.villageResourcesLayout.list[i].lvl);
//alert("raw title:\n"+/(\d+)/.exec(xTITLE));
this.villageResourcesLayout.list[i].name = /([^]*)\s[^]+\s\d+$/.exec(xTITLE)[1];
//alert("this.villageResourcesLayout.list["+i+"].name = "+this.villageResourcesLayout.list[i].name);
// if (this.villageResourcesLayout.list[i].lvl){
if(ResourceIdentifier == ResourceIdentifiers[0]){this.villageResourcesLayout.list[i].type = 'g1';}
if(ResourceIdentifier == ResourceIdentifiers[1]){this.villageResourcesLayout.list[i].type = 'g2';}
if(ResourceIdentifier == ResourceIdentifiers[2]){this.villageResourcesLayout.list[i].type = 'g3';}
if(ResourceIdentifier == ResourceIdentifiers[3]){this.villageResourcesLayout.list[i].type = 'g4';}
/* }else{
//VillageLayout[i] = (i+1) + '/g00/0/NULL';
this.villageResourcesLayout.list[i].position=i+1;
this.villageResourcesLayout.list[i].setLvl(0);
this.villageResourcesLayout.list[i].type='g00';
this.villageResourcesLayout.list[i].name="NULL";
}
*/
//alert("this.villageResourcesLayout.list["+i+"]:\n"+this.villageResourcesLayout.list[i]+"\n\n\n"+this.villageResourcesLayout.list[i].merge());
}
//var GMvalue = this.villageResourcesLayout.merge();
//GM_setValue(this.villageResourcesLayout.getVillageResourcesLayoutID(),this.villageResourcesLayout.merge());
var GMvalue = this.villageResourcesLayout.storeData();
//alert("GMvalue:\n"+this.villageResourcesLayout.getVillageResourcesLayoutID()+"\n\n\n"+GMvalue);
//this.villageResourcesLayout.loadData();
//alert("this.villageResourcesLayout:\n\n"+this.villageResourcesLayout);
//alert("Village resource fields layout data stored on GreaseMonkey database");
/*
this.villageResourcesLayout.list[5].position=30;
this.villageResourcesLayout.list[5].setLvl(30);
this.villageResourcesLayout.list[5].type='g0';
this.villageResourcesLayout.list[5].name="fake field!!!";
alert("this.villageResourcesLayout changes:\n\n"+this.villageResourcesLayout);
//this.villageResourcesLayout.parse(GM_getValue(this.villageResourcesLayout.getVillageResourcesLayoutID()));
this.villageResourcesLayout.loadData();
alert("this.villageResourcesLayout fixed:\n\n"+this.villageResourcesLayout);
*/
}
//ok the code until here was related to dorf1.php to gather resource fields data, now we will go to dorf2.php and gather buildings data
//old SS1 (the same variable as before, it was used twice in the function)
this.buildingsMap = TM_searchDOM('//map[@name="map2"]//area');
//alert("this.buildingsMap.snapshotItem(0): "+this.buildingsMap.snapshotItem(0));
//alert('this.buildingsMap.snapshotLength: '+this.buildingsMap.snapshotLength);
//same as before, if the map is found (inside dorf2.php), browse it and gather all info
if (this.buildingsMap.snapshotItem(0)) {
//here in the old plugin it used to have a code with variable SS2 to get buildings pictures, but it seems that at some point (probably with T3.5), everything started using the same path "img/x.gif" and this wasn't possible anymore
//alert("this.buildingsMap.snapshotLength: "+this.buildingsMap.snapshotLength);
for ( var i=0 ; i < this.buildingsMap.snapshotLength-2; i++ ) { // -2 because of duplicate earth walls!! total 22 slots
this.villageBuildingsLayout.list[i].position=i+19;
this.villageBuildingsLayout.list[i].type="g9";
//xTITLE receives each building title property, which stores their name and lvl
var xTITLE = this.buildingsMap.snapshotItem(i).getAttribute("title");
//alert('i='+i+' xTITLE = '+xTITLE);
var rawLvl = /(\d+)/.exec(xTITLE);
if(rawLvl != null){
this.villageBuildingsLayout.list[i].setLvl( rawLvl[1] );
}else{
this.villageBuildingsLayout.list[i].setLvl(0);
}
//alert('this.villageBuildingsLayout.list['+i+'].lvl = '+this.villageBuildingsLayout.list[i].lvl);
if (this.villageBuildingsLayout.list[i].lvl>0){
var buildingName = /([^]*)\s[^]+\s\d+$/.exec(xTITLE); // still not quite right, but close
if(buildingName==null){
this.villageBuildingsLayout.list[i].name = xTITLE;
}else{
this.villageBuildingsLayout.list[i].name = buildingName[1];
}
}else{
this.villageBuildingsLayout.list[i].type="g00";
this.villageBuildingsLayout.list[i].name="NULL";
}
//alert('this.villageBuildingsLayout.list[i].name = '+this.villageBuildingsLayout.list[i].name);
//alert('this.villageBuildingsLayout.list['+i+']:\n\n'+this.villageBuildingsLayout.list[i]);
}
var GMvalue=this.villageBuildingsLayout.storeData();
//this.villageBuildingsLayout.loadData();
//alert("this.villageBuildingsLayout:\n\n"+this.villageBuildingsLayout);
/*
alert(GMvalue);
this.villageBuildingsLayout.list[5].position=30;
this.villageBuildingsLayout.list[5].setLvl(30);
this.villageBuildingsLayout.list[5].name="fake building!!";
alert("changed building:\n\n"+this.villageBuildingsLayout);
this.villageBuildingsLayout.loadData();
alert("fixed building:\n\n"+this.villageBuildingsLayout);
*/
}
/*
alert("ok");
this.villageResourcesLayout.loadData();
alert(this.villageResourcesLayout);
this.villageBuildingsLayout.loadData();
alert(this.villageBuildingsLayout);
*/
}
}
function AddListener(){
// this.clock refers to all images with a clock, this image is generally on upgrade pages
// these pages are each resource field/building page, where we see its info and have the option to upgrade it
// on these pages there is also this clock image and on its right we will have the upgrade duration time
// a clock is necessary for any timed event addition. so far.
this.clock;
this.clockCount = 0;
//this.links stores all links on the page
this.links;
// this.eventType stores if we are dealing with a resource field or a building
// 1: resource field (Dorf1)
// 2: building (Dorf2)
this.eventType;
// this.layout stores a resource field or a building layout, depending on the type of structure page we are on
this.layout;
//a construction info, got from Dorf layouts
this.eventInfo;
this.get = function(){
//alert("entering AddListener.get()");
//allVillagesEvents.purge();
//alert(allVillagesEvents);
this.clock = this.getClock();
//alert("this.clock.snapshotItem(0):\n"+this.clock.snapshotItem(0));
if(this.clock){
var clockCount=0;
var evt = new Event();
//old SS1
this.links = TM_searchDOM('//a[@href]');
//alert("links: "+this.links.snapshotLength);
for(var i=0;i<this.links.snapshotLength;i++){
//old xA
var currentLink = this.links.snapshotItem(i);
// Upgrade existing building links.
// these links are found when we enter on an existing construction's page, and we have enought resources to upgrade it
// this will be the link to upgrade the construction
// old X
var upgradeLink = /\?a=(\d+)&c=/.exec(currentLink.getAttribute("href"));
if(upgradeLink){
//alert("i="+i+" upgradeLink(case1)= "+upgradeLink);
var buildSport = upgradeLink[1];
if(buildSport<19){
this.eventType = 1;
this.layout = new VillageResourcesLayout(vInfo.activeVillageIndex);
}else{
this.eventType = 2;
this.layout = new VillageBuildingsLayout(vInfo.activeVillageIndex);
}
//alert("this.eventType = "+this.eventType);
var err = this.layout.loadData();
if(!err){ // possibility this doesn't exist yet, if not give warning that event wil not be recorded
var warn = addDiv('TMWarn' + i,'TMmain','I do not know this village yet.<br>' +
'Please go to <a href="dorf1.php">your fields<a/> and <a href="dorf2.php"> your village</a> 1st.<br>' +
'You only need this once so I know what is built.',false);
warn.style.right = '25px';
//alert("this.layout with error:\n\n"+this.layout);
return;
}
//alert("this.layout:\n\n"+this.layout);
//alert("this.layout.count="+this.layout.count);
//the following code gets a whole resource field/building layout
//it loops throu each structure looking for the structure whose position matches with BuildSpot
//then it stores this structure data array into eventInfo
for(var j=0;j<this.layout.count;j++){
if(this.layout.list[j].position==buildSport){
this.eventInfo=this.layout.list[j];
}
}
//this.eventInfo.position=30;
//alert("eventInfo:\n\n"+this.eventInfo);
evt = new Event();
evt.type=this.eventType;
evt.setUnformattedDuration(this.clock.snapshotItem(this.clock.snapshotLength-1).nextSibling.nodeValue); // should be last clock on the page. maybe.
evt.structure=this.eventInfo;
function innerCreateUpgradeEvent(){
evt.start=getCurrentTime()+5;
allVillagesEvents.addNewEvent(evt);
}
//alert(evt);
//innerCreateUpgradeEvent();
//alert(allVillagesEvents);
// upgrade link: the link to upgrade the building
currentLink.addEventListener('click', innerCreateUpgradeEvent, true);
}
// Construct new building links.
// these links are found when we enter on a unconstructed zone's page, available to construcing new buildings/fields
//there may be many of these links on those pages, there is one link for each building available to be newly constructed
// the following code loops thru all those links and add a listener to each of them, so that if the user decided to build a new building, modkit creates an event for it
var newConstructionLink = /\?a=(\d+)&id=\d+&c=/.exec(currentLink.getAttribute("href"));
if(newConstructionLink){
//alert("i="+i+" newConstructionLink= "+newConstructionLink);
evt = new Event();
evt.type=2;
evt.setUnformattedDuration(this.clock.snapshotItem(clockCount).nextSibling.nodeValue);
var constr = new Construction();
constr.position=newConstructionLink[1];
constr.type="g9";
constr.lvl=0;
//alert("building name:\n\n"+currentLink.parentNode.parentNode.parentNode.parentNode.previousSibling.previousSibling.innerHTML);
constr.name=currentLink.parentNode.parentNode.parentNode.parentNode.previousSibling.previousSibling.innerHTML;
evt.structure=constr;
//we created the event that will be added to allVillagesEvents, but now we must pass it into innerCreateConstructionEvent
//so we will merge it into a string and add it as a currentLink attribute, so that we can parse it back and get the event inside innerCreateConstructionEvent
var strEvent=evt.merge();
//alert("strEvent:\n"+strEvent);
currentLink.setAttribute('TMEvent20',strEvent);
function innerCreateConstructionEvent(){
var localEvent=new Event();
localEvent.parse(this.getAttribute('TMEvent20'));
//alert("AddListener.get().innerCreateConstructionEvent() has run\ncurrentLink: "+currentLink+"\n\n"+localEvent);
localEvent.start=getCurrentTime()+5;
allVillagesEvents.addNewEvent(localEvent);
}
// upgrade link: the link to upgrade the building
currentLink.addEventListener('click', innerCreateConstructionEvent, true);
clockCount++;
}
}
this.eventType=0;
//alert("this.eventType: "+this.eventType);
// The following snapshot appears on BARRACKS, STABLE, ARMORY, BLACKSMITH, ACADEMY, MARKET, TOWNHALL, and I assume Great Barracks and Great Stable
// THIS CODE IS BUGGED INSIDE MARCKET
this.links = TM_searchDOM('//input[@name="id"]');
//alert(this.links.snapshotLength+" troops links found");
if(this.links.snapshotItem(0)){
// this holds our building spot
var buildID = this.links.snapshotItem(0).getAttribute("value");
//alert("buildID: "+buildID);
// we have a record of what is built there
this.layout=new VillageBuildingsLayout(vInfo.activeVillageIndex);
this.layout.loadData(); //this may return invalid data if we haven't read village layout yet
//alert(this.layout);
for(var i=0;i<this.layout.count;i++){
if(this.layout.list[i].position==buildID){
if (this.layout.list[i].type == 'g19'){this.eventType = 3;} // g19 is barracks (not implemented yet)
if (this.layout.list[i].type == 'g20'){this.eventType = 4;} // g20 is stable (not implemented yet)
}
}
//alert("this.eventType: "+this.eventType);
// only interested in barracks and stable at the moment
// this is related to troops training
if (this.eventType == 3 || this.eventType == 4){
/*
//this input is the button to train troops
this.links = TM_searchDOM('//input[@name="s1"]');
var xINPUT = this.links.snapshotItem(0);
*/
}
}
} //end clocks if(this.clock)
//alert("ok after clock");
// special case demolish building, no timer until next page.
var demolish=this.getDemolishTable();
if(demolish.snapshotLength>0){
//alert(allVillagesEvents);
demolish=demolish.snapshotItem(0);
//alert(demolish.innerHTML);
/* old code, it used to create a button to add demolish event manually, I left it as a code exemple
var addBtn = addImg(false,false,Xadd,false);
addBtn.style.cursor='pointer';
addBtn.addEventListener('click', function() {
var table=this.parentNode.parentNode.parentNode.firstChild;
var buildingName = table.childNodes[3].innerHTML.replace(/^\s+|\s+$/g,""); //replace is used to trim the string
var timeleft = table.childNodes[5].childNodes[1].innerHTML;
var evt=new Event();
evt.type=5;
evt.start=getCurrentTime();
evt.setUnformattedDuration(timeleft);
evt.structure.position=19;
evt.structure.type="g9";
evt.structure.setLvl(/(\d+)/.exec(buildingName)[1]);
evt.structure.name=/([^]*)\s[^]+\s/.exec(buildingName)[1];
//alert(evt);
allVillagesEvents.addNewEvent(evt);
//alert(allVillagesEvents);
}, true);
var TR=document.createElement('TR');
demolish.appendChild(TR);
var TD=document.createElement('TD');
TR.appendChild(TD);
TD=document.createElement('TD');
TR.appendChild(TD);
TD=document.createElement('TD');
TR.appendChild(TD);
TD.appendChild(addBtn);
*/
// if demolish was found, it means there is something being demolished, so let's update it on event list
// first we must remove it in case it is already there
allVillagesEvents.removeDemolishEvent();
//alert("demolish event removed");
// now we can add it
//var table=this.parentNode.parentNode.parentNode.firstChild;
var table=demolish.firstChild;
var buildingName = table.childNodes[3].innerHTML.replace(/^\s+|\s+$/g,""); //replace is used to trim the string
var timeleft = table.childNodes[5].childNodes[1].innerHTML;
if(!timeleft) timeleft = table.childNodes[5].childNodes[0].innerHTML;
//alert("variables gathered");
//alert("table: "+table.innerHTML);
//alert("buildingName: "+buildingName);
//alert("timeleft: "+timeleft);
//alert(table.childNodes[5].childNodes[1].innerHTML);
var evt=new Event();
evt.type=3;
evt.start=getCurrentTime();
evt.setUnformattedDuration(timeleft);
//alert(evt);
evt.structure.position=19; //invalid data, to get correct position use <select class="dropdown" name="abriss"> values
evt.structure.type="g9";
evt.structure.setLvl(/(\d+)/.exec(buildingName)[1]);
evt.structure.name="(demolish) "+/([^]*)\s[^]+\s/.exec(buildingName)[1];
//alert(evt);
allVillagesEvents.addNewEvent(evt);
//alert(allVillagesEvents);
}
demolish=this.getDemolishSelect();
if(demolish.snapshotLength>0){
//alert(demolish.snapshotItem(0).innerHTML);
//if it was found, it means there is no demolition ocurring, meaning that or it was never initiated at all, or user just cancelled it
//in any case, let's remove any demolition even there may exist for this village and move on
allVillagesEvents.removeDemolishEvent();
//alert(allVillagesEvents);
}
/* Events refreshing
The following code is related to that + sign that is added on the side of construction on Dorf1 and Dorf1
Timers currently work this way:
- they are shared among troops movements and buildings
- all of them have that string showing its time left, and it is rounded by a span
- if there is only 1 of them (1 troop or 1 building), the span has id="timer1" regardless of what it is
- if there are 2 of them, with any combination, 1st building (the one that will complete fastest) will have id="timer1", and the other, being it another (roman) building or any troop, it will have id="timer2"
- if there are 2 roman buildings, the fastest will be timer1 and the other will be timer2, and any troop movement will have timer3 and so on
Here what we want is buildings, so we will look for timer1 and timer2
Since there may be 2 buildings and their code is the same, let's put it inside a method and call it twice
*/
this.refreshEvent(1);
this.refreshEvent(2);
// now we go to brand new events, first one is Blacksmith and Armoury troops upgrades and Town Hall celebrations
this.registerBmArm();
// Barrack, Stable and Workshop trainings
this.registerTrain();
//troops & mercants movements
this.registerMovements();
//if(allVillagesEvents.count()>0){
//alert(allVillagesEvents);
//}
//alert(allVillagesEvents.count()+"\n\n"+allVillagesEvents);
}
this.refreshEvent = function(timerNumber){
var timerQuery='//table[@id="building_contract"]//span[@id="timer1"]';
if(timerNumber==2) timerQuery='//table[@id="building_contract"]//span[@id="timer2"]';
var buildingTimer = TM_searchDOM(timerQuery);
if(buildingTimer.snapshotItem(0)){
//alert(buildingTimer.snapshotItem(0).innerHTML);
if (/dorf/.exec(window.location.href)){
var fullName = buildingTimer.snapshotItem(0).parentNode.previousSibling.innerHTML;
var constructName = /([^]*)\s[^]+\s/.exec(fullName)[1];
var baseName = fullName.slice(0,5);
//+alert("fullName: "+fullName+"\nconstructName: "+constructName+"\nbaseName: "+baseName);
var level = parseInt(/(\d+)/.exec(buildingTimer.snapshotItem(0).parentNode.previousSibling.innerHTML)[1])-1;
//alert("level: "+level);
function innerUpdateit(){
allVillagesEvents.loadData();
var eventIndex=allVillagesEvents.villages[vInfo.activeVillageIndex].findEvent(baseName);
//alert("eventIndex: "+eventIndex);
//alert("events BEFORE updating:\n\n"+allVillagesEvents);
if(eventIndex>=0){ //event exists, let's update it
allVillagesEvents.villages[vInfo.activeVillageIndex].events[eventIndex].structure.lvl=level;
allVillagesEvents.villages[vInfo.activeVillageIndex].events[eventIndex].start=getCurrentTime();
allVillagesEvents.villages[vInfo.activeVillageIndex].events[eventIndex].setUnformattedDuration(buildingTimer.snapshotItem(0).innerHTML);
allVillagesEvents.villages[vInfo.activeVillageIndex].storeData();
//alert(allVillagesEvents.villages[vInfo.activeVillageIndex]);
}else{ // well, event is not known yet, we may have lost its creation, or it may be troops timer
var evt=new Event();
evt.start=getCurrentTime();
evt.setUnformattedDuration(buildingTimer.snapshotItem(0).innerHTML);
evt.structure.lvl=level;
switch(constructName){
case xLang['Wood Field']:
evt.type=1;
evt.structure.position=1; //invalid data
evt.structure.type="g1";
break;
case xLang['Clay Field']:
evt.type=1;
evt.structure.position=1; //invalid data
evt.structure.type="g2";
break;
case xLang['Iron Field']:
evt.type=1;
evt.structure.position=1; //invalid data
evt.structure.type="g3";
break;
case xLang['Crop Field']:
evt.type=1;
evt.structure.position=1; //invalid data
evt.structure.type="g4";
break;
default:
evt.type=2;
evt.structure.position=18; //invalid data
evt.structure.type="g9";
}
//alert(evt);
evt.structure.name=constructName;
//alert(evt);
allVillagesEvents.addNewEvent(evt);
}
showEvents.buildEventsTable(false);
//window.location.href = window.location.href;
//allVillagesEvents.loadData();
//alert("events AFTER updating:\n\n"+allVillagesEvents);
}
var imgAdd = addImg(false,false,Xadd,false);
imgAdd.style.cursor='pointer';
imgAdd.style.left='3px';
imgAdd.addEventListener('click', innerUpdateit, true);
buildingTimer.snapshotItem(0).parentNode.appendChild(imgAdd);
}
}
}
// Blacksmith, Armoury, and also Town Hall celebrations
// there is no way (it seems) to distinguish these 3 buildgings, so I'll leave them all sharing the same event type
this.registerBmArm = function(){
//alert("entering AddListener.registerBmArm()");
var baUpgrades = this.getBmArmTable();
//alert("baUpgrades: "+baUpgrades);
if(baUpgrades){
for(var i=0;i<baUpgrades.length;i++){
//alert("baUpgrades["+i+"]: "+baUpgrades[i]);
if(baUpgrades[i].upgradeLink){
var evt = new Event();
evt.type=4;
evt.duration=baUpgrades[i].duration;
var element = new MiscElement();
element.element=baUpgrades[i].troopName+" (upgrd)";
evt.structure=element;
//alert("original event: "+evt+"\n\nmerged event: "+evt.merge());
//we created the event that will be added to allVillagesEvents, but now we must pass it into innerCreateConstructionEvent
//so we will merge it into a string and add it as a currentLink attribute, so that we can parse it back and get the event inside innerCreateConstructionEvent
var strEvent=evt.merge();
//alert("strEvent:\n"+strEvent);
baUpgrades[i].upgradeLink.setAttribute('TMEvent20',strEvent);
function innerBmArmEvent(){
var localEvent=new Event();
localEvent.parse(this.getAttribute('TMEvent20'));
//alert("AddListener.registerBmArm().innerBmArmEvent() has run\nupgradeLink: "+baUpgrades[i].upgradeLink+"\n\n"+localEvent);
localEvent.start=getCurrentTime()+5;
allVillagesEvents.addNewEvent(localEvent);
showEvents.buildEventsTable(false);
}
// upgrade link: the link to upgrade the building
baUpgrades[i].upgradeLink.addEventListener('click', innerBmArmEvent, true);
}
/*
//this code is to test the event, it simulates first link being clicked
if(i==0){
var localEvent=new Event();
localEvent.parse(baUpgrades[i].upgradeLink.getAttribute('TMEvent20'));
localEvent.start=getCurrentTime()+5;
allVillagesEvents.addNewEvent(localEvent);
alert(allVillagesEvents);
}
*/
}
var baProgress = this.getBmArmProgress();
//alert("baProgress: "+baProgress);
if(baProgress){
function innerBaUpdate(){
//alert("entering innerBaUpdate()");
var evt = new Event();
evt.type=4;
evt.duration=baProgress.duration;
evt.start=getCurrentTime();
var element = new MiscElement();
element.element=baProgress.troopName+" (upgrd)";
evt.structure=element;
//alert(evt);
allVillagesEvents.addNewEvent(evt);
showEvents.buildEventsTable(false);
}
var imgAdd = addImg(false,false,Xadd,false);
imgAdd.style.cursor='pointer';
imgAdd.style.left='3px';
imgAdd.addEventListener('click', innerBaUpdate, true);
baProgress.upgradeLink.appendChild(imgAdd);
}
}
}
// Barrack, Stable and Workshop trainings
this.registerTrain = function(){
//alert("entering AddListener.registerTrain()");
var trainTable = this.getTrainTable();
//alert("trainTable:\n\n"+trainTable);
if(!trainTable) return;
// verify if there is anything being trained
// if nothing was found training, skip update and go on
if(trainTable.isTraining){
//alert("entering if(trainTable.isTraining)");
// get all training events for current village
allVillagesEvents.loadData();
/*
var events=allVillagesEvents.villages[vInfo.activeVillageIndex].getEventOfType(5);
//alert("events: "+events.length);
// see if this building is logged
var trainEvent=-1;
for(var i=0;i<events.length;i++){
if(allVillagesEvents.villages[vInfo.activeVillageIndex].events[events[i]].structure.name==trainTable.building){
trainEvent=i;
break;
}
}
//alert("trainEvent: "+trainEvent);
// if nothing was found, this building is training but user doesn't want it logged, go on
// if building was found, update it without waiting for user intervation (automatically to user)
if(trainEvent>-1){
allVillagesEvents.villages[vInfo.activeVillageIndex].removeEvent(trainEvent);
//alert(allVillagesEvents);
*/
// if nothing was found, this building is training but user doesn't want it logged, go on
// if building was found, update it without waiting for user intervation (automatically to user)
var eventIsLogged = allVillagesEvents.villages[vInfo.activeVillageIndex].removeTrainingEvents(trainTable.building);
if(eventIsLogged){
var evt=new Event();
evt.type=5;
evt.start=getCurrentTime();
evt.duration=trainTable.duration;
var trainStructure=new Training();
trainStructure.name=trainTable.building;
trainStructure.troopName=trainTable.troopName;
evt.structure=trainStructure;
//alert("evt: "+evt);
allVillagesEvents.addNewEvent(evt);
//alert(allVillagesEvents);
//showEvents.buildEventsTable(false); // DON'T print events table now, showEvents is not ready yet!!
}
// now let's use a Xadd listerner
// this listener must remove any event there may exist, create a new one and add it
// user should need it only in case it removed this building event earlier and wants to add it again
// but in case any bug happened, it can be used to flosh any training event from this building and add a brand new one
function innerTrainingAdd(){
//alert("entering AddListener.registerTrain().innerTrainingAdd()");
allVillagesEvents.loadData();
/*
var events=allVillagesEvents.villages[vInfo.activeVillageIndex].getEventOfType(5);
//alert("events: "+events.length);
var trainEvent=-1;
for(var i=0;i<events.length;i++){
if(allVillagesEvents.villages[vInfo.activeVillageIndex].events[events[i]].structure.name==trainTable.building){
trainEvent=i;
break;
}
}
//alert("trainEvent: "+trainEvent);
if(trainEvent>-1)
allVillagesEvents.villages[vInfo.activeVillageIndex].removeEvent(trainEvent);
//alert(allVillagesEvents);
*/
allVillagesEvents.villages[vInfo.activeVillageIndex].removeTrainingEvents(trainTable.building);
var evt=new Event();
evt.type=5;
evt.start=getCurrentTime();
evt.duration=trainTable.duration;
var trainStructure=new Training();
trainStructure.name=trainTable.building;
trainStructure.troopName=trainTable.troopName;
evt.structure=trainStructure;
//alert("evt: "+evt);
allVillagesEvents.addNewEvent(evt);
//alert(allVillagesEvents);
showEvents.buildEventsTable(false);
}
var imgAdd = addImg(false,false,Xadd,false);
imgAdd.style.cursor='pointer';
imgAdd.style.left='3px';
imgAdd.addEventListener('click', innerTrainingAdd, true);
trainTable.addCell.appendChild(imgAdd);
}else{ // if(trainTable.isTraining)
// ok, we already dealt with any training that may have been found
// now we'll deal with train button, adding a listener to track new trainings
// tracking train button when there are troops being trained is not needed because they will be updated automatically anyway
// but if there is nothing being trained and user clicks train button, it is probable that he added troops, so we must start logging it
function innerTrainBtn(){
allVillagesEvents.loadData();
/*
var events=allVillagesEvents.villages[vInfo.activeVillageIndex].getEventOfType(5);
//alert("events: "+events.length);
var trainEvent=-1;
for(var i=0;i<events.length;i++){
if(allVillagesEvents.villages[vInfo.activeVillageIndex].events[events[i]].structure.name==trainTable.building){
trainEvent=i;
break;
}
}
//alert("trainEvent: "+trainEvent);
if(trainEvent>-1)
allVillagesEvents.villages[vInfo.activeVillageIndex].removeEvent(trainEvent);
*/
allVillagesEvents.villages[vInfo.activeVillageIndex].removeTrainingEvents(trainTable.building);
var evt=new Event();
evt.type=5;
evt.start=getCurrentTime();
evt.duration=-1;
var trainStructure=new Training();
trainStructure.name=trainTable.building;
trainStructure.troopName=trainTable.troopName;
evt.structure=trainStructure;
//alert("evt: "+evt);
allVillagesEvents.addNewEvent(evt);
//alert(allVillagesEvents);
//showEvents.buildEventsTable(false);
// note that this added event is not a valid event, it has duration = -1
// it is just a flag, to inform that a building that wasn't training (probably) started training now
// with this flag, on next reload ModKit will update this invalid event to a valid one based on the under_progress table that will be available then
}
trainTable.btnLink.addEventListener('click', innerTrainBtn, true);
// but this leaves us with an issues
// if user clicks the train button without selecting any troop to be training and there is nothing being trained, this new event will be added,
// but on next reload there will be nothing being trained to update, and he will have a new and already expired event to remove
// to avoid this, we must track train btn clicks that result in no trainings starting
// the flag for this is the evt.duration = -1, if there is no training AND there is an event with negative duration, we just remove it automatically
allVillagesEvents.loadData();
var events=allVillagesEvents.villages[vInfo.activeVillageIndex].getEventOfType(5);
//alert("events: "+events.length);
var trainEvent=-1;
for(var i=0;i<events.length;i++){
if(allVillagesEvents.villages[vInfo.activeVillageIndex].events[events[i]].structure.name==trainTable.building
&& allVillagesEvents.villages[vInfo.activeVillageIndex].events[events[i]].duration < 0){
trainEvent=i;
break;
}
}
//alert("trainEvent: "+trainEvent);
if(trainEvent>-1)
allVillagesEvents.villages[vInfo.activeVillageIndex].removeEvent(trainEvent);
}
}
this.registerMovements = function(){
//alert("entering AddListener.registerMovements()");
function innerMovement(){
//alert("entering innerMovement()");
var evt = new Event();
evt.parse(this.getAttribute("TMEvent"));
//alert(evt);
allVillagesEvents.addNewEvent(evt);
showEvents.buildEventsTable(false);
}
var mercant=this.getMercant();
//alert("mercant:\n\n"+mercant);
if(mercant){
for(var i=0;i<mercant.length;i++){
var element=new MiscElement();
element.element=mercant[i].name;
var evt=new Event();
evt.type=6;
evt.start=mercant[i].start;
evt.setUnformattedDuration(mercant[i].time);
evt.structure=element;
//alert(evt);
var imgAdd = addImg(false,false,Xadd,false);
imgAdd.style.cursor='pointer';
imgAdd.style.left='3px';
imgAdd.setAttribute("TMEvent",evt.merge());
imgAdd.addEventListener('click', innerMovement, true);
mercant[i].cell.appendChild(imgAdd);
}
}
var troops=this.getTroopMovement();
//alert("troops:\n\n"+troops);
if(troops){
for(var i=0;i<troops.length;i++){
var element=new MiscElement();
element.element=troops[i].name;
var evt=new Event();
evt.type=6;
evt.start=troops[i].start;
evt.setUnformattedDuration(troops[i].time);
evt.structure=element;
//alert(evt);
var imgAdd = addImg(false,false,Xadd,false);
imgAdd.style.cursor='pointer';
imgAdd.style.left='3px';
imgAdd.setAttribute("TMEvent",evt.merge());
imgAdd.addEventListener('click', innerMovement, true);
troops[i].cell.appendChild(imgAdd);
}
}
}
// getClock() tries to find images with a clock, this image is generally on upgrade pages
// these pages are each resource field/building page, where we see its info and have the option to upgrade it
// on these pages there is also this clock image and on its right we will have the upgrade duration time
this.getClock = function(){
var clock=null;
clock=TM_searchDOM('//img[@class="clock"]');
if(clock.snapshotItem(0)){ return clock; }
return clock;
}
this.getDemolishTable = function(){
//alert("entering AddListener.getDemolishTable()");
var demolish=null;
demolish=TM_searchDOM('//table[@id="demolish"]/tbody');
if(demolish.snapshotLength>0){ return demolish; }
return demolish;
}
this.getDemolishSelect = function(){
var demolish=null;
demolish=TM_searchDOM('//select[@name="abriss"]');
if(demolish.snapshotLength>0){ return demolish; }
return demolish;
}
this.getBmArmTable = function(){
//alert("entering AddListener.getBmArmTable()");
// if a train button is found, we are inside a Barrack/Stable/Workshop page, and not inside BlackSmith/Armoury
// both type of pages have the same HTML table structures, but only Barrack/Stable/Workshop pages have the train button
// then, if the train button is found, we are on the wrong place, so let's just leave
var trainBtn = TM_searchDOM('//input[@id="btn_train"]');
//alert("trainBtn: "+trainBtn.snapshotLength);
if(trainBtn.snapshotLength>0) return null;
// ok, there is no train button, now we see if table is found
// this page is used later, so we must check first if we are on the correct table, even if there is no upgrade link available
// if we are on the wrong page (train button is found or table is not found), we return null
// else, if we are on the right page but anything else is not found, we return an empty array, reporting it is the right page but no upgrade data was found
var buildDetailsTable = TM_searchDOM('//table[@class="build_details"]');
//alert("buildDetailsTable: "+buildDetailsTable.snapshotLength);
if(buildDetailsTable.snapshotLength<=0) return null;
// there are some rows that don't have upgrade links, this can be due of lack of resources for upgrading, because the buildings needs to be upgraded first or because this troop is fully upgraded
// since we only want available upgrades, first we find these upgrade links, then we browse back to their tr node and gether the other stuff
upgradeLink = TM_searchDOM('//table[@class="build_details"]/tbody/tr/td[@class="act"]/a');
//alert("upgradeLink: "+upgradeLink.snapshotLength);
//alert("upgradeLink: "+upgradeLink.snapshotItem(0).childNodes[0]);
if(upgradeLink.snapshotLength<=0) return new Array();
var bmArmList = new Array();
for(var i=0;i<upgradeLink.snapshotLength;i++){
var bmArm = new BmArmTable();
bmArm.upgradeLink=upgradeLink.snapshotItem(i);
var troopRow = bmArm.upgradeLink.parentNode.parentNode;
//alert("troopRow i="+i+":\n\n"+troopRow.innerHTML);
var troopName = TM_searchNode(troopRow,'td[@class="desc"]/div[@class="tit"]/a');
//alert("troopName: "+troopName.snapshotLength);
//alert("troopName: "+troopName.snapshotItem(0).innerHTML);
if(troopName.snapshotLength<=0) return new Array();
var lvl = TM_searchNode(troopRow,'td[@class="desc"]/div[@class="tit"]/span');
//alert("lvl: "+lvl.snapshotLength);
//alert("lvl: "+lvl.snapshotItem(0).innerHTML);
if(lvl.snapshotLength<=0) return new Array();
var duration = TM_searchNode(troopRow,'td[@class="desc"]/div[@class="details"]/span[5]');
//alert("duration: "+duration.snapshotLength);
//alert("duration: "+duration.snapshotItem(0).childNodes[1].nodeValue);
if(duration.snapshotLength<=0) return new Array();
bmArm.troopName=troopName.snapshotItem(0).innerHTML;
bmArm.lvl=parseInt(/(\d+)/.exec(lvl.snapshotItem(0).innerHTML)[0])+1;
bmArm.setUnformattedDuration(duration.snapshotItem(0).childNodes[1].nodeValue);
//alert("bmArm: "+bmArm);
bmArmList[bmArmList.length] = bmArm;
}
//alert("bmArmList:\n\n"+bmArmList);
return bmArmList;
}
this.getBmArmProgress = function(){
//alert("entering AddListener.getBmArmProgress()");
var troopName = TM_searchDOM('//table[@class="under_progress"]/tbody/tr/td[@class="desc"]');
//alert("troopName: "+troopName.snapshotLength);
//alert("troopName: "+troopName.snapshotItem(0).innerHTML);
//alert("troopName: "+trim(troopName.snapshotItem(0).childNodes[2].nodeValue));
if(troopName.snapshotLength<=0) return null;
var duration = TM_searchDOM('//table[@class="under_progress"]/tbody/tr/td[@class="dur"]/span');
//alert("duration: "+duration.snapshotLength);
//alert("duration: "+duration.snapshotItem(0).innerHTML);
if(duration.snapshotLength<=0) return null;
var upgradeLink = TM_searchDOM('//table[@class="under_progress"]/tbody/tr/td[@class="dur"]');
//alert("upgradeLink: "+upgradeLink.snapshotLength);
//alert("upgradeLink: "+upgradeLink.snapshotItem(0).innerHTML);
if(upgradeLink.snapshotLength<=0) return null;
var bmArm = new BmArmTable();
//alert("raw bmArm: "+bmArm);
// although the under_progress table is the same for Blacksmith, Armoury and Town Hall,
// BM and Arm shows a pic together with the name, while TH shows only a raw name
// because of that we must deal with this detail separately
// if we find more than 1 node inside troop cell, we skip pic node and get only the name
// and if we don't find this extra node, so we are on TH, then we just get the only node available
if(troopName.snapshotItem(0).childNodes[2]){
bmArm.troopName=trim(troopName.snapshotItem(0).childNodes[2].nodeValue);
}else{
bmArm.troopName=troopName.snapshotItem(0).innerHTML;
}
//bmArm.troopName=trim(troopName.snapshotItem(0).childNodes[2].nodeValue);
//bmArm.troopName=troopName.snapshotItem(0).innerHTML;
bmArm.setUnformattedDuration(duration.snapshotItem(0).innerHTML);
bmArm.upgradeLink=upgradeLink.snapshotItem(0); // upgradeLink is being used to get the element (duration td) where Xadd will be added
//alert("filled bmArm: "+bmArm);
return bmArm;
}
// AddListener.getTrainTable() works inside Barrack, Stable and Workshop buildings
// it searches for the train button, if it is not found we are not on any of these buildings and it returns
// if it is found, there are 2 possibilities: there is some troop being trained, or there is nothing being trained ATM
// if there is nothing being trained, training.isTraining is set false and training is returned almost empty (and all empty values must be ignored)
// if under_progress table is found, its last row t(he last training troop) is gathered and returned
this.getTrainTable = function(){
//alert("entering AddListener.getTrainTable()");
var trainBtn = TM_searchDOM('//input[@id="btn_train"]');
//alert("trainBtn: "+trainBtn.snapshotLength);
if(trainBtn.snapshotLength<1) return null;
var building = TM_searchDOM('//h1');
//alert("building length: "+building.snapshotLength);
//alert("building: "+building.snapshotItem(0).innerHTML);
//alert("building final: "+/([^]*)\s[^]+\s\d+$/.exec(building.snapshotItem(0).innerHTML)[1]);
var troopName = TM_searchDOM('//table[@class="under_progress"]/tbody/tr[last()-1]/td[@class="desc"]');
//alert("troopName length: "+troopName.snapshotLength);
//alert("troopName: "+troopName.snapshotItem(0).innerHTML);
var duration = TM_searchDOM('//table[@class="under_progress"]/tbody/tr[last()-1]/td[@class="dur"]/span');
//alert("duration length: "+duration.snapshotLength);
//alert("duration: "+duration.snapshotItem(0).innerHTML);
var finCell = TM_searchDOM('//table[@class="under_progress"]/tbody/tr[last()-1]/td[@class="fin"]');
//alert("finCell length: "+finCell.snapshotLength);
//alert("finCell: "+finCell.snapshotItem(0).innerHTML);
var training = new TrainTable();
//alert("raw training:\n\n"+training);
training.btnLink = trainBtn.snapshotItem(0);
training.building = /([^]*)\s[^]+\s\d+$/.exec(building.snapshotItem(0).innerHTML)[1];
if(troopName.snapshotLength>0){
training.isTraining=true;
training.troopName = troopName.snapshotItem(0).innerHTML;
training.setUnformattedDuration(duration.snapshotItem(0).innerHTML);
training.addCell=finCell.snapshotItem(0);
}else{
training.isTraining=false;
}
//alert("filled training:\n\n"+training);
return training;
}
this.getMercant = function(){
//alert("entering AddListener.getMercant()");
var mercantTime = TM_searchDOM('//table[@class="traders"]//div[@class="in"]/span');
//alert("mercantTime: "+mercantTime.snapshotLength);
//alert("mercantTime: "+mercantTime.snapshotItem(0).innerHTML);
if(mercantTime.snapshotLength<1) return null;
var mercantCell = TM_searchDOM('//table[@class="traders"]//div[@class="in"]');
//alert("mercantCell: "+mercantCell.snapshotLength);
//alert("mercantCell: "+mercantCell.snapshotItem(0).innerHTML);
if(mercantCell.snapshotLength<1) return null;
var mercantDesc = TM_searchDOM('//table[@class="traders"]/thead/tr/td[2]/a[1]');
//alert("mercantDesc: "+mercantDesc.snapshotLength);
//alert("mercantDesc: "+mercantDesc.snapshotItem(0).innerHTML);
if(mercantDesc.snapshotLength<1) return null;
var mercant = new Array();
for(var i=0;i<mercantCell.snapshotLength;i++){
var move=new Movement();
move.name=mercantDesc.snapshotItem(i).innerHTML.substring(0,25);
move.time=mercantTime.snapshotItem(i).innerHTML;
move.cell=mercantCell.snapshotItem(i);
move.start=getCurrentTime();
mercant.push(move);
}
//alert("mercant:\n\n"+mercant);
return mercant;
}
this.getTroopMovement = function(){
//alert("entering AddListener.getTroopMovement()");
// these tables are inside Rally Point page
// they currently may have 2 class values: 'in small' for troops recently sent and that can still be brought back, and 'in' for troops that can't come back anymore
// due to that we must make 2 searches
var troopTime = TM_searchDOM('//table[@class="troop_details"]//div[@class="in"]/span');
//alert("troopTime: "+troopTime.snapshotLength);
//alert("troopTime: "+troopTime.snapshotItem(0).innerHTML);
var troopTimeNew = TM_searchDOM('//table[@class="troop_details"]//div[@class="in small"]/span');
//alert("troopTimeNew: "+troopTimeNew.snapshotLength);
//alert("troopTimeNew: "+troopTimeNew.snapshotItem(0).innerHTML);
if( (troopTime.snapshotLength + troopTimeNew.snapshotLength) <1) return null;
var troop = new Array();
for(var i=0;i<troopTime.snapshotLength;i++){
var move=new Movement();
move.time=troopTime.snapshotItem(i).innerHTML;
move.start=getCurrentTime();
move.cell=troopTime.snapshotItem(i).parentNode;
var table=troopTime.snapshotItem(i).parentNode.parentNode.parentNode.parentNode.parentNode;
//alert("table i="+i+":\n\n\n"+table.innerHTML);
var name=table.childNodes[1].childNodes[1].childNodes[2].childNodes[0];
//alert("name:\n\n"+name.innerHTML);
move.name=name.innerHTML;
//alert(move);
troop.push(move);
}
for(var i=0;i<troopTimeNew.snapshotLength;i++){
var move=new Movement();
move.time=troopTimeNew.snapshotItem(i).innerHTML;
move.start=getCurrentTime();
move.cell=troopTimeNew.snapshotItem(i).parentNode;
var table=troopTimeNew.snapshotItem(i).parentNode.parentNode.parentNode.parentNode.parentNode;
//alert("table i="+i+":\n\n\n"+table.innerHTML);
var name=table.childNodes[1].childNodes[1].childNodes[2].childNodes[0];
//alert("name:\n\n"+name.innerHTML);
move.name=name.innerHTML;
//alert(move);
troop.push(move);
}
//alert("troop:\n\n"+troop);
return troop;
}
}
//=================================
// View (presents/prints info to the user)
// ›› Show total Village resource production, overlayed over left menu bar.
function ShowTotalProduction(){
//div that stores left table with general resources info
this.generalDiv;
//div that stores villages table, on the right
//this.villagesDiv;
//villages table's HTML code
this.villagesTable;
//div where tables' divs are attached into
this.attachDiv = 'side_navi';
this.show = function(){
//alert("entering ShowTotalProduction.show()");
vInfo.reloadData();
//alert(vInfo);
//alert('ok after resources, before table');
var generalProdHTML = '<table width="100%" cellpadding="4" cellspacing="0" border="0">' +
'<tr><td colspan=2 class="TTitle">' + vInfo.count + ' Villages</td></tr>';
generalProdHTML += '<tr><td colspan=2 class="TTitle">++ Production</td></tr>' +
'<tr class="TWoodBack"><td>Wood</td><td class="right">' + vInfo.totalProduction.woodf() + '</td></tr>' +
'<tr class="TClayBack"><td>Clay</td><td class="right">' + vInfo.totalProduction.clayf() + '</td></tr>' +
'<tr class="TIronBack"><td>Iron</td><td class="right">' + vInfo.totalProduction.ironf() + '</td></tr>' +
'<tr class="TCropBack"><td>Crop</td><td class="right">' + vInfo.totalProduction.cropf() + '</td></tr>' +
'<tr><td colspan=2 class="TTitle">++ Resources</td></tr>' +
'<tr class="TWoodBack"><td>Wood</td><td class="right">' + vInfo.totalStock.woodf() + '</td></tr>' +
'<tr class="TClayBack"><td>Clay</td><td class="right">' + vInfo.totalStock.clayf() + '</td></tr>' +
'<tr class="TIronBack"><td>Iron</td><td class="right">' + vInfo.totalStock.ironf() + '</td></tr>' +
'<tr class="TCropBack"><td>Crop</td><td class="right">' + vInfo.totalStock.cropf() + '</td></tr>' +
'<tr><td colspan=2 class="TTitle">++ Storage</td></tr>' +
'<tr class="TClayBack"><td><span style="font-size:0.8em;">Warehouse</span></td><td class="right">' + vInfo.totalCapacity.warehousef() + '</td></tr>' +
'<tr class="TCropBack"><td>Granary</td><td class="right">' + vInfo.totalCapacity.granaryf() + '</td></tr>' +
'<tr><td colspan=2 class="TTitle">++ Filled</td></tr>' +
'<tr class="TWoodBack"><td>Wood</td><td class="right">' + vInfo.totalFilled.wood.toFixed(0) + '%</td></tr>' +
'<tr class="TClayBack"><td>Clay</td><td class="right">' + vInfo.totalFilled.clay.toFixed(0) + '%</td></tr>' +
'<tr class="TIronBack"><td>Iron</td><td class="right">' + vInfo.totalFilled.iron.toFixed(0) + '%</td></tr>' +
'<tr class="TCropBack"><td>Crop</td><td class="right">' + vInfo.totalFilled.crop.toFixed(0) + '%</td></tr>' +
'<tr><td colspan=2 class="TTitle">Production Factor</td></tr>' +
'<tr class="TWoodBack"><td>Wood</td><td class="right">' + vInfo.productionFactor.woodf() + '</td></tr>' +
'<tr class="TClayBack"><td>Clay</td><td class="right">' + vInfo.productionFactor.clayf() + '</td></tr>' +
'<tr class="TIronBack"><td>Iron</td><td class="right">' + vInfo.productionFactor.ironf() + '</td></tr>' +
'<tr class="TCropBack"><td>Crop</td><td class="right">' + vInfo.productionFactor.cropf() + '</td></tr>' +
'</table>';
var generalProdPosRaw=GM_getValue(vInfo.uniqueID+"DragWin.generalProd");
var generalProdPosTop="95px";
var generalProdPosLeft="0px";
if(generalProdPosRaw){
generalProdPosSplit=generalProdPosRaw.split(":");
generalProdPosTop=generalProdPosSplit[0];
generalProdPosLeft=generalProdPosSplit[1];
}else{
GM_setValue(vInfo.uniqueID+"DragWin.generalProd",generalProdPosTop+":"+generalProdPosLeft);
}
var body, generalProdWin, generalProdTitlebar, generalProdtiTlehead,generalProdContent,
generalProdStatusbar, generalProdAclose, generalProdAhide, generalProdAminimax;
body = document.getElementsByTagName('body')[0];
generalProdWin = document.createElement('DIV');
generalProdWin.id='generalProd';
generalProdWin.className='DW_window';
generalProdWin.style.width="140px";
generalProdWin.style.top=generalProdPosTop;
generalProdWin.style.left=generalProdPosLeft;
generalProdTitlebar = document.createElement('DIV');
generalProdTitlebar.className='titlebar';
generalProdWin.appendChild(generalProdTitlebar);
generalProdtiTlehead = document.createElement('H2');
generalProdtiTlehead.innerHTML='General';
generalProdTitlebar.appendChild(generalProdtiTlehead);
generalProdAclose = document.createElement('A');
generalProdAclose.title="Close";
generalProdAclose.id="close";
generalProdAclose.addEventListener('mouseup', function(){ DW_closeWindow(generalProdAclose); }, false);
generalProdAclose.innerHTML='x';
generalProdTitlebar.appendChild(generalProdAclose);
/*
generalProdAhide = document.createElement('A');
generalProdAhide.title="Hide";
generalProdAhide.id="hide";
generalProdAhide.addEventListener('mouseup', function(){ DW_hideWindow(generalProdAhide); }, false);
generalProdAhide.innerHTML='^';
generalProdTitlebar.appendChild(generalProdAhide);
*/
generalProdAminimax = document.createElement('A');
generalProdAminimax.title="Minimize";
generalProdAminimax.id="minimax";
generalProdAminimax.addEventListener('mouseup', function(){ DW_minimax(generalProdAminimax); }, false);
generalProdAminimax.innerHTML='-';
generalProdTitlebar.appendChild(generalProdAminimax);
generalProdContent = document.createElement('DIV');
generalProdContent.className='content';
generalProdWin.appendChild(generalProdContent);
generalProdStatusbar = document.createElement('DIV');
generalProdStatusbar.className='statusbar';
generalProdStatusbar.innerHTML='statusbar .:';
generalProdWin.appendChild(generalProdStatusbar);
generalProdContent.innerHTML = generalProdHTML;
body.appendChild(generalProdWin);
generalProdWin.addEventListener('mousedown', function(){ DW_startDrag(generalProdWin); }, false);
generalProdWin.addEventListener('mouseup', DW_stopDrag, false);
generalProdWin.addEventListener('mousemove', function(event) { DW_moving(event); }, false);
// we just created the window, it is not minimized ATM
// but if it should be, we call the function to minimize it
if(DW_isMinimized(generalProdWin)){
DW_setMinimized(generalProdAminimax,true);
}
// we also must check if it should be closed, closing it if that's the case
if(DW_isClosed(generalProdWin)){
DW_closeWindow(generalProdAclose);
}
//this.generalDiv = addDiv('TMleftmenu','TMleftmenu',HTML,this.attachDiv);
//this.generalDiv.addEventListener('click', function() {
//this.parentNode.removeChild(this);}, true);
//alert("ok after table 1");
var villagesDataPosRaw=GM_getValue(vInfo.uniqueID+"DragWin.villagesData");
var villagesDataPosTop="29px";
var villagesDataPosLeft=(document.body.clientWidth-164)+"px";
if(villagesDataPosRaw){
villagesDataPosSplit=villagesDataPosRaw.split(":");
villagesDataPosTop=villagesDataPosSplit[0];
villagesDataPosLeft=villagesDataPosSplit[1];
}else{
GM_setValue(vInfo.uniqueID+"DragWin.villagesData",villagesDataPosTop+":"+villagesDataPosLeft);
}
var body, villagesDataWin, villagesDataTitlebar, villagesDatatiTlehead,villagesDataContent,
villagesDataStatusbar, villagesDataAclose, villagesDataAhide, villagesDataAminimax;
body = document.getElementsByTagName('body')[0];
villagesDataWin = document.createElement('DIV');
villagesDataWin.id='villagesData';
villagesDataWin.className='DW_window';
villagesDataWin.style.width="160px";
villagesDataWin.style.top=villagesDataPosTop;
villagesDataWin.style.left=villagesDataPosLeft;
villagesDataTitlebar = document.createElement('DIV');
villagesDataTitlebar.className='titlebar';
villagesDataWin.appendChild(villagesDataTitlebar);
villagesDatatiTlehead = document.createElement('H2');
villagesDatatiTlehead.innerHTML='Villages';
villagesDataTitlebar.appendChild(villagesDatatiTlehead);
villagesDataAclose = document.createElement('A');
villagesDataAclose.title="Close";
villagesDataAclose.id="close";
villagesDataAclose.addEventListener('mouseup', function(){ DW_closeWindow(villagesDataAclose); }, false);
villagesDataAclose.innerHTML='x';
villagesDataTitlebar.appendChild(villagesDataAclose);
/*
villagesDataAhide = document.createElement('A');
villagesDataAhide.title="Hide";
villagesDataAhide.id="hide";
villagesDataAhide.addEventListener('mouseup', function(){ DW_hideWindow(villagesDataAhide); }, false);
villagesDataAhide.innerHTML='^';
villagesDataTitlebar.appendChild(villagesDataAhide);
*/
villagesDataAminimax = document.createElement('A');
villagesDataAminimax.title="Minimize";
villagesDataAminimax.id="minimax";
villagesDataAminimax.addEventListener('mouseup', function(){ DW_minimax(villagesDataAminimax); }, false);
villagesDataAminimax.innerHTML='-';
villagesDataTitlebar.appendChild(villagesDataAminimax);
villagesDataContent = document.createElement('DIV');
villagesDataContent.className='content';
villagesDataWin.appendChild(villagesDataContent);
villagesDataStatusbar = document.createElement('DIV');
villagesDataStatusbar.className='statusbar';
villagesDataStatusbar.innerHTML='statusbar .:';
villagesDataWin.appendChild(villagesDataStatusbar);
//this.villagesDiv = addDiv('VillagesTable','TMleftmenu',this.villagesTable,this.attachDiv);
//this.villagesDiv.style.left = villagesTableLeftCoord;
//var villagesDiv;
var villagesTable = "";
//villagesDiv = addDiv('HikariMenu','TMleftmenu',villagesTable,this.attachDiv);
//villagesDiv.style.left = villagesTableLeftCoord;
//alert("villagesTable instantiation ok");
villagesDataContent.addEventListener('click', function() {
switch(vInfo.getTableStatus()){
case 1:
vInfo.setTableStatus(2);
editVillagesTable();
break;
case 2:
vInfo.setTableStatus(3);
editVillagesTable();
break;
case 3:
vInfo.setTableStatus(4);
editVillagesTable();
break;
case 4:
vInfo.setTableStatus(8);
editVillagesTable();
break;
case 8:
if(debugMode){
vInfo.setTableStatus(1); // change to 9 if status 9 is desired
editVillagesTable();
break;
}
case 9:
vInfo.setTableStatus(1);
editVillagesTable();
break;
default:
vInfo.setTableStatus(1);
editVillagesTable();
}
}, true);
/*
Status info:
status 1: showns stock, but only if it is above vInfo.maxcap
status 2: percentage filled
status 3: free available space on warehouse/granary
status 8: debug, last time each village was visited
status 9: only table title shown
*/
function editVillagesTable(){
//alert("entering ShowTotalProduction.show().editVillagesTable()");
switch(vInfo.getTableStatus()){
case 1:
villagesDataStatusbar.innerHTML='overflowing .:1';
break;
case 2:
villagesDataStatusbar.innerHTML='current stock .:2';
break;
case 3:
villagesDataStatusbar.innerHTML='stock percentage .:3';
break;
case 4:
villagesDataStatusbar.innerHTML='free available space .:4';
break;
case 8:
villagesDataStatusbar.innerHTML='last visited .:8';
break;
case 9:
villagesDataStatusbar.innerHTML='nothing shown .:9';
break;
default:
villagesDataStatusbar.innerHTML='statusbar .:';
}
villagesTable = '<table width="100%" cellpadding="4" cellspacing="0" border="0">';
//+ '<tr><td colspan="2" class="TTitle"> </td></tr>';
//alert(vInfo.getTableStatus());
//villagesTable += '<tr><td colspan=2 class="TTitle">'+ 'testing' + '</td></tr>';
for (var i = 0; i < vInfo.count; i++){
if(vInfo.getTableStatus()!=9){
// villagesTable += '<tr><td colspan=2 class="TTitle">++ Village '+ (i+1) +'</td></tr>' +
if(vInfo.getTableStatus()==3){
villagesTable += '<tr><td colspan=2 class="TTitle">'+ vInfo.vList[i].name + '</td></tr>';
villagesTable += '<tr style="background:#AAAAAA;"><td>Warehouse </td><td class="right">' + vInfo.vList[i].resCapacity.warehousef() + '</td></tr>';
villagesTable += '<tr class="TWoodBack"><td>Wood</td><td class="right">' + vInfo.vList[i].resFilled.wood.toFixed(0) + '%</td></tr>';
villagesTable += '<tr class="TClayBack"><td>Clay</td><td class="right">' + vInfo.vList[i].resFilled.clay.toFixed(0) + '%</td></tr>';
villagesTable += '<tr class="TIronBack"><td>Iron</td><td class="right">' + vInfo.vList[i].resFilled.iron.toFixed(0) + '%</td></tr>';
villagesTable += '<tr class="TCropBack"><td>Crop</td><td class="right">' + vInfo.vList[i].resFilled.crop.toFixed(0) + '%</td></tr>';
}else if(vInfo.getTableStatus()==4){
villagesTable += '<tr><td colspan=2 class="TTitle">'+ vInfo.vList[i].name + '</td></tr>';
villagesTable += '<tr style="background:#AAAAAA;"><td>Warehouse </td><td class="right">' + vInfo.vList[i].resCapacity.warehousef() + '</td></tr>';
villagesTable += '<tr class="TWoodBack"><td>Wood</td><td class="right">-' + vInfo.vList[i].resLeft.woodf() + '</td></tr>';
villagesTable += '<tr class="TClayBack"><td>Clay</td><td class="right">-' + vInfo.vList[i].resLeft.clayf() + '</td></tr>';
villagesTable += '<tr class="TIronBack"><td>Iron</td><td class="right">-' + vInfo.vList[i].resLeft.ironf() + '</td></tr>';
villagesTable += '<tr class="TCropBack"><td>Crop</td><td class="right">-' + vInfo.vList[i].resLeft.cropf() + '</td></tr>';
villagesTable += '<tr class="TCropBack"><td>Crop</td><td class="right">' + vInfo.vList[i].resFilled.crop.toFixed(0) + '%</td></tr>';
}else if(vInfo.getTableStatus()==8){
villagesTable += '<tr><td colspan=2 class="TTitle">'+ vInfo.vList[i].name + '</td></tr>';
villagesTable += '<tr style="background:#AAAAAA;"><td class="center">'+vInfo.vList[i].getLastUpdatedAgo(true)+'</td></tr>';
}else{ // if ==2
if(vInfo.vList[i].resFull.any || vInfo.vList[i].resFull.crop || vInfo.getTableStatus()==2) villagesTable += '<tr><td colspan=2 class="TTitle">'+ vInfo.vList[i].name + '</td></tr>';
if(vInfo.vList[i].resFull.any || vInfo.getTableStatus()==2) villagesTable += '<tr style="background:#AAAAAA;"><td>Warehouse </td><td class="right">' + vInfo.vList[i].resCapacity.warehousef() + '</td></tr>';
if(vInfo.vList[i].resFull.wood || vInfo.getTableStatus()==2) villagesTable += '<tr class="TWoodBack"><td>Wood</td><td class="right">' + vInfo.vList[i].getCurrentStockWood(true) + '</td></tr>';
if(vInfo.vList[i].resFull.clay || vInfo.getTableStatus()==2) villagesTable += '<tr class="TClayBack"><td>Clay</td><td class="right">' + vInfo.vList[i].getCurrentStockClay(true) + '</td></tr>';
if(vInfo.vList[i].resFull.iron || vInfo.getTableStatus()==2) villagesTable += '<tr class="TIronBack"><td>Iron</td><td class="right">' + vInfo.vList[i].getCurrentStockIron(true) + '</td></tr>';
if(vInfo.vList[i].resFull.crop || vInfo.getTableStatus()==2) villagesTable += '<tr class="TCropBack"><td>Crop</td><td class="right">' + vInfo.vList[i].getCurrentStockCrop(true) + '</td></tr>';
if(vInfo.vList[i].resFull.crop || vInfo.getTableStatus()==2) villagesTable += '<tr class="TCropBack"><td>Granary</td><td class="right">' + vInfo.vList[i].resCapacity.granaryf() + '</td></tr>';
}
}
}
villagesTable += '<tr><td colspan=2 class="TTitle"> </td></tr>';
villagesTable += '</table>';
villagesDataContent.innerHTML=villagesTable;
}
editVillagesTable();
villagesDataContent.innerHTML = villagesTable;
body.appendChild(villagesDataWin);
villagesDataTitlebar.addEventListener('mousedown', function(){ DW_startDrag(villagesDataWin); }, false);
villagesDataTitlebar.addEventListener('mouseup', DW_stopDrag, false);
villagesDataTitlebar.addEventListener('mousemove', function(event) { DW_moving(event); }, false);
// we just created the window, it is not minimized ATM
// but if it should be, we call the function to minimize it
if(DW_isMinimized(villagesDataWin)){
DW_setMinimized(villagesDataAminimax,true);
}
// we also must check if it should be closed, closing it if that's the case
if(DW_isClosed(villagesDataWin)){
DW_closeWindow(villagesDataAclose);
}
//alert('ok after table 2');
//alert(addSeparatorsNF(100000,",",",","."));
//alert(vInfo.vList[0].resCapacity.granaryf());
}
}
// The new ShowEvents creates a brand new table to show events to the user
// I decided to take events showing off of villages table so that we have enough free space to print anything we want
// In original ModKit, events were added into TR rows that were inserted directly into original villages table... this was nicely done
// but when we started to have dens of villages, that table grew a lot in height and it started to be hard to view all of them, and probably users end up disabling the feature
// Now, on the other hand, we have 2 tables, the original villages table (on the right of the screen), and events table, that is added to a draggable window
// original villages table is still used to show Dorf1 and Dorf2 layout status, but everything else was ported to events table
function ShowEvents(){
this.dwEventsContent;
this.dwEventsStatusbar;
this.dwEventsHTML="";
//refers to vlist table, it is the table on the right that lists all villages
this.vlistTable;
// old IMG
this.images=new Array();
// vLink holds the anchor that has villages names and links, this anchor was already used alot throu ModKit :P
this.vLink=new Array();
// emptyVillages stores villages that have no constructions running
this.emptyVillages = new Array();
this.dotCell = new Array();
this.show = function(){
//alert("entering ShowEvents.show()");
//first we create the draggable window that will hold our events table
this.buildWindow();
//alert("dwWindow ok");
// this query gets villages table's row, it is a xPath with an arry with a village row in each snapshotItem
this.vlistTable=this.getVlistTable();
//alert("villages found: "+this.vlistTable.snapshotLength);
this.buildEventsTable(true);
//alert("this.vLink: "+this.vLink);
}
this.buildWindow = function(){
var dwEventsPosRaw=GM_getValue(vInfo.uniqueID+"DragWin.dwEvents");
var dwEventsPosTop="29px";
var dwEventsPosLeft=(document.body.clientWidth-468)+"px";
if(dwEventsPosRaw){
dwEventsPosSplit=dwEventsPosRaw.split(":");
dwEventsPosTop=dwEventsPosSplit[0];
dwEventsPosLeft=dwEventsPosSplit[1];
}else{
GM_setValue(vInfo.uniqueID+"DragWin.dwEvents",dwEventsPosTop+":"+dwEventsPosLeft);
}
var body, dwEventsWin, dwEventsTitlebar, dwEventstiTlehead,
dwEventsAclose, dwEventsAhide, dwEventsAminimax;
body = document.getElementsByTagName('body')[0];
if(!dwEventsWin){
dwEventsWin = document.createElement('DIV');
dwEventsWin.id='dwEvents';
dwEventsWin.className='DW_window';
dwEventsWin.style.width="300px";
dwEventsWin.style.top=dwEventsPosTop;
dwEventsWin.style.left=dwEventsPosLeft;
dwEventsTitlebar = document.createElement('DIV');
dwEventsTitlebar.className='titlebar';
dwEventsWin.appendChild(dwEventsTitlebar);
dwEventstiTlehead = document.createElement('H2');
dwEventstiTlehead.innerHTML='Construction Events';
dwEventsTitlebar.appendChild(dwEventstiTlehead);
dwEventsAclose = document.createElement('A');
dwEventsAclose.title="Close";
dwEventsAclose.id="close";
dwEventsAclose.addEventListener('mouseup', function(){ DW_closeWindow(dwEventsAclose); }, false);
dwEventsAclose.innerHTML='x';
dwEventsTitlebar.appendChild(dwEventsAclose);
/*
dwEventsAhide = document.createElement('A');
dwEventsAhide.title="Hide";
dwEventsAhide.id="hide";
dwEventsAhide.addEventListener('mouseup', function(){ DW_hideWindow(dwEventsAhide); }, false);
dwEventsAhide.innerHTML='^';
dwEventsTitlebar.appendChild(dwEventsAhide);
*/
dwEventsAminimax = document.createElement('A');
dwEventsAminimax.title="Minimize";
dwEventsAminimax.id="minimax";
dwEventsAminimax.addEventListener('mouseup', function(){ DW_minimax(dwEventsAminimax); }, false);
dwEventsAminimax.innerHTML='-';
dwEventsTitlebar.appendChild(dwEventsAminimax);
this.dwEventsContent = document.createElement('DIV');
this.dwEventsContent.className='content';
dwEventsWin.appendChild(this.dwEventsContent);
this.dwEventsStatusbar = document.createElement('DIV');
this.dwEventsStatusbar.className='statusbar';
this.dwEventsStatusbar.innerHTML='statusbar .:';
dwEventsWin.appendChild(this.dwEventsStatusbar);
this.dwEventsContent.innerHTML = this.dwEventsHTML;
body.appendChild(dwEventsWin);
dwEventsTitlebar.addEventListener('mousedown', function(){ DW_startDrag(dwEventsWin); }, false);
dwEventsTitlebar.addEventListener('mouseup', DW_stopDrag, false);
dwEventsWin.addEventListener('mousemove', function(event) { DW_moving(event); }, false);
}
// we just created the window, it is not minimized ATM
// but if it should be, we call the function to minimize it
if(DW_isMinimized(dwEventsWin)){
DW_setMinimized(dwEventsAminimax,true);
}
// we also must check if it should be closed, closing it if that's the case
if(DW_isClosed(dwEventsWin)){
DW_closeWindow(dwEventsAclose);
}
}
this.buildEventsTable = function(printVlist){
//alert("entering ShowEvents.buildEventsTable(), printVlist: "+printVlist);
//alert(allVillagesEvents);
allVillagesEvents.loadData();
//alert(allVillagesEvents);
this.dwEventsContent.innerHTML="";
//alert("dwEventsContent is clean");
// this is the begining of our events table
var dwEventsTable = '<div class="TMEventsWindow">';
// we will start the table with the most worthy information: next events to expire
// this info is in the top because when we have a lot of villages and many of them have events, the window may go very long
// next villages info is as a short resume of the full events list, that will be printed soon
// adding it first assures that it will be promptly visible to user on every page reload, without him having to scroll down if the window goes down the screen
//this list must have the exact same villages as the full events list
var nextEvents = allVillagesEvents.getNextEvents();
//alert("next events: "+nextEvents.length+"\n\n"+nextEvents);
if(nextEvents.length>0){
//nextEvents.sort(sortNextEvents);
dwEventsTable += '<div class="nextExpire"><div class="villageInfo">Next events to expire</div>';
for(var nxevt=0;nxevt<nextEvents.length;nxevt++){
var villageResourcesLayout = new VillageResourcesLayout(nextEvents[nxevt].village);
var villageBuildingsLayout = new VillageBuildingsLayout(nextEvents[nxevt].village);
resLayoutOK = villageResourcesLayout.loadData();
buildLayoutOK = villageBuildingsLayout.loadData();
resDot=this.getEventDot(resLayoutOK,nextEvents[nxevt].village,new Array(-1,1));
buildDot=this.getEventDot(buildLayoutOK,nextEvents[nxevt].village,new Array(2,3));
var troopDot=this.getEventDot(true,nextEvents[nxevt].village,new Array(4,5));
var moveDot=this.getEventDot(true,nextEvents[nxevt].village,new Array(-1,6));
dwEventsTable += '<div class="villageEvent"><span class="floatLeft">';
if (vInfo.activeVillageIndex==nextEvents[nxevt].village){
dwEventsTable += '<img src="'+Xarrow+'"> ';
}
var timeleft=nextEvents[nxevt].event.getTimeLeft();
dwEventsTable += '<span id="TMcooldown" timeleft="'+timeleft+'">'+formatTime(timeleft)+'</span> ';
dwEventsTable += '<span class="floatLeft">';
dwEventsTable += '<a href="/dorf1.php?newdid='+vInfo.rawVillageIDs[nextEvents[nxevt].village]+'" title="Resources fields status"><img title="Resources fields status" alt="o" src="'+resDot+'" /></a><a href="/dorf2.php?newdid='+vInfo.rawVillageIDs[nextEvents[nxevt].village]+'" title="Buildings & Demolish status"><img title="Buildings & Demolish status" alt="o" src="'+buildDot+'" /></a><img title="Blacksmith & Armoury upgrades, Town Hall celebrations, and Barrack, Stable & Worksop troops training" alt="o" src="'+troopDot+'" /><img title="troops & mercants movements" alt="o" src="'+moveDot+'" /></span>';
dwEventsTable += '<a href="'+vInfo.vList[nextEvents[nxevt].village].link+'">'+vInfo.vList[nextEvents[nxevt].village].name+'</a>';
dwEventsTable += '</span></div>';
}
dwEventsTable += '</div>';
}
// now we go to the full events list
dwEventsTable += '<div class="fullEvents">';
dwEventsTable += '<div class="villageInfo">Full events list</div>';
var villagesWithEvents=0;
this.emptyVillages = new Array();
//var nextEvents = new Array();
// [--1--] For every table row.
for ( var i=0 ; i < this.vlistTable.snapshotLength; i++ ) {
// from the beginning of the loop until vLink we'll add a pretty arrow to point to Active Village, replacing those ugly dots, and add Dorf1 and Dorf2 dots
var villageRow = this.vlistTable.snapshotItem(i);
//alert("i="+i+" villageRow:\n"+villageRow.innerHTML);
// adds an arrow pointing to active village
if(printVlist){
//original dot's cell
this.dotCell[i] = this.vlistTable.snapshotItem(i).firstChild;
//alert("this.dotCell[i]:\n"+this.dotCell[i].innerHTML);
var arrowCell = document.createElement('TD');
if (vInfo.activeVillageIndex==i){
arrowCell.innerHTML = '<img src="'+Xarrow+'">';
}
villageRow.insertBefore(arrowCell,this.dotCell[i]); // replace it with the arrow
}
//if(printVlist)
//this.dotCell[i].innerHTML="";
var villageResourcesLayout = new VillageResourcesLayout(i);
var villageBuildingsLayout = new VillageBuildingsLayout(i);
var resLayoutOK = villageResourcesLayout.loadData();
var buildLayoutOK = villageBuildingsLayout.loadData();
//alert("resLayoutOK: "+resLayoutOK+" buildLayoutOK: "+buildLayoutOK);
var resDot=this.getEventDot(resLayoutOK,i,new Array(-1,1));
var buildDot=this.getEventDot(buildLayoutOK,i,new Array(2,3));
var troopDot=this.getEventDot(true,i,new Array(4,5));
var moveDot=this.getEventDot(true,i,new Array(-1,6));
this.dotCell[i].innerHTML = '<a href="/dorf1.php?newdid='+vInfo.rawVillageIDs[i]+'" title="Resources fields status"><img src="'+resDot+'" alt="o" title="Resources fields status" /></a> <a href="/dorf2.php?newdid='+vInfo.rawVillageIDs[i]+'" title="Buildings status"><img src="'+buildDot+'" alt="o" title="Buildings status" /></a>';
// vLink holds the anchor that has villages names and links, this anchor was already used alot throu ModKit :P
//now we'll use it once more to add village's name and link to events table, that will start being built now
if(printVlist){
if(this.dotCell[i].nextSibling.innerHTML)
this.vLink[i] = this.dotCell[i].nextSibling.innerHTML; // old HTML version
else
this.vLink[i] = this.dotCell[i].nextSibling.nextSibling.firstChild.innerHTML;
}
//alert(vLink.innerHTML);
//alert("old vLink: "+this.dotCell[i].nextSibling.innerHTML);
//alert("new vLink: "+this.dotCell[i].nextSibling.nextSibling.firstChild.innerHTML);
//alert("this.vLink[i]: "+this.vLink[i]);
// ok, we're done with original villages table, now let's build our pretty events table
// if this village has no events, we're done
if(allVillagesEvents.villages[i].count()>0){
// if layout is unknown, leave them red (layout is priority over events), else let's use them to show event status
//var resEtDot=this.getEventDot(resLayoutOK,i,1);
//var buildEtDot=this.getEventDot(buildLayoutOK,i,2);
villagesWithEvents++;
dwEventsTable += '<div class="village">';
dwEventsTable += '<div class="villageInfo">';
if (vInfo.activeVillageIndex==i){
dwEventsTable += '<img src="'+Xarrow+'"> ';
}
dwEventsTable += '<span class="floatLeft">';
dwEventsTable += '<a href="/dorf1.php?newdid='+vInfo.rawVillageIDs[i]+'" title="Resources fields status"><img title="Resources fields status" alt="o" src="'+resDot+'" /></a> <a href="/dorf2.php?newdid='+vInfo.rawVillageIDs[i]+'" title="Buildings & Demolish status"><img title="Buildings & Demolish status" alt="o" src="'+buildDot+'" /></a> <img title="Blacksmith & Armoury upgrades, Town Hall celebrations, and Barrack, Stable & Worksop troops training" alt="o" src="'+troopDot+'" /> <img title="troops & mercants movements" alt="o" src="'+moveDot+'" /></span>';
dwEventsTable += '<span class="floatLeft"><a href="'+vInfo.vList[i].link+'">'+vInfo.vList[i].name+'</a></span>';
dwEventsTable += '</div>';
var gotNextEvent=false;
for(var j=0;j<allVillagesEvents.villages[i].count();j++){
var timeleft=allVillagesEvents.villages[i].events[j].getTimeLeft();
//if(timeleft<0) timeleft=0;
/* if(timeleft>0 && !gotNextEvent){
nextEvents[nextEvents.length]=new NextEvent(i,allVillagesEvents.villages[i].events[j]);
gotNextEvent=true;
}
*/
//alert("nextEvents count: "+nextEvents.length);
dwEventsTable += '<div class="villageEvent';
if(timeleft<0) dwEventsTable += ' ExpiredEvent';
else dwEventsTable += ' RunningEvent';
dwEventsTable += ' ">';
if(timeleft<=0){
dwEventsTable += '<span><a id="TMRemoveEvent" village="'+i+'" event="'+j+'"><img src="'+XCancel+'" alt="X" title="This construction has finished, click to remove it from the list" /></a> </span> ';
}
dwEventsTable += '<span class="floatLeft" id="TMcooldown" timeleft="'+timeleft+'"';
if(timeleft<0) dwEventsTable += ' yellow="true"';
dwEventsTable += '>'+formatTime(timeleft)+'</span>'
if(allVillagesEvents.villages[i].events[j].isConstructionEvent()){
dwEventsTable += '<span class="floatLeft">'+allVillagesEvents.villages[i].events[j].structure.name+' ' +
(allVillagesEvents.villages[i].events[j].structure.lvl+1)+'</span>';
}else if(allVillagesEvents.villages[i].events[j].isTrainingEvent()){
dwEventsTable += '<span class="floatLeft">'+allVillagesEvents.villages[i].events[j].structure.name+' '+allVillagesEvents.villages[i].events[j].getEndingTime()+'</span>';
}else{
dwEventsTable += '<span class="floatLeft">'+allVillagesEvents.villages[i].events[j].structure.element+'</span>';
}
if(timeleft>0){
dwEventsTable += '<span class="floatLeft"><a id="TMRemoveEvent" village="'+i+'" event="'+j+'"><img src="'+XCancel+'" alt="X" title="Remove this event from list" /></a></span>';
}
dwEventsTable += '</div>';
}
dwEventsTable += '</div>';
}else{
this.emptyVillages[this.emptyVillages.length]=i;
//alert("this.emptyVillages.length: "+this.emptyVillages.length);
}
}
dwEventsTable += '</div>';
// all villages with events were added, now print empty villages to make it easy to the user to know which villages are not on previous lists and may be useful to set something to construct
if(this.emptyVillages.length>0){
dwEventsTable += '<div class="emptyVillages"><div class="villageInfo">Villages with no events</div>';
for(var emptyVillage=0;emptyVillage<this.emptyVillages.length;emptyVillage++){
//var resEtDot=this.getEventDot(resLayoutOK,this.emptyVillages[emptyVillage],1);
//var buildEtDot=this.getEventDot(buildLayoutOK,this.emptyVillages[emptyVillage],2);
var villageResourcesLayout = new VillageResourcesLayout(this.emptyVillages[emptyVillage]);
var villageBuildingsLayout = new VillageBuildingsLayout(this.emptyVillages[emptyVillage]);
resLayoutOK = villageResourcesLayout.loadData();
buildLayoutOK = villageBuildingsLayout.loadData();
resDot=this.getEventDot(resLayoutOK,this.emptyVillages[emptyVillage],new Array(-1,1));
buildDot=this.getEventDot(buildLayoutOK,this.emptyVillages[emptyVillage],new Array(2,3));
dwEventsTable += '<div class="villageEvent"><span class="floatLeft">';
if (vInfo.activeVillageIndex==this.emptyVillages[emptyVillage]){
dwEventsTable += '<img src="'+Xarrow+'"> ';
}
dwEventsTable += '<a href="/dorf1.php?newdid='+vInfo.rawVillageIDs[this.emptyVillages[emptyVillage]]+'" title="Resources fields status"><img title="Resources fields status" alt="o" src="'+resDot+'" /></a> <a href="/dorf2.php?newdid='+vInfo.rawVillageIDs[this.emptyVillages[emptyVillage]]+'" title="Buildings & Demolish status"><img title="Buildings & Demolish status" alt="o" src="'+buildDot+'" /></a></span><span class="floatLeft">';
dwEventsTable += '<a href="'+vInfo.vList[this.emptyVillages[emptyVillage]].link+'">'+vInfo.vList[this.emptyVillages[emptyVillage]].name+'</a></span></div>';
}
dwEventsTable += '</div>';
}
dwEventsTable += '</div>';
this.dwEventsContent.innerHTML=dwEventsTable;
this.dwEventsStatusbar.innerHTML=allVillagesEvents.count()+" events in "+villagesWithEvents+" villages .: ";
addRemoveEvent();
}
//there are some event types that share the same dot, because of that 'type' must be an array
// for dots with only 1 event type, pass an array with 1 element
// in the case you (as me) want to use Array constructor inside function parameters and add only 1 element, use '-1' as another element to have 2 elements for the Array constructor
// exemple: new Array(-1,1) if you want to pass event type 1
// any event type <0 will be discarded
this.getEventDot = function(layout,vindex,type){
//alert("entering ShowEvents.getEventDot()\ntype: "+type);
var dot=Xnull; // variable created, Xnull is default
for(var i=0;i<type.length;i++){
if(type[i]<0) continue; // trick for invalid event types <0, used to create arrays with 1 parameter
if(!layout){ // if layout is unknown, change it to XRed and return
dot=XRed;
return dot;
}else{ // but if layout is known, let's move on...
if(allVillagesEvents.villages[vindex].hasEventType(type[i])){ // if required village has an event of required type, change it to Xon and move on
//alert(vInfo.vList[i].name+" has event type 1");
dot=Xon;
if(allVillagesEvents.villages[vindex].hasExpiredEventOfType(type[i])){ // but wait, if it has this type of event, but it has expired, then what we want is Xdone!!
//alert(vInfo.vList[i].name+" has expired event of type 1");
dot=Xdone;
return dot;
}
}
}
}
return dot;
}
this.getVlistTable = function(){
var table=null;
//alert("GetReferenceData.getVlistTable()\nbrx, multiple village, Beyond 3.8.8.2 supported");
table = TM_searchDOM('//div[@id="side_info"]/table[@id="vlist"]/tbody/tr'); // village list
if(table.snapshotLength>0){ return table; }
//alert("old version");
table = TM_searchDOM('//div[@id="sright"]/table[@id="vlist"]/tbody/tr'); // village list
if(table.snapshotLength>0){ return table; }
return table;
}
}
function ShowCPSuggestions(){
this.dwCPSuggContent;
this.dwCPSuggStatusbar;
this.dwCPSuggHTML="";
this.CPList;
// these are villages table's villages names links, gathered by ShowEvents.show()
// I'm using it by comodity, what's needed is a list of villages names with their links
// in the future it would be nice to add them to vInfo.vList[] and create anchors manually
// but for now, since ShowCPSuggestions is using ShowEvents.show(), it must be run before ShowCPSuggestions can be instantiated
this.vLink=showEvents.vLink;
this.show = function(){
//alert("entering ShowCPSuggestions.show()");
//first we create the draggable window that will hold our events table
this.buildWindow();
//alert("dwWindow ok");
//alert("this.vLink:\n\n"+this.vLink);
this.buildCPTable();
//alert("dwCPTable ok");
}
this.buildWindow = function(){
var dwCPSuggPosRaw=GM_getValue(vInfo.uniqueID+"DragWin.dwCPSugg");
var dwCPSuggPosTop="600px";
var dwCPSuggPosLeft="700px";
if(dwCPSuggPosRaw){
dwCPSuggPosSplit=dwCPSuggPosRaw.split(":");
dwCPSuggPosTop=dwCPSuggPosSplit[0];
dwCPSuggPosLeft=dwCPSuggPosSplit[1];
}else{
GM_setValue(vInfo.uniqueID+"DragWin.dwCPSugg",dwCPSuggPosTop+":"+dwCPSuggPosLeft);
}
var body, dwCPSuggWin, dwCPSuggTitlebar, dwCPSuggtiTlehead,
dwCPSuggAclose, dwCPSuggAhide, dwCPSuggAminimax;
body = document.getElementsByTagName('body')[0];
if(!dwCPSuggWin){
dwCPSuggWin = document.createElement('DIV');
dwCPSuggWin.id='dwCPSugg';
dwCPSuggWin.className='DW_window';
dwCPSuggWin.style.width="500px";
dwCPSuggWin.style.top=dwCPSuggPosTop;
dwCPSuggWin.style.left=dwCPSuggPosLeft;
dwCPSuggTitlebar = document.createElement('DIV');
dwCPSuggTitlebar.className='titlebar';
dwCPSuggWin.appendChild(dwCPSuggTitlebar);
dwCPSuggtiTlehead = document.createElement('H2');
dwCPSuggtiTlehead.innerHTML='CP Buildings Suggestions';
dwCPSuggTitlebar.appendChild(dwCPSuggtiTlehead);
dwCPSuggAclose = document.createElement('A');
dwCPSuggAclose.title="Close";
dwCPSuggAclose.id="close";
dwCPSuggAclose.addEventListener('mouseup', function(){ DW_closeWindow(dwCPSuggAclose); }, false);
dwCPSuggAclose.innerHTML='x';
dwCPSuggTitlebar.appendChild(dwCPSuggAclose);
/*
dwCPSuggAhide = document.createElement('A');
dwCPSuggAhide.title="Hide";
dwCPSuggAhide.id="hide";
dwCPSuggAhide.addEventListener('mouseup', function(){ DW_hideWindow(dwCPSuggAhide); }, false);
dwCPSuggAhide.innerHTML='^';
dwCPSuggTitlebar.appendChild(dwCPSuggAhide);
*/
dwCPSuggAminimax = document.createElement('A');
dwCPSuggAminimax.title="Minimize";
dwCPSuggAminimax.id="minimax";
dwCPSuggAminimax.addEventListener('mouseup', function(){ DW_minimax(dwCPSuggAminimax); }, false);
dwCPSuggAminimax.innerHTML='-';
dwCPSuggTitlebar.appendChild(dwCPSuggAminimax);
this.dwCPSuggContent = document.createElement('DIV');
this.dwCPSuggContent.className='content';
dwCPSuggWin.appendChild(this.dwCPSuggContent);
this.dwCPSuggStatusbar = document.createElement('DIV');
this.dwCPSuggStatusbar.className='statusbar';
this.dwCPSuggStatusbar.innerHTML='statusbar .:';
dwCPSuggWin.appendChild(this.dwCPSuggStatusbar);
this.dwCPSuggContent.innerHTML = this.dwCPSuggHTML;
body.appendChild(dwCPSuggWin);
dwCPSuggTitlebar.addEventListener('mousedown', function(){ DW_startDrag(dwCPSuggWin); }, false);
dwCPSuggTitlebar.addEventListener('mouseup', DW_stopDrag, false);
dwCPSuggWin.addEventListener('mousemove', function(event) { DW_moving(event); }, false);
}
// we just created the window, it is not minimized ATM
// but if it should be, we call the function to minimize it
if(DW_isMinimized(dwCPSuggWin)){
DW_setMinimized(dwCPSuggAminimax,true);
}
// we also must check if it should be closed, closing it if that's the case
if(DW_isClosed(dwCPSuggWin)){
DW_closeWindow(dwCPSuggAclose);
}
}
this.buildCPTable = function(){
this.dwCPSuggContent.innerHTML="";
//alert("dwEventsContent is clean");
// its parameter defines how many entries will be used for each village
this.CPList=getCPRank(5);
//alert("this.CPList:\n\n"+this.CPList);
var cpSort= GM_getValue(vInfo.uniqueID+"DragWin.dwCPSugg.sort");
//alert("cpSort: "+cpSort);
if(!cpSort){
cpSort="efficiency";
GM_setValue(vInfo.uniqueID+"DragWin.dwCPSugg.sort",cpSort);
}
this.CPList.sortBy(cpSort);
// this is the begining of our events table
var dwCPTable = '<table width="100%" border="0" class="TMCPWindow"><tr>';
if(cpSort=="efficiency"){
dwCPTable += '<th>Rank</th><th>Earn</th><th>Building</th><th><a id="TMResortCP" sort="village"><img src="'+Xarrow+'" alt=">" title="Sort by village" /></a> Village</th>';
this.dwCPSuggStatusbar.innerHTML = "sorted by Efficiency .: ";
}else{
dwCPTable += '<th><a id="TMResortCP" sort="efficiency"><img src="'+Xarrow+'" alt=">" title="Sort by Efficiency Rank" /></a> Rank</th><th>Earn</th><th>Building</th><th>Village</th>';
this.dwCPSuggStatusbar.innerHTML = "sorted by Village .: ";
}
dwCPTable += '</tr>';
for(var i=0;i<this.CPList.count();i++){
dwCPTable += '<tr>';
dwCPTable += '<td>'+cps[this.CPList.list[i].cpIndex].rank+'</td>';
dwCPTable += '<td>'+cps[this.CPList.list[i].cpIndex].cp+'</td>';
dwCPTable += '<td>'+cps[this.CPList.list[i].cpIndex].building+' '+cps[this.CPList.list[i].cpIndex].lvl+
' <a id="TMSkipCPEntry" vid="'+vInfo.vList[this.CPList.list[i].vIndex].id+'" cpsid="'+this.CPList.list[i].cpIndex+'" ><img src="'+XCancel+'" alt="X" title="Click if you want to skip this upgrade" /></a></td>';
dwCPTable += '<td>'+this.vLink[this.CPList.list[i].vIndex]+'</td>';
dwCPTable += '</tr>';
}
dwCPTable += '<tr><td colspan="4" class="right"><a id="TMResetSkips" title="Reset CP Suggestions Skips" >Reset Skips <img src="'+XCancel+'" alt="X" title="Reset CP Suggestions Skips" /></a></td></tr>';
dwCPTable += '</table>';
this.dwCPSuggContent.innerHTML=dwCPTable;
addResortCP();
}
this.resortCPTable = function(sortBy){
if(sortBy=="efficiency"){
GM_setValue(vInfo.uniqueID+"DragWin.dwCPSugg.sort","efficiency");
}else{
GM_setValue(vInfo.uniqueID+"DragWin.dwCPSugg.sort","village");
}
showCPSuggestions.buildCPTable();
}
}
/*
Prefs info: everything known about each option
- Prefs[0]:
. it can be '0' or 'M'
. it is related to MM[0] menu, which has '[]' text
. 0 makes it red background, M makes it green
- Prefs[ 1 to 4 ]:
. they can be '0' or '1'
. they are related to MM [ 1 to 4 ], which are 4 dots
. 0 makes its dot green, 1 makes it red
- Prefs[5]:
. it can be 0 or T
. it is related to MM[5], which has '00:00:00', it seems this text never changes
. 0 makes it red background, T makes it green
- Prefs[6]:
. it exists, but I don't know much about it
. it is related with villages layout not being known, when any of them is unknown it is set to '0'
*/
function CreateMenu(){
this.show = function(){
//alert(GM_getValue(vInfo.uniqueID+"Prefs"));
var M,MENU,MM=new Array();
M = addDiv('TMmenutrigger','TMmain','',false);
M.style.backgroundColor = 'green';
M.style.cursor = 'pointer';
M.style.fontSize="0.5em";
M.innerHTML="MK";
M.addEventListener('click', function() {
//alert("M.addEventListener");
MENU = addDiv('TMmenu','TMmain','',false);
MENU.style.right = "34px";
MM[0] =addDiv('TMmm0','TMdisplay','Reopen Windows','TMmenu');
MM[0].style.backgroundColor = 'green';
MM[0].addEventListener('click', function() {
DW_openWindows();
}, true);
}, true);
}
}
// Draggable Windows functions
var DW_mouseX, DW_mouseY, DW_offsetX, DW_offsetY;
var DW_id = "win1";
var DW_dragMode = false;
var DW_offsetMode = false;
function DW_selection(target, act){
if (!act) {
if (typeof target.onselectstart != "undefined") //IE route
target.onselectstart = function() { return false; }
else if (typeof target.style.MozUserSelect != "undefined") //Firefox route
target.style.MozUserSelect = "none";
else //All other route (ie: Opera)
target.onmousedown = function() { return false; }
} else {
if (typeof target.onselectstart != "undefined") //IE route
target.onselectstart = function() { return true; }
else if (typeof target.style.MozUserSelect != "undefined") //Firefox route
target.style.MozUserSelect = "none";
else //All other route (ie: Opera)
target.onmousedown = function() { return true; }
}
}
function DW_findPos(obj) {
var left = 0;
var top = 0;
if (obj.offsetParent) {
left = obj.offsetLeft;
top = obj.offsetTop;
while (obj = obj.offsetParent) {
left += obj.offsetLeft;
top += obj.offsetTop;
}
}
DW_offsetX = left;
DW_offsetY = top;
}
function DW_moving(event) {
var alvo = document.getElementById(DW_id);
if (document.all) {
DW_mouseX = window.event.clientX;
DW_mouseY = window.event.clientY;
} else {
DW_mouseX = event.pageX;
DW_mouseY = event.pageY;
}
if (!DW_offsetMode) {
DW_findPos(document.getElementById(DW_id));
DW_offsetX = DW_mouseX - DW_offsetX;
DW_offsetY = DW_mouseY - DW_offsetY;
}
var debugPanel = document.getElementById("debug");
if(debugPanel) debugPanel.innerHTML = "DW_mouseX: "+DW_mouseX+"<br />DW_mouseY: "+DW_mouseY+"<br />DW_offsetX: "+DW_offsetX+"<br />DW_offsetY: "+DW_offsetY+"<br />window: "+DW_id;
var body = document.getElementsByTagName("body").item(0);
if (DW_dragMode) {
alvo.style.top = (DW_mouseY-DW_offsetY)+"px";
alvo.style.left = (DW_mouseX-DW_offsetX)+"px";
alvo.style.cursor = "move";
alvo.style.opacity = 0.7;
alvo.style.filter = "alpha(opacity=70)";
DW_selection(body, false);
GM_setValue(vInfo.uniqueID+"DragWin."+DW_id,alvo.style.top+":"+alvo.style.left);
} else {
alvo.style.cursor = "default";
alvo.style.opacity = 1;
alvo.style.filter = "alpha(opacity=100)";
DW_selection(body, true);
}
}
function DW_startDrag(domWindow) {
DW_id=domWindow.getAttribute("id");
DW_findPos(document.getElementById(DW_id));
DW_offsetX = DW_mouseX - DW_offsetX;
DW_offsetY = DW_mouseY - DW_offsetY;
DW_dragMode = true; DW_offsetMode = true;
}
function DW_stopDrag() { DW_dragMode = false; DW_offsetMode = false; }
function DW_closeWindow(btn) {
var window=btn.parentNode.parentNode;
var id=window.getAttribute("id");
window.style.visibility = "hidden";
GM_setValue(vInfo.uniqueID+"DragWin."+id+".closed","true");
}
function DW_isClosed(window){
var id=window.getAttribute("id");
var closed=GM_getValue(vInfo.uniqueID+"DragWin."+id+".closed");
return closed=="true";
}
function DW_openWindows() {
var windows=document.evaluate('//div[@class="DW_window"]',document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);
for(var i=0;i<windows.snapshotLength;i++){
windows.snapshotItem(i).style.visibility = "visible";
var id=windows.snapshotItem(i).getAttribute("id");
GM_setValue(vInfo.uniqueID+"DragWin."+id+".closed","false");
}
}
function DW_isMinimized(window){
var id=window.getAttribute("id");
var minimized=GM_getValue(vInfo.uniqueID+"DragWin."+id+".minimized");
return minimized=="true";
//return window.getAttribute("minimized")=="true";
}
function DW_minimax(btn) {
//alert("entering DW_minimax()");
var window=btn.parentNode.parentNode;
var id=window.getAttribute("id");
//alert("id: "+id);
var minimized=DW_isMinimized(window);
//alert("minimized: "+minimized);
if(minimized){ // if it is minimized, let's restore it
DW_setMinimized(btn,false);
}else{ // but if it is not minimized, let's minimize it
DW_setMinimized(btn,true);
}
}
function DW_setMinimized(btn,value){
var window=btn.parentNode.parentNode;
var id=window.getAttribute("id");
var content=document.evaluate('//div[@id="'+window.getAttribute("id")+'"]/div[@class="content"]',document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0);
var statusbar=document.evaluate('//div[@id="'+window.getAttribute("id")+'"]/div[@class="statusbar"]',document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0);
if(value){ // minimize it
content.style.display = "none";
btn.innerHTML = "+";
btn.setAttribute("title", "Maximize");
window.setAttribute("minimized",true);
GM_setValue(vInfo.uniqueID+"DragWin."+id+".minimized","true");
}else{ // restore it
content.style.display = "block";
btn.innerHTML = "-";
btn.setAttribute("title", "Minimize");
statusbar.style.display = "block";
window.setAttribute("minimized",false);
GM_setValue(vInfo.uniqueID+"DragWin."+id+".minimized","false");
}
}
function DW_hideWindow(btn) {
var window=btn.parentNode.parentNode;
var minimaxBtn=document.evaluate('//div[@id="'+window.getAttribute("id")+'"]//a[@id="minimax"]',document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null).snapshotItem(0);
if (!DW_isMinimized(window)) {
DW_minimax(minimaxBtn);
}
window.style.top = 0;
window.style.left = 0;
window.getElementById("statusbar").style.display = "none";
}
//document.onmousemove = function(event) { DW_moving(event); }
//document.addEventListener('mousemove', function(event) { DW_moving(event); }, false);
/* Window exemple
function debug(){
var dwwin =
'<p><img src="xls.jpg" alt="random image"/>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Phasellus venenatis fringilla purus. Suspendisse ultrices, leo vitae mollis eleifend, mi orci volutpat justo, in mollis erat dolor at dolor. Etiam volutpat diam. Morbi diam. Cras leo enim, imperdiet sit amet, facilisis a, ullamcorper in, nunc. Nunc elit quam, egestas sed, viverra eget, tempus nec, turpis. Morbi mauris dolor, adipiscing id, facilisis eget, dapibus ac, turpis.</p>'+
'<p>Quisque nec magna. Morbi tellus nisl, ullamcorper sed, ullamcorper in, adipiscing et, tellus. Maecenas at urna. In vehicula est sed purus. Quisque lobortis vestibulum nulla. Sed lacinia pellentesque massa. Nulla facilisi. Vestibulum semper. Nulla vitae lacus eu mauris tincidunt luctus. Ut porttitor nisi quis tortor. Vestibulum adipiscing, elit id scelerisque molestie, tortor lacus ullamcorper neque, ut tristique mi purus sit amet orci.</p>'+
'<p>Ut venenatis lacus ut diam. Nunc dignissim mattis risus. Nam sollicitudin nunc ut mauris commodo venenatis. Fusce augue tortor, consectetuer non, cursus nec, aliquam ac, magna. Praesent orci.</p>'+
'<p id="debug">Ut venenatis lacus ut diam. Nunc dignissim mattis risus. Nam sollicitudin nunc ut mauris commodo venenatis. Fusce augue tortor, consectetuer non, cursus nec, aliquam ac, magna. Praesent orci.</p>';
var body, windiv, titlebar, titlehead, content, statusbar, aclose, ahide, aminimax;
body = document.getElementsByTagName('body')[0];
windiv = document.createElement('DIV');
windiv.id='win1';
windiv.className='DW_window';
windiv.style.top="600px";
windiv.style.left="700px";
titlebar = document.createElement('DIV');
titlebar.className='titlebar';
windiv.appendChild(titlebar);
titlehead = document.createElement('H2');
titlehead.innerHTML='Window Title';
titlebar.appendChild(titlehead);
aclose = document.createElement('A');
aclose.title="Close";
aclose.id="close";
aclose.addEventListener('mouseup', function(){ DW_closeWindow(aclose); }, false);
aclose.innerHTML='x';
titlebar.appendChild(aclose);
ahide = document.createElement('A');
ahide.title="Hide";
ahide.id="hide";
ahide.addEventListener('mouseup', function(){ DW_hideWindow(ahide); }, false);
ahide.innerHTML='^';
titlebar.appendChild(ahide);
aminimax = document.createElement('A');
aminimax.title="Minimize";
aminimax.id="minimax";
aminimax.addEventListener('mouseup', function(){ DW_minimax(aminimax); }, false);
aminimax.innerHTML='-';
titlebar.appendChild(aminimax);
content = document.createElement('DIV');
content.className='content';
windiv.appendChild(content);
statusbar = document.createElement('DIV');
statusbar.className='statusbar';
statusbar.innerHTML='statusbar .:';
windiv.appendChild(statusbar);
content.innerHTML = dwwin;
body.appendChild(windiv);
windiv.addEventListener('mousedown', function(){ DW_startDrag(windiv); }, false);
windiv.addEventListener('mouseup', DW_stopDrag, false);
windiv.addEventListener('mousemove', function(event) { DW_moving(event); }, false);
}
*/
//=================================
// support functions
// nice function for number formatting
// found at http://www.mredkj.com/javascript/numberFormat.html and http://www.mredkj.com/javascript/nfbasic.html
function addSeparatorsNF(nStr, inD, outD, sep)
{
nStr += '';
var dpos = nStr.indexOf(inD);
var nStrEnd = '';
if (dpos != -1) {
nStrEnd = outD + nStr.substring(dpos + 1, nStr.length);
nStr = nStr.substring(0, dpos);
}
var rgx = /(\d+)(\d{3})/;
while (rgx.test(nStr)) {
nStr = nStr.replace(rgx, '$1' + sep + '$2');
}
return nStr + nStrEnd;
}
function trim(str, chars) {
return ltrim(rtrim(str, chars), chars);
}
function ltrim(str, chars) {
chars = chars || "\\s";
return str.replace(new RegExp("^[" + chars + "]+", "g"), "");
}
function rtrim(str, chars) {
chars = chars || "\\s";
return str.replace(new RegExp("[" + chars + "]+$", "g"), "");
}
function TM_searchDOM(X){return document.evaluate(X,document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);}
function TM_searchNode(doc,X){return document.evaluate(X,doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);}
function pI(X){return parseInt(X);}
// ›› Adds a generic div.
function addDiv(id,style,html,parent){
var body, div;
if (!parent){body = document.getElementsByTagName('body')[0];}else{body = document.getElementById(parent);}
if (!body) {return false;}
div = document.createElement('DIV');
if (id) {div.id = id;}
if (style) {div.className = style;}
if (html) {div.innerHTML = html;}
body.appendChild(div);
return div;
}
// ›› Adds a generic image.
function addImg(id,style,src,parent){
var body, img;
if (!parent){body = document.getElementsByTagName('body')[0];}else{body = document.getElementById(parent);}
if (!body) {return false;}
img = document.createElement('IMG');
if(id) {img.id = id};
if(style) {img.className = style};
if(src) {img.src = src};
body.appendChild(img);
return img;
}
// ›› Add generic CSS
function addCSS(cssString) {
var style = document.createElement('STYLE');
style.type = 'text/css';style.innerHTML = cssString;
document.getElementsByTagName('HEAD')[0].appendChild(style);
}
// ›› Make default CSS.
function makeDefaultCSS(){
var cssString = "";
addCSS('.TMnull{position:relative;}');
cssString = '.TMpopup{' +
'background-color:white;' +
'border:thin solid #000000;' +
'font-family: Verdana, Arial, Helvetica, sans-serif;' +
'font-size:8pt;' +
'font-weight:bold;' +
'padding-bottom:3px;' +
'padding-left:3px;' +
'padding-right:3px;' +
'padding-top:3px;' +
'position:absolute;' +
'visibility:hidden;' +
'z-index:200;}';
addCSS(cssString);
cssString = '.TMdisplay{' +
'cursor:pointer;' +
'font-family: Verdana, Arial, Helvetica, sans-serif;' +
'font-size:8pt;' +
'float:left;' +
'margin:3px;' +
'padding:3px;' +
'position:relative;}';
addCSS(cssString);
cssString = '.TMmain{' +
'border:thin solid #000000;' +
'bottom:5px;' +
'font-family: Verdana, Arial, Helvetica, sans-serif;' +
'font-size:8pt;' +
'font-weight:bold;' +
'padding-bottom:5px;' +
'padding-left:5px;' +
'padding-right:5px;' +
'padding-top:5px;' +
'position:fixed;' +
'right:8px;' +
'z-index:1050;}';
addCSS(cssString);
var cssString = '.TMbuildingtags{' +
'background-color:#FDF8C1;' +
'border:thin solid #000000;' +
'cursor:pointer;' +
'font-family: Verdana, Arial, Helvetica, sans-serif;' +
'font-size:8pt;' +
'font-weight:bold;' +
'height:14px;' +
'position:absolute;' +
'text-align:center;' +
'visibility:hidden;' +
'width:21px;' +
'z-index:50;}';
addCSS(cssString);
cssString = '.TMtimers{' +
'font-family: Verdana, Arial, Helvetica, sans-serif;' +
'font-size:8pt;' +
'float:left;' +
'padding-bottom:1px;' +
'padding-left:15px;' +
'position:relative;' +
'z-index:50;}';
addCSS(cssString);
cssString = '.TMleftmenu{' +
'background-color:white;' +
'cursor:pointer;' +
'font-family: Verdana, Arial, Helvetica, sans-serif;' +
'font-size:7pt;' +
'font-weight:bold;' +
'padding-bottom:5px;' +
'padding-left:0px;' +
//'padding-right:15px;' +
'position:absolute;' +
'width:145px;' +
'border:0;' +
'top:0px;' +
'z-index:4;}';
addCSS(cssString);
cssString = '.TMleftmenu td{' +
'border:0;}';
addCSS(cssString);
cssString = '.TMdemo{' +
'position:fixed;' +
'top:108px;' +
'right:8px;' +
'z-index:50;}';
addCSS(cssString);
cssString = '.TWoodBack{' +
'background:#DDEEDD;}';
addCSS(cssString);
cssString = '.TClayBack{' +
'background:#FFCD8E;}';
addCSS(cssString);
cssString = '.TIronBack{' +
'background:#DEE3E9;}';
addCSS(cssString);
cssString = '.TCropBack{' +
'background:#FDF8C1;}';
addCSS(cssString);
cssString = '.TTitle{' +
'background:#FFFFFF;' +
'text-align:center}';
addCSS(cssString);
cssString = '.DW_window table, .DW_window table tbody th, .DW_window table tbody td{' +
'background-color:transparent;}';
addCSS(cssString);
cssString = 'td.tb3c table, table.traders tbody{' +
'background-color:#FFFFFF;}';
addCSS(cssString);
cssString = '#vlist tbody tr, div#side_info table td{' +
'line-height:1em;}';
addCSS(cssString);
// Draggable Windows
cssString = '.DW_window{' +
'border-top: 1px solid #000000;' +
'border-right: 2px solid #666666;' +
'border-bottom: 2px solid #000000;' +
'border-left: 1px solid #999999;' +
'width: 400px;' +
'position: absolute;' +
'z-index: 1000;' +
'top: 600px'+
'left: 700px;}';
addCSS(cssString);
cssString = '.DW_window .titlebar{' +
'width: 100%;' +
'height: 25px;' +
'background: #666666;' +
'border-top: 1px solid #999999;' +
'border-right: 1px solid #666666;' +
'border-bottom: 1px solid black;' +
'border-left: 1px solid #999999;}';
addCSS(cssString);
cssString = '.DW_window .titlebar h2{' +
'font: 12px Verdana, Arial, Sans-serif;' +
'color: #ffffff;' +
'padding: 5px 5px;' +
'margin: 0px;' +
'float: left;}';
addCSS(cssString);
cssString = '.DW_window .titlebar a{' +
'font: 12px Verdana, Arial, Sans-serif;' +
'color: #ffffff;' +
'padding: 1px 4px;' +
'margin: 4px 2px 0px 1px;' +
'text-decoration: none;' +
'display: block;' +
'border: 1px solid #000000;' +
'float: right;}';
addCSS(cssString);
cssString = '.DW_window .content{' +
//'padding: 10px 20px;' +
'background: #f1f1f1;' +
'border-top: 1px solid #999999;' +
'border-bottom: 1px solid #CCCCCC;}';
addCSS(cssString);
cssString = '.DW_window .content p{' +
'font: 12px Verdana, Arial, Sans-serif;' +
'color: #333333;' +
'margin-bottom: 5px;}';
addCSS(cssString);
cssString = '.DW_window .statusbar{' +
'font: 10px Verdana, Arial, Sans-serif;' +
'color: #999999;' +
'padding: 1px 5px;' +
'background: #d9d9d9;' +
'border-top: 1px solid #666666;' +
'text-align: right;}';
addCSS(cssString);
cssString = '.TMEventsWindow .floatLeft, .TMCPWindow .floatLeft{' +
//'float: left;'+
'margin-right:15px;}';
addCSS(cssString);
cssString = '.TMEventsWindow .village{' +
'border-top: 1px solid;'+
'padding:2px 2px 10px 2px;}';
addCSS(cssString);
cssString = '.TMEventsWindow .villageInfo{' +
'padding:0 0 5px 0;}';
addCSS(cssString);
cssString = '.TMEventsWindow .villageEvent{' +
'padding:0 0 2px 10px;}';
addCSS(cssString);
cssString = '.TMCPWindow td, .TMCPWindow th{' +
'background-color:#FFFFFF;' +
'border:0;' +
'padding:5px 5px;}';
addCSS(cssString);
cssString = '.TMCPWindow th{' +
'text-align: left;' +
'padding-bottom: 10px;' +
'border-bottom: 1px solid;' +
'font-weight: bold}';
addCSS(cssString);
cssString = '.RunningEvent{' +
'color:#6666FF;}';
addCSS(cssString);
cssString = '.ExpiredEvent{' +
//'color:#CCCC00;}';
'color:#808080;}';
addCSS(cssString);
cssString = '.TMEventsWindow .fullEvents{' +
'margin-bottom:20px;}';
addCSS(cssString);
cssString = '.TMEventsWindow .fullEvents, .TMEventsWindow .emptyVillages{' +
'border-bottom: 1px solid;'+
'padding:20px 2px 2px 2px;}';
addCSS(cssString);
cssString = '#villagesData div table tbody tr td, #generalProd div table tbody tr td{' +
'border: 1px solid #CCCCCC;}';
addCSS(cssString);
cssString = '.d1{' +
'font-weight: bold;' +
'color:#228B22;}';
addCSS(cssString);
cssString = '.d2{' +
'font-weight: bold;' +
'color:#F2C700;}';
addCSS(cssString);
}
function getCurrentTime(){
return Math.round(new Date().getTime()/1000);
}
function getSeconds(FormattedTime){
var timeArray = FormattedTime.split(":");
var secs = timeArray[0]*3600+timeArray[1]*60+timeArray[2]*1;
return secs;
}
function formatTime(seconds){
var negative=false;
if (seconds<0){
seconds = seconds*-1;
negative=true;
}
az=Math.floor(seconds/3600); //hour
an=Math.floor(seconds/60)%60;if(an<10){an="0"+an;} //minute
af=seconds%60; if(af<10){af="0"+af;} //second
t=az+':'+an+':'+af;
if (negative){t="-"+t;}
return t;
}
// ›› Inactive stub.
function inactivestub (){alert('Bad news =[ No place to save preferences. Firefox required. If you have Firefox, your version of Greasemonkey might be too old. If this is the case... UPGRADE NOW. There are SERIOUS security issues with older versions of Greasemonkey!');}
// ›› Offsite stub.
function offsitestub() {}
// ›› Back to drawing board on redirect.
function redirect() {}
//alert("support functions ok");
function switchLanguage(){
//alert("vInfo.serverLang: "+vInfo.serverLang);
switch(vInfo.serverLang){
case 'br':
case 'pt':
xLang['Main']='Edifício Principal';
xLang['Market']='Mercado';
xLang['Academy']='Academia';
xLang['Embassy']='Embaixada';
xLang['Granary']='Celeiro';
xLang['Stable']='Cavalaria';
xLang['Wall']='Muralha'; // roman wall
xLang['Gaul Wall']='Muralha';
xLang['Teuton Wall']='Muralha';
xLang['Warehouse']='Armazém';
xLang['Rally']='Ponto de Reunião Militar';
xLang['Blacksmith']='Ferreiro';
xLang['Armoury']='Fábrica de Armaduras';
xLang['Palace']='Palácio';
xLang['Residence']='Residência';
xLang['Workshop']='Oficina';
xLang['Barracks']='Quartel';
xLang['Town Hall']='Casa do Povo'; //nome mais cretino q conseguiram imaginar
xLang['Trade']='Companhia do Comércio';
xLang['Wood Field']='Bosque';
xLang['Clay Field']='Poço de Barro';
xLang['Iron Field']='Mina de Ferro';
xLang['Crop Field']='Campo de Cereais';
break;
case 'nl':
// translation by underke
xLang['Main']='Hoofdgebouw';
xLang['Market']='Marktplaats';
xLang['Academy']='Academie';
xLang['Embassy']='Ambassade';
xLang['Granary']='Graansilo';
xLang['Stable']='Stal';
xLang['Wall']='Stadsmuur'; // roman wall
xLang['Gaul Wall']='Palissade';
xLang['Teuton Wall']='Muur van aarde';
xLang['Warehouse']='Pakhuis';
xLang['Rally']='Verzamelplaats';
xLang['Blacksmith']='Wapensmid';
xLang['Armoury']='Uitrustingssmederij';
xLang['Palace']='Paleis';
xLang['Residence']='Residentie';
xLang['Workshop']='Werkplaats';
xLang['Barracks']='Barakken';
xLang['Town Hall']='Raadhuis';
xLang['Trade']='Handelskantoor';
xLang['Wood Field']='Houthakker';
xLang['Clay Field']='Klei-afgraving';
xLang['Iron Field']='IJzermijn';
xLang['Crop Field']='Graanakker';
break;
case 'ru':
xLang['Main']='Главное здание';
xLang['Market']='Рынок';
xLang['Academy']='Академия';
xLang['Embassy']='Посольство';
xLang['Granary']='Амбар';
xLang['Stable']='Конюшня';
xLang['Wall']='Римская стена'; // roman wall
xLang['Gaul Wall']='Частоколл(галлы)';
xLang['Teuton Wall']='Земляной вал';
xLang['Warehouse']='Склад';
xLang['Rally']='Пункт сбора';
xLang['Blacksmith']='Кузница оружия';
xLang['Armoury']='Кузница доспехов';
xLang['Palace']='Дворец';
xLang['Residence']='Резиденция';
xLang['Workshop']='Мастерская';
xLang['Barracks']='Казарма';
xLang['Town Hall']='Ратуша';
xLang['Trade']='Торговая палата';
xLang['Wood Field']='Лесопилка';
xLang['Clay Field']='Глиняный карьер';
xLang['Iron Field']='Железный рудник';
xLang['Crop Field']='Ферма';
break;
case 'com':
case 'us':
default:
xLang['Main']='Main Building';
xLang['Market']='Marketplace';
xLang['Academy']='Academy';
xLang['Embassy']='Embassy';
xLang['Granary']='Granary';
xLang['Stable']='Stable';
xLang['Wall']='City Wall'; // roman wall
xLang['Gaul Wall']='Palisade';
xLang['Teuton Wall']='Earth Wall';
xLang['Warehouse']='Warehouse';
xLang['Rally']='Rally Point';
xLang['Blacksmith']='Blacksmith';
xLang['Armoury']='Armoury';
xLang['Palace']='Palace';
xLang['Residence']='Residence';
xLang['Workshop']='Workshop';
xLang['Barracks']='Barracks';
xLang['Town Hall']='Town Hall';
xLang['Trade']='Trade Office';
xLang['Wood Field']='Woodcutter';
xLang['Clay Field']='Clay Pit';
xLang['Iron Field']='Iron Mine';
xLang['Crop Field']='Cropland';
}
cps[0] = new CP(xLang['Main'], 0,1,2,10526);
cps[1] = new CP(xLang['Main'], 1,2,1,4167);
cps[2] = new CP(xLang['Market'], 2,1,2,10526);
cps[3] = new CP(xLang['Embassy'], 3,1,5,9259);
cps[4] = new CP(xLang['Academy'], 4,1,5,9804);
cps[5] = new CP(xLang['Market'], 5,2,1,4167);
cps[6] = new CP(xLang['Granary'], 6,1,1,3704);
cps[7] = new CP(xLang['Main'], 7,4,1,2532);
cps[8] = new CP(xLang['Main'], 8,5,1,1961);
cps[9] = new CP(xLang['Palace'], 9,1,6,2553);
cps[10] = new CP(xLang['Market'], 10,4,1,2532);
cps[11] = new CP(xLang['Wall'], 11,1,1,2500);
cps[12] = new CP(xLang['Warehouse'], 12,1,1,2381);
cps[13] = new CP(xLang['Rally'], 13,1,1,2326);
cps[14] = new CP(xLang['Blacksmith'], 14,1,2,2273);
cps[15] = new CP(xLang['Armoury'], 15,1,2,2273);
cps[16] = new CP(xLang['Granary'], 16,3,1,2247);
cps[17] = new CP(xLang['Market'], 17,5,1,1961);
cps[18] = new CP(xLang['Main'], 18,6,1,1538);
cps[19] = new CP(xLang['Main'], 19,7,1,1190);
cps[20] = new CP(xLang['Main'], 20,8,2,1860);
cps[21] = new CP(xLang['Market'], 21,6,1,1538);
cps[22] = new CP(xLang['Market'], 22,7,1,1190);
cps[23] = new CP(xLang['Market'], 23,8,2,1860);
cps[24] = new CP(xLang['Academy'], 24,2,1,1538);
cps[25] = new CP(xLang['Wall'], 25,3,1,1527);
cps[26] = new CP(xLang['Embassy'], 26,2,1,1460);
cps[27] = new CP(xLang['Academy'], 27,3,1,1205);
cps[28] = new CP(xLang['Academy'], 28,4,1,935);
cps[29] = new CP(xLang['Academy'], 29,5,2,1465);
cps[30] = new CP(xLang['Warehouse'], 30,3,1,1460);
cps[31] = new CP(xLang['Residence'], 31,1,2,1274);
cps[32] = new CP(xLang['Main'], 32,9,1,730);
cps[33] = new CP(xLang['Main'], 33,10,2,1140);
cps[34] = new CP(xLang['Main'], 34,11,3,1339);
cps[35] = new CP(xLang['Rally'], 35,3,1,1429);
cps[36] = new CP(xLang['Barracks'], 36,1,1,1370);
cps[37] = new CP(xLang['Market'], 37,9,1,730);
cps[38] = new CP(xLang['Market'], 38,10,2,1140);
cps[39] = new CP(xLang['Market'], 39,11,3,1339);
cps[40] = new CP(xLang['Market'], 40,12,3,1045);
cps[41] = new CP(xLang['Main'], 41,12,3,1045);
cps[42] = new CP(xLang['Academy'], 42,6,2,1143);
cps[43] = new CP(xLang['Embassy'], 43,3,1,1130);
cps[44] = new CP(xLang['Embassy'], 44,4,1,881);
cps[45] = new CP(xLang['Embassy'], 45,5,2,1375);
cps[46] = new CP(xLang['Academy'], 46,7,2,891);
cps[47] = new CP(xLang['Academy'], 47,8,3,1045);
cps[48] = new CP(xLang['Academy'], 48,9,4,1087);
cps[49] = new CP(xLang['Main'], 49,13,3,816);
cps[50] = new CP(xLang['Main'], 50,14,5,1063);
cps[51] = new CP(xLang['Blacksmith'], 51,2,1,889);
cps[52] = new CP(xLang['Stable'], 52,1,2,2778);
cps[53] = new CP(xLang['Academy'], 53,10,4,850);
cps[54] = new CP(xLang['Workshop'], 54,1,4,2116);
cps[55] = new CP(xLang['Town Hall'], 55,1,6,1422);
cps[56] = new CP(xLang['Stable'], 56,2,1,1081);
cps[57] = new CP(xLang['Embassy'], 57,6,2,1078);
cps[58] = new CP(xLang['Market'], 58,13,3,816);
cps[59] = new CP(xLang['Market'], 59,14,5,1063);
cps[60] = new CP(xLang['Embassy'], 60,7,2,844);
cps[61] = new CP(xLang['Embassy'], 61,8,3,1031);
cps[62] = new CP(xLang['Embassy'], 62,9,4,1030);
cps[63] = new CP(xLang['Main'], 63,15,5,830);
cps[64] = new CP(xLang['Market'], 64,15,5,830);
cps[65] = new CP(xLang['Academy'], 65,11,5,831);
cps[66] = new CP(xLang['Embassy'], 66,10,4,802);
cps[67] = new CP(xLang['Main'], 67,16,6,778);
cps[68] = new CP(xLang['Main'], 68,17,7,710);
cps[69] = new CP(xLang['Main'], 69,18,9,713);
cps[70] = new CP(xLang['Main'], 70,19,11,680);
cps[71] = new CP(xLang['Main'], 71,20,13,628);
cps[72] = new CP(xLang['Market'], 72,16,6,778);
cps[73] = new CP(xLang['Market'], 73,17,7,710);
cps[74] = new CP(xLang['Market'], 74,18,9,713);
cps[75] = new CP(xLang['Market'], 75,19,11,680);
cps[76] = new CP(xLang['Market'], 76,20,13,628);
cps[77] = new CP(xLang['Embassy'], 77,11,5,784);
cps[78] = new CP(xLang['Academy'], 78,12,6,778);
cps[79] = new CP(xLang['Embassy'], 79,12,6,735);
cps[80] = new CP(xLang['Granary'], 80,6,1,1075);
cps[81] = new CP(xLang['Granary'], 81,7,1,840);
cps[82] = new CP(xLang['Barracks'], 82,3,1,837);
cps[83] = new CP(xLang['Armoury'], 83,2,1,889);
cps[84] = new CP(xLang['Academy'], 84,13,7,710);
cps[85] = new CP(xLang['Warehouse'], 85,6,1,694);
cps[86] = new CP(xLang['Academy'], 86,14,8,634);
cps[87] = new CP(xLang['Academy'], 87,15,11,681);
cps[88] = new CP(xLang['Embassy'], 88,13,7,670);
cps[89] = new CP(xLang['Embassy'], 89,14,8,598);
cps[90] = new CP(xLang['Embassy'], 90,15,11,643);
cps[91] = new CP(xLang['Academy'], 91,16,12,580);
cps[92] = new CP(xLang['Academy'], 92,17,15,566);
cps[93] = new CP(xLang['Embassy'], 93,16,12,548);
cps[94] = new CP(xLang['Warehouse'], 94,7,1,542);
cps[95] = new CP(xLang['Embassy'], 95,17,15,535);
cps[96] = new CP(xLang['Academy'], 96,18,17,502);
cps[97] = new CP(xLang['Academy'], 97,19,22,507);
cps[98] = new CP(xLang['Palace'], 98,2,1,332);
cps[99] = new CP(xLang['Palace'], 99,3,2,519);
cps[100] = new CP(xLang['Residence'], 100,2,1,498);
cps[101] = new CP(xLang['Embassy'], 101,18,17,474);
cps[102] = new CP(xLang['Embassy'], 102,19,22,479);
cps[103] = new CP(xLang['Academy'], 103,20,25,450);
cps[104] = new CP(xLang['Embassy'], 104,20,25,425);
cps[105] = new CP(xLang['Granary'], 105,9,1,514);
cps[106] = new CP(xLang['Stable'], 106,4,1,662);
cps[107] = new CP(xLang['Stable'], 107,5,1,517);
cps[108] = new CP(xLang['Wall'], 108,6,1,727);
cps[109] = new CP(xLang['Wall'], 109,7,1,567);
cps[110] = new CP(xLang['Blacksmith'], 110,4,1,542);
cps[111] = new CP(xLang['Blacksmith'], 111,5,1,424);
cps[112] = new CP(xLang['Armoury'], 112,4,1,541);
cps[113] = new CP(xLang['Armoury'], 113,5,1,423);
cps[114] = new CP(xLang['Rally'], 114,6,1,676);
cps[115] = new CP(xLang['Rally'], 115,7,1,528);
cps[116] = new CP(xLang['Stable'], 116,6,1,404);
cps[117] = new CP(xLang['Granary'], 117,10,1,402);
cps[118] = new CP(xLang['Granary'], 118,11,1,314);
cps[119] = new CP(xLang['Granary'], 119,12,2,490);
cps[120] = new CP(xLang['Blacksmith'], 120,6,1,331);
cps[121] = new CP(xLang['Armoury'], 121,6,1,331);
cps[122] = new CP(xLang['Blacksmith'], 122,7,1,258);
cps[123] = new CP(xLang['Blacksmith'], 123,8,2,404);
cps[124] = new CP(xLang['Armoury'], 124,7,1,258);
cps[125] = new CP(xLang['Armoury'], 125,8,2,404);
cps[126] = new CP(xLang['Stable'], 126,7,1,315);
cps[127] = new CP(xLang['Stable'], 127,8,2,493);
cps[128] = new CP(xLang['Granary'], 128,13,2,383);
cps[129] = new CP(xLang['Stable'], 129,9,1,193);
cps[130] = new CP(xLang['Stable'], 130,10,2,301);
cps[131] = new CP(xLang['Trade'], 131,1,4,924);
cps[132] = new CP(xLang['Palace'], 132,4,1,203);
cps[133] = new CP(xLang['Palace'], 133,5,2,317);
cps[134] = new CP(xLang['Palace'], 134,6,3,372);
cps[135] = new CP(xLang['Stable'], 135,11,3,353);
cps[136] = new CP(xLang['Warehouse'], 136,9,1,330);
cps[137] = new CP(xLang['Wall'], 137,9,1,347);
cps[138] = new CP(xLang['Wall'], 138,10,1,271);
cps[139] = new CP(xLang['Wall'], 139,11,1,212);
cps[140] = new CP(xLang['Wall'], 140,12,2,331);
cps[141] = new CP(xLang['Rally'], 141,9,1,322);
cps[142] = new CP(xLang['Granary'], 142,14,2,299);
cps[143] = new CP(xLang['Warehouse'], 143,10,1,258);
cps[144] = new CP(xLang['Warehouse'], 144,11,1,202);
cps[145] = new CP(xLang['Warehouse'], 145,12,2,315);
cps[146] = new CP(xLang['Rally'], 146,10,1,252);
cps[147] = new CP(xLang['Rally'], 147,11,1,197);
cps[148] = new CP(xLang['Rally'], 148,12,2,308);
cps[149] = new CP(xLang['Barracks'], 149,6,1,399);
cps[150] = new CP(xLang['Barracks'], 150,7,1,311);
cps[151] = new CP(xLang['Palace'], 151,7,3,290);
cps[152] = new CP(xLang['Palace'], 152,8,3,227);
cps[153] = new CP(xLang['Palace'], 153,9,5,295);
cps[154] = new CP(xLang['Residence'], 154,4,1,304);
cps[155] = new CP(xLang['Workshop'], 155,3,1,323);
cps[156] = new CP(xLang['Workshop'], 156,4,1,252);
cps[157] = new CP(xLang['Workshop'], 157,5,1,197);
cps[158] = new CP(xLang['Workshop'], 158,6,2,308);
cps[159] = new CP(xLang['Granary'], 159,15,2,234);
cps[160] = new CP(xLang['Granary'], 160,16,3,274);
cps[161] = new CP(xLang['Granary'], 161,17,4,285);
cps[162] = new CP(xLang['Stable'], 162,12,3,276);
cps[163] = new CP(xLang['Stable'], 163,13,3,215);
cps[164] = new CP(xLang['Stable'], 164,14,5,281);
cps[165] = new CP(xLang['Blacksmith'], 165,9,1,158);
cps[166] = new CP(xLang['Blacksmith'], 166,10,2,246);
cps[167] = new CP(xLang['Blacksmith'], 167,11,3,289);
cps[168] = new CP(xLang['Armoury'], 168,9,1,158);
cps[169] = new CP(xLang['Armoury'], 169,10,2,246);
cps[170] = new CP(xLang['Armoury'], 170,11,3,289);
cps[171] = new CP(xLang['Granary'], 171,18,5,279);
cps[172] = new CP(xLang['Wall'], 172,13,2,258);
cps[173] = new CP(xLang['Warehouse'], 173,13,2,246);
cps[174] = new CP(xLang['Workshop'], 174,7,2,241);
cps[175] = new CP(xLang['Rally'], 175,13,2,240);
cps[176] = new CP(xLang['Residence'], 176,5,1,237);
cps[177] = new CP(xLang['Town Hall'], 177,2,1,185);
cps[178] = new CP(xLang['Town Hall'], 178,3,2,289);
cps[179] = new CP(xLang['Palace'], 179,10,5,231);
cps[180] = new CP(xLang['Blacksmith'], 180,12,3,226);
cps[181] = new CP(xLang['Armoury'], 181,12,3,226);
cps[182] = new CP(xLang['Blacksmith'], 182,13,3,176);
cps[183] = new CP(xLang['Blacksmith'], 183,14,5,229);
cps[184] = new CP(xLang['Armoury'], 184,13,3,176);
cps[185] = new CP(xLang['Armoury'], 185,14,5,229);
cps[186] = new CP(xLang['Stable'], 186,15,5,219);
cps[187] = new CP(xLang['Granary'], 187,19,5,218);
cps[188] = new CP(xLang['Palace'], 188,11,6,216);
cps[189] = new CP(xLang['Palace'], 189,12,8,225);
cps[190] = new CP(xLang['Workshop'], 190,8,2,188);
cps[191] = new CP(xLang['Workshop'], 191,9,2,147);
cps[192] = new CP(xLang['Workshop'], 192,10,4,229);
cps[193] = new CP(xLang['Residence'], 193,6,1,185);
cps[194] = new CP(xLang['Residence'], 194,7,1,145);
cps[195] = new CP(xLang['Residence'], 195,8,2,226);
cps[196] = new CP(xLang['Stable'], 196,16,6,205);
cps[197] = new CP(xLang['Granary'], 197,20,6,204);
cps[198] = new CP(xLang['Wall'], 198,14,2,202);
cps[199] = new CP(xLang['Town Hall'], 199,4,1,113);
cps[200] = new CP(xLang['Town Hall'], 200,5,2,177);
cps[201] = new CP(xLang['Town Hall'], 201,6,3,207);
cps[202] = new CP(xLang['Warehouse'], 202,14,2,192);
cps[203] = new CP(xLang['Rally'], 203,14,2,188);
cps[204] = new CP(xLang['Stable'], 204,17,7,187);
cps[205] = new CP(xLang['Stable'], 205,18,9,188);
cps[206] = new CP(xLang['Wall'], 206,15,2,158);
cps[207] = new CP(xLang['Wall'], 207,16,3,185);
cps[208] = new CP(xLang['Wall'], 208,17,4,193);
cps[209] = new CP(xLang['Wall'], 209,18,5,188);
cps[210] = new CP(xLang['Palace'], 210,13,8,176);
cps[211] = new CP(xLang['Palace'], 211,14,11,189);
cps[212] = new CP(xLang['Warehouse'], 212,15,2,150);
cps[213] = new CP(xLang['Warehouse'], 213,16,3,176);
cps[214] = new CP(xLang['Warehouse'], 214,17,4,183);
cps[215] = new CP(xLang['Stable'], 215,19,11,180);
cps[216] = new CP(xLang['Blacksmith'], 216,15,5,179);
cps[217] = new CP(xLang['Armoury'], 217,15,5,179);
cps[218] = new CP(xLang['Barracks'], 218,9,1,190);
cps[219] = new CP(xLang['Barracks'], 219,10,1,149);
cps[220] = new CP(xLang['Barracks'], 220,11,1,116);
cps[221] = new CP(xLang['Barracks'], 221,12,2,181);
cps[222] = new CP(xLang['Rally'], 222,15,2,147);
cps[223] = new CP(xLang['Rally'], 223,16,3,172);
cps[224] = new CP(xLang['Rally'], 224,17,4,179);
cps[225] = new CP(xLang['Warehouse'], 225,18,5,179);
cps[226] = new CP(xLang['Rally'], 226,18,5,175);
cps[227] = new CP(xLang['Palace'], 227,15,13,175);
cps[228] = new CP(xLang['Blacksmith'], 228,16,6,168);
cps[229] = new CP(xLang['Armoury'], 229,16,6,168);
cps[230] = new CP(xLang['Stable'], 230,20,13,166);
cps[231] = new CP(xLang['Workshop'], 231,11,3,134);
cps[232] = new CP(xLang['Workshop'], 232,12,5,175);
cps[233] = new CP(xLang['Town Hall'], 233,7,3,162);
cps[234] = new CP(xLang['Town Hall'], 234,8,3,126);
cps[235] = new CP(xLang['Town Hall'], 235,9,5,164);
cps[236] = new CP(xLang['Palace'], 236,16,15,157);
cps[237] = new CP(xLang['Palace'], 237,17,19,156);
cps[238] = new CP(xLang['Blacksmith'], 238,17,7,153);
cps[239] = new CP(xLang['Blacksmith'], 239,18,9,154);
cps[240] = new CP(xLang['Armoury'], 240,17,7,153);
cps[241] = new CP(xLang['Armoury'], 241,18,9,154);
cps[242] = new CP(xLang['Residence'], 242,9,1,88);
cps[243] = new CP(xLang['Residence'], 243,10,2,138);
cps[244] = new CP(xLang['Residence'], 244,11,3,162);
cps[245] = new CP(xLang['Workshop'], 245,13,5,137);
cps[246] = new CP(xLang['Workshop'], 246,14,7,150);
cps[247] = new CP(xLang['Wall'], 247,19,5,147);
cps[248] = new CP(xLang['Blacksmith'], 248,19,11,147);
cps[249] = new CP(xLang['Armoury'], 249,19,11,147);
cps[250] = new CP(xLang['Barracks'], 250,13,2,142);
cps[251] = new CP(xLang['Palace'], 251,18,22,141);
cps[252] = new CP(xLang['Warehouse'], 252,19,5,140);
cps[253] = new CP(xLang['Wall'], 253,20,6,138);
cps[254] = new CP(xLang['Rally'], 254,19,5,137);
cps[255] = new CP(xLang['Blacksmith'], 255,20,13,136);
cps[256] = new CP(xLang['Armoury'], 256,20,13,136);
cps[257] = new CP(xLang['Palace'], 257,19,27,135);
cps[258] = new CP(xLang['Warehouse'], 258,20,6,131);
cps[259] = new CP(xLang['Residence'], 259,12,3,126);
cps[260] = new CP(xLang['Residence'], 260,13,3,99);
cps[261] = new CP(xLang['Residence'], 261,14,5,129);
cps[262] = new CP(xLang['Rally'], 262,20,6,128);
cps[263] = new CP(xLang['Town Hall'], 263,10,5,128);
cps[264] = new CP(xLang['Palace'], 264,20,32,125);
cps[265] = new CP(xLang['Town Hall'], 265,11,6,120);
cps[266] = new CP(xLang['Town Hall'], 266,12,8,125);
cps[267] = new CP(xLang['Workshop'], 267,15,7,117);
cps[268] = new CP(xLang['Workshop'], 268,16,9,117);
cps[269] = new CP(xLang['Workshop'], 269,17,12,122);
cps[270] = new CP(xLang['Barracks'], 270,14,2,111);
cps[271] = new CP(xLang['Trade'], 271,3,1,141);
cps[272] = new CP(xLang['Trade'], 272,4,1,110);
cps[273] = new CP(xLang['Trade'], 273,5,1,86);
cps[274] = new CP(xLang['Trade'], 274,6,2,134);
cps[275] = new CP(xLang['Town Hall'], 275,13,8,98);
cps[276] = new CP(xLang['Town Hall'], 276,14,11,105);
cps[277] = new CP(xLang['Trade'], 277,7,2,105);
cps[278] = new CP(xLang['Workshop'], 278,18,13,103);
cps[279] = new CP(xLang['Barracks'], 279,15,2,86);
cps[280] = new CP(xLang['Barracks'], 280,16,3,101);
cps[281] = new CP(xLang['Barracks'], 281,17,4,106);
cps[282] = new CP(xLang['Barracks'], 282,18,5,103);
cps[283] = new CP(xLang['Residence'], 283,15,5,100);
cps[284] = new CP(xLang['Workshop'], 284,19,16,100);
cps[285] = new CP(xLang['Town Hall'], 285,15,13,97);
cps[286] = new CP(xLang['Residence'], 286,16,6,94);
cps[287] = new CP(xLang['Trade'], 287,8,2,82);
cps[288] = new CP(xLang['Trade'], 288,9,2,64);
cps[289] = new CP(xLang['Trade'], 289,10,4,100);
cps[290] = new CP(xLang['Workshop'], 290,20,19,92);
cps[291] = new CP(xLang['Town Hall'], 291,16,15,88);
cps[292] = new CP(xLang['Town Hall'], 292,17,19,87);
cps[293] = new CP(xLang['Residence'], 293,17,7,86);
cps[294] = new CP(xLang['Residence'], 294,18,9,86);
cps[295] = new CP(xLang['Residence'], 295,19,11,82);
cps[296] = new CP(xLang['Barracks'], 296,19,5,81);
cps[297] = new CP(xLang['Town Hall'], 297,18,22,78);
cps[298] = new CP(xLang['Residence'], 298,20,13,76);
cps[299] = new CP(xLang['Barracks'], 299,20,6,75);
cps[300] = new CP(xLang['Town Hall'], 300,19,27,75);
cps[301] = new CP(xLang['Town Hall'], 301,20,32,70);
cps[302] = new CP(xLang['Trade'], 302,11,3,59);
cps[303] = new CP(xLang['Trade'], 303,12,5,76);
cps[304] = new CP(xLang['Trade'], 304,13,5,60);
cps[305] = new CP(xLang['Trade'], 305,14,7,65);
cps[306] = new CP(xLang['Trade'], 306,15,7,51);
cps[307] = new CP(xLang['Trade'], 307,16,9,51);
cps[308] = new CP(xLang['Trade'], 308,17,12,53);
cps[309] = new CP(xLang['Trade'], 309,18,13,45);
cps[310] = new CP(xLang['Trade'], 310,19,16,43);
cps[311] = new CP(xLang['Trade'], 311,20,19,40);
}