· 6 years ago · Feb 13, 2020, 05:22 PM
1// ==UserScript==
2// @name Sangu Package
3// @author Laoujin / De Goede Fee
4// @namespace sangu.be
5// @description Package for Tribal Wars bullies
6// @icon http://www.sangu.be/images/favicon.png
7// @include https://*.tribalwars.*/game.php?*
8// @include https://*.fyletikesmaxes.gr/game.php*
9// @include http://sangu.be/*
10// @include http://www.sangu.be/*
11// @version 8.197.1
12// @grant GM_xmlhttpRequest
13// ==/UserScript==
14
15//We are Sangu. You will be assimilated. Resistance is Futile.
16
17// The not-one-file source code can be found at:
18// https://github.com/SanguPackage/Script
19
20function sangu_ready() {
21 //var start_time = new Date();
22 //console.time("SanguPackage");
23 var /**
24 * When game_data.majorVersion is different from Sangu version then activate sangu 'compatibility' mode (gray icon)
25 */
26 sangu_version = '8.197.1',
27 /**
28 * true: popup with crash dump, false: don't show the popup
29 */
30 sangu_crash = sangu_version.split(".").length === 4,
31 /**
32 * jQuery element of the cell (td) that contains all page specific widgets
33 */
34 content_value = $("#content_value"),
35 /**
36 * config/ Configuration per server (nl, de). Contains stuff like ajaxAllowed, etc
37 */
38 server_settings = {},
39 /**
40 * config/ Contains all translations except for the setting related translations in sangu_trans
41 */
42 trans = {},
43 /**
44 * config/ Contains all user settings
45 */
46 user_data = {},
47 /**
48 * config/ The current world configuration. settings like hasArchers, nightbonus, etc
49 */
50 world_config = {},
51 /**
52 * config/ Contains all data for this world (resources, units, buildings, units_off, unitsSize, ...)
53 * What's in this variable depends on world_config.
54 * This variable is a complete and utter mess :)
55 */
56 world_data = {},
57 /**
58 * Identifies the current page based on the querystring
59 */
60 current_page = {
61 screen: game_data.screen,
62 mode: game_data.mode
63 },
64 keyCodeMap = {
65 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pausebreak", 20: "capslock", 27: "escape", 32: " ",
66 33: "pageup", 34: "pagedown", 35: "end", 36: "home", 37: "arrow left", 38: "arrow up", 39: "arrow right", 40: "arrow down", 43: "+",
67 44: "printscreen", 45: "insert", 46: "delete", 48: "0", 49: "1", 50: "2", 51: "3", 52: "4", 53: "5", 54: "6", 55: "7", 56: "8", 57: "9",
68 59: ";", 61: "=", 65: "a", 66: "b", 67: "c", 68: "d", 69: "e", 70: "f", 71: "g", 72: "h", 73: "i", 74: "j", 75: "k", 76: "l", 77: "m",
69 78: "n", 79: "o", 80: "p", 81: "q", 82: "r", 83: "s", 84: "t", 85: "u", 86: "v", 87: "w", 88: "x", 89: "y", 90: "z", 96: "0", 97: "1",
70 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7", 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111: "/", 112: "f1",
71 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8", 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock",
72 145: "scrolllock", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'"
73 };
74
75 server_settings = {
76 /**
77 * Calculate how many more days we can attack in vacation mode
78 */
79 maxSitDays: 60,
80 helpdeskUrl: "https://forum.tribalwars.nl/showthread.php?137674-8-11-GM-Algemeen-discussietopic-Sangu-Package",
81 /**
82 * This needs to be here for 'historical' reasons (Innogames versionchecker API remembers email on the server)
83 * when in 'compatibility' mode (gray sangu icon). Also used in the crash report.
84 */
85 sangu: "sangu.be",
86 sanguEmail: "sangu@pongit.be",
87 /**
88 * More then 500 [ cannot be sent in messages or pasted in the noteblock
89 */
90 allowedSquareBrackets: 500,
91 /**
92 * Are ajax calls allowed on this server
93 */
94 ajaxAllowed: true,
95 /*
96 * async: true on AJAX calls is only allowed when this property is true
97 */
98 asyncAjaxAllowed: false,
99 /**
100 * True: we add a direct link in the place to fill in coordinates. False: Show coords in an input field
101 */
102 coordinateLinkAllowed: false,
103 /**
104 * Can we fill in the coordinates directly in the place (using the url querystring) from troops overview
105 */
106 autoFillCoordinatesAllowed: true,
107 scriptsDatabaseUrl: "http://www.twscripts.nl/"
108 };
109
110 //$.extend(server_settings, {
111 // extraProperty: "yaye"
112 //});
113 /**
114 * Contains all translation
115 * The highest level is split in
116 * - tw = translations that should be translated by their server equivalents (they are used somewhere in the html by Innogames)
117 * - sp = new translations specific for the Sangu Package
118 */
119 trans = {
120 tw: {
121 units: {
122 names: { "spear": "Speer", "sword": "Zwaard", "archer": "Boog", "axe": "Bijl", "spy": "Verk", "light": "Lc", "marcher": "Bb", "heavy": "Zc", "ram": "Ram", "catapult": "Kata", "knight": "Ridder", "snob": "Edel" },
123 twShortNames: { "spear": "Speer", "sword": "Zwaard", "archer": "Boog", "axe": "Bijl", "spy": "Verk.", "light": "Lcav.", "marcher": "Bboog.", "heavy": "Zcav.", "ram": "Ram", "catapult": "Kata.", "knight": "Ridder", "snob": "Edel." },
124 shortNames: { "spear": "Sp", "sword": "Zw", "archer": "Boog", "axe": "Bijl", "spy": "Ver", "light": "Lc", "marcher": "Bb", "heavy": "Zc", "ram": "Ram", "catapult": "Kata", "knight": "Ridder", "snob": "Edel" },
125 militia: "Militia"
126 },
127 all: {
128 today: "vandaag om",
129 tomorrow: "morgen om",
130 dateOn: "op",
131 timeOn: "om",
132 farm: "Boerderij",
133 wood: "Hout",
134 iron: "IJzer",
135 stone: "Leem",
136 groups: "Groepen",
137 continentPrefix: "C"
138 },
139 main: {
140 loyaltyHeader: "Toestemming:"
141 },
142 command: {
143 returnText: "Terugkeer",
144 attack: "Aanval",
145 support: "Ondersteuning",
146 haul: "Buit:",
147 abortedOperation: "Afgebroken commando",
148 catapultTarget: "Katapultdoel:",
149 buttonValue: "OK",
150 attackOn: "Aanval op ",
151 supportFor: "Ondersteuning voor ",
152 walkingTimeTitle: "Duur:"
153 },
154 incoming: {
155 defaultCommandName: "Bevel"
156 },
157 place: {
158 troopMovements: "Troepenbewegingen"
159 },
160 market: {
161 incomingTransports: "Binnenkomende transporten"
162 },
163 profile: {
164 title: "Profiel",
165 claimedBy: "Geclaimd door:",
166 awardsWon: "Behaalde awards"
167 },
168 overview: {
169 village: "Dorp",
170 incomingTroops: "Aankomend"
171 }
172 },
173 sp: {
174 sp: {
175 settings: {
176 reset: "De standaard Sangu Package settings herstellen",
177 resetAll: "Sangu Package 'fabrieksinstellingen' herstellen",
178 configuration: "Configuratie",
179 configurationFormTogglerTooltip: "Klik op de knoppen om de verschillende editeerschermen te openen",
180 activate: "Activeer",
181 deleteTooltip: "Verwijderen",
182 addRecord: "» Toevoegen",
183 exportSettings: "Instellingen exporteren",
184 importSettings: "Instellingen importeren",
185 importSettingsDesc: "Door de sangu instellingen te exporteren en elders opnieuw te importeren kan je de huidige sangu configuratie hergebruiken op een andere wereld of computer.",
186 importSettingsSuccess: "Settings zijn geïmporteerd!",
187 importError: "Het ziet er naar uit dat de geplakte tekst foutief is.",
188 importErrorContinueAnyway: "Toch importeren?"
189 },
190 donate: {
191 title: "Donatie",
192 whyWouldI: "Als je op regelmatige basis functionaliteit van het Sangu Package gebruikt, dan is dat een goede reden om een donatie te doen."
193 + "<br><br>"
194 + "Jouw dankbaarheid en financiële steun helpen me motiveren verder te blijven werken aan het Sangu Package.",
195 books: "Er staan ook een aantal zeer interessante JavaScript boeken op mijn {abegin}Amazon wishlist{aend}. Daarmee kan je me ook altijd een plezier doen :)",
196 notable: "Een aantal personen hebben reeds een notabele donatie gedaan:",
197 buttonAmount: "Doneer €{amount}",
198 beer: "Trakteer me een biertje",
199 food: "Een spaghetti voor Wouter! (of pizza!)",
200 yaye: "Een nieuw IT boek voor mijn verzameling!"
201 },
202 configuration: "Sangu Package configureren (v{version})",
203 activatePackage: "Sangu Package activeren",
204 deactivatePackage: "Sangu Package deactiveren",
205 packageCrashTitle: "Het Sangu Package is gecrasht :)",
206 packageCrashTooltip: "Crash!!! Klik op de bol om het crash rapport te bekijken. "
207 + "Je kan dit rapport naar ons doorsturen waardoor we het probleem mogelijk kunnen oplossen.",
208 packageCrash:
209 "<a href='http://" + server_settings.sangu + "'>Controleer eerst of er een update is!</a><br>"
210 + "<b>Foutmelding</b>: <i>{error}</i><br>"
211 + "<b>Details</b>:<br>"
212 + "<textarea style='width: 95%' rows='20' id='crashArea'>"
213 + "Foutmelding: {error}\n"
214 + "Pagina: {title} -> {page}\n"
215 + "URL: {url}\n"
216 + "Versie: {version}\n"
217 + "Brower: {browser}\n"
218 + "game_data: {game_data}\n"
219 + "\n{stacktrace}\n"
220 + "\n\n\n[HTML]\n"
221 + "</textarea>"
222 + "<br><br>Je kan de bug <a href='{forum-url}' target='_blank'>hier</a> melden."
223 + "<br>Of je kan de bug <a href='mailto:{email}'>mailen</a>."
224 + "<br><br><center><i>Een bug waarvan we niet weten dat ie bestaat zal ook niet gefixed worden!</i></center>"
225 + "<br><center><b>Geef zoveel mogelijk informatie mee bij het sturen van een bugrapport!!!</b></center>",
226
227 activatePackageWithCompatibility: "Sangu Package (v{version}) mogelijk incompatibel met huidige TW versie",
228 firstTimeRun: "<b>Welkom!</b> Het Sangu Package is momenteel inactief. Klik op de nieuwe {img} naast de opslagplaats hierboven om het package aan en uit te schakelen.",
229 firstTimeRunEditSettings: "Klik op de nieuwe 'Sangu Package' link om het package naar jouw smaak in te stellen!",
230 removeScriptWarning: "Niet meer tonen",
231 moreScripts: "Meer scripts",
232 moreScriptsTooltip: "Ga naar de site met alle goedgekeurde TW scripts",
233 sanguLinkTitle: "Het package naar jouw smaak instellen"
234 },
235 all: {
236 populationShort: "Pop",
237 population: "Populatie",
238 total: "Totaal",
239 last: "Laatste",
240 target: "Doel",
241 targetEx: "Doelwit",
242 more: "meer",
243 less: "minder",
244 all: "Alle",
245 withText: "met",
246 merchants: "Handelaren",
247 further: "verder",
248 closer: "dichter",
249 fieldsSuffix: "(F{0})",
250 close: "Sluiten"
251 },
252 main: {
253 unitsReplacement: "Eigen",
254 unitsOther: "Ondersteunende Eenheden",
255 rallyPointTroops: "troepen",
256 ownStackTitle: "Totale populatie van de eigen troepen",
257 supportingStackTitle: "Totale populatie van de ondersteunende troepen",
258 showHiddenDivs: "» Alle verborgen terugzetten ({amount} verborgen)",
259 hideDiv: "Volledig verbergen"
260 },
261 map: {
262 dodgeLastTagged: "Dodgetijd van de laatst getagde aanval"
263 },
264 tagger: {
265 openButton: "Open Tagger",
266 rename: "Herbenoemen",
267 renameTooltip: "Alle bevelen waarvan de checkbox aangevinkt is hernoemen",
268 incomingTroops: "Binnenkomende troepen",
269 arrival: "Aankomst",
270 arrivalIn: "Aankomst in",
271 sentNow: "Zojuist",
272 sentSeconds: "seconde(n)",
273 sent1Minute: "1 minuut",
274 sentMinutes: "minuten",
275 sent1Hour: "1 uur",
276 sentHours: "uren",
277 sentOn: "Verstuurtijd",
278 ago: "Geleden",
279 arrivesInNightBonus: " (NACHT!)",
280 tagIt: "Aanval Taggen",
281 checkAllSupport: "Aanvinken van alle zichtbare ondersteuning",
282 uncheckAllSupport: "Uitvinken van alle zichtbare ondersteuning",
283 tagged: "Tagged!",
284 dodgeTime: "Dodgetijd",
285 slowest: "Traagst",
286 slowestTip: "Traagste eenheid in het dorp",
287 allAbove: "Alle vroegere aanvallen aanvinken",
288 allBelow: "Alle latere aanvallen aanvinken",
289 renameTo: "Hernoemen naar: ",
290 switchModus: "» Alle aanvallen openen/sluiten",
291 checkAllAttacks: "Aanvinken van alle zichtbare aanvallen",
292 uncheckAllAttacks: "Uitvinken van alle zichtbare aanvallen",
293 activeDodgeTime: "Actieve dodgetijd (wordt op de kaart getoond)",
294 totalAttacksOnVillage: "Aantal aanvallen",
295 renameButtonShortcutTooltip: "Shortcut: CTRL + {hitkey}"
296 },
297 place: {
298 distance: "Afstand",
299 backOn: "Terug op",
300 onlyAttack: "1 aanval op {arrivalDateFirst} ({timeLeftFirst})",
301 multipleAttack: "{amount} aanvallen tussen {arrivalDateFirst} ({timeLeftFirst}) en {arrivalDateLast} ({timeLeftLast})",
302 changeSpeedImageTooltips: "{originalTitle} - Klik om de traagste eenheid te wijzigen"
303 },
304 jumper: {
305 goToMap: "Ga naar de kaart"
306 },
307 command: {
308 returnOn: "Terug op:",
309 arrival: "Aankomst",
310 dodgeNotFarEnough: "De dodge is niet ver genoeg!",
311 dodgeMinuteReturn: "(Terugkeer na {minutes})",
312 catapultImageTitle: "Klik om gebouw te vernietigen"
313 },
314 overviews: {
315 totalVillages: "Aantal dorpen:",
316 loadNextPage: "[volgende pagina laden]"
317 },
318 troopOverview: {
319 help: "<b>Laat je looptijden uitrekenen door Sangu!</b><br>"
320 + "Gebruik de nieuwe kolom uiterst rechts om de looptijden tot een ingegeven doeldorp te berekenen.<br>"
321 + "<br>Je kan de eenheden icons ({unitIcon}) aanklikken om de snelheid van de traagste eenheid te wijzigen."
322 + "<span style='line-height: 2'>"
323 + "<br>Klikken wijzigt de <span style='border: 2px green dotted'>snelheid op de huidige pagina</span>. "
324 + "<br>Dubbelklikken wijzigt de <span style='border: 3px red solid'>snelheid op alle pagina's</span>."
325 + "</span>"
326 + "<br>De cellen met de groene en rode rand geven de huidige traagst eenheid-snelheid aan."
327 + "<br><br><b>De iconen in de 'Opdracht' kolom</b>:"
328 + "<br>Gebruik <img src='graphic/dots/red.png'> om een rij te verwijderen."
329 + "<br>Gebruik <img src='graphic/command/attack.png'> om naar de verzamelplaats te gaan."
330 + "(gebruik de middelste muisknop om in een nieuwe tab te openen)",
331 helpTitle: "Snel dorpen aanvallen (of ondersteunen)",
332 removeVillage: "Dorp verwijderen",
333 toThePlace: "Verzamelplaats",
334 setTargetVillageButton: "OK",
335 setTargetVillageButtonAlert: "Geef de coördinaten van het dorp dat je wil aanvallen (of ondersteunen)",
336 commandTitle: "Opdracht",
337 selectUnitSpeed: "Selecteer {0} als traagste eenheid. (Klik op deze pagina, Dubbel klik op alle pagina's.)",
338 nightBonus: "Nacht?",
339 village: "Dorp",
340 filterTroops: "Filter",
341 filterTroopsTooltip: "Toon enkel de dorpen met meer dan het aangegeven aantal eenheden",
342 filterPopulation: "Filter populatie",
343 filterPopulationTooltip: "Toon enkel de dorpen met meer/minder bevolking",
344 filterWalkingTime: "Filter looptijd",
345 filterWalkingTimeTooltip: "Toon enkel de dorpen met een langere looptijd (in uren) tot het doeldorp",
346 calcStack: "Bereken stack",
347 calcStackTooltip: "Toon de bevolking per dorp in de \"Nacht?\" kolom",
348 filterNoble: "Toon edels",
349 filterNobleTooltip: "Toon enkel de dorpen waar edels aanwezig zijn",
350 filterUnderAttack: "Toon onder aanval",
351 filterUnderAttackTooltip: "Toon enkel de dorpen die onder aanval zijn",
352 sort: "Sorteren",
353 sortTooltip: "Sorteren op looptijd tot doeldorp",
354 restack: "Stack BB Codes",
355 restackTitle: "<b>Alle dorpen met minstens {requiredDiff}k bevolking minder dan {to}k</b><br>"
356 + "<font size='-2'>(configuratie wijzigbaar bij Sangu instellingen)</font>",
357 cheapNobles: "Goedkope edelmannen beschikbaar",
358
359 filtersReverse: "De filtering omdraaien",
360 filtersReverseInfo: "Filters omdraaien",
361 freeTextFilter: "Tekst filter",
362 freeTextFilterTooltip: "Dorpen {filterType} de tekst wegfilteren",
363 freeTextFilterTooltipFilterTypeWith: "met",
364 freeTextFilterTooltipFilterTypeWithout: "zonder",
365 continentFilter: "Continent",
366 continentFilterTooltip: "Alle dorpen in continent wegfilteren",
367 continentFilterTooltipReverse: "Alle dorpen in continent tonen"
368 },
369 prodOverview: {
370 filter: "Filter",
371 filterFullGS: "Volle opslag",
372 merchantTooltip: "Vink aan om handelaren te highlighten",
373 merchantAmountTooltip: "Als de checkbox aangevinkt is worden dorpen met minder dan x handelaren in het rood gehighlight",
374 bbCodes: "BB Codes",
375 bbCodesInfo: "Gebruik IMG",
376 filterTooltip: "Dorpen die niet aan de filtercriteria voldoen verbergen",
377 filterTooltipReverse: "Dorpen die voldoen aan de filtercriteria highlighten",
378 filterFullGSTooltip: "Dorpen waarbij niet minstens 1 van de grondstoffen vol is verbergen",
379 filterFullGSTooltipReverse: "Dorpen waarbij minstens 1 van de grondstoffen vol is highlighten",
380 filterAllTooltip: "Dorpen waarbij niet minstens 1 van de grondstoffen meer/minder dan x is verbergen",
381 filterAllTooltipReverse: "Dorpen waarbij minstens 1 van de grondstoffen meer/minder dan x is highlighten",
382 filter1Tooltip: "Dorpen waarbij er nier meer/minder dan x {0} is verbergen",
383 filter1TooltipReverse: "Dorpen waarbij er meer/minder dan x {0} is highlighten",
384 tooMuch: "Teveel:",
385 tooMuchText: "Alle dorpen met minstens {diff}k meer grondstoffen dan {min}k",
386 tooLittle: "Te weinig:",
387 tooLittleText: "Alle dorpen met minstens {diff}k minder grondstoffen dan {min}k",
388 bbCodeExtraInfo: "<br><font size='-2'>(configuratie wijzigbaar bij Sangu instellingen)</font>"
389 },
390 buildOverview: {
391 optimistic: "Optimistisch",
392 mark: "Duiden",
393 filter: "Filteren"
394 },
395 smithOverview: {
396 optimistic: "Optimistisch",
397 mark: "Duiden",
398 filter: "Filteren"
399 },
400 defOverview: {
401 stackButton: "Totalen berekenen",
402 stackTooltip: "Totale stack en afstanden berekenen",
403 stackFilter: "Filter op stack",
404 stackFilterTooltip: "Filter dorpen met meer/minder dan x totale stack vanbuiten het dorp",
405 village: "Dorp:",
406 distFilter: "Filter op afstand",
407 distFilterTooltip: "Filter alle dorpen die verder/dichter dan x velden liggen van dorp y",
408 stackBBCodes: "Stack BBCodes",
409 stackBBCodesTooltip: "Bepaal BB codes en aantal troepen voor een stack tot x populatie voor alle zichtbare dorpen",
410 filterNoSupport: "Zonder OS wegfilteren",
411 filterNoSupportTooltip: "Wegfilteren van alle dorpen waar geen ondersteuning meer zichtbaar is",
412 extraFiltersSupport: "Ondersteunende dorpen filters:",
413 extraFiltersDefense: "Ondersteuning filters:",
414 extraFiltersReverse: "De filtering omdraaien",
415 extraFiltersInfo: "Filters omdraaien",
416 distFilter2: "Afstand filter",
417 freeTextFilter: "Tekst filter",
418 barbarianFilter: "Barbarendorpen",
419 barbarianFilterTooltip: "Toon alle ondersteuningen naar barbarendorpen",
420 nobleFilter: "Alle edel-ondersteuning tonen",
421 nobleFilterRev: "Alle edel-ondersteuning wegfilteren",
422 spyFilter: "Alle verkenner-ondersteuning tonen",
423 spyFilterRev: "Alle verkenner-ondersteuning wegfilteren",
424 attackFilter: "Alle aanval-ondersteuning tonen",
425 attackFilterRev: "Alle aanval-ondersteuning wegfilteren",
426 supportFilter: "Alle verdediging-ondersteuning tonen",
427 supportFilterRev: "Alle verdediging-ondersteuning wegfilteren",
428 otherPlayerFilterShow: "tonen",
429 otherPlayerFilterHide: "wegfilteren",
430 otherPlayerFilterTo: "Alle ondersteuningen naar andere spelers {action}",
431 otherPlayerFilterFrom: "Alle ondersteuningen van andere spelers {action}",
432
433 filterTooltipVillageTypeSupporting: "Ondersteunende dorpen",
434 filterTooltipVillageTypeSupported: "Ondersteunde dorpen",
435 freeTextFilterTooltip: "{villageType} {filterType} de tekst wegfilteren",
436 freeTextFilterTooltipFilterTypeWith: "met",
437 freeTextFilterTooltipFilterTypeWithout: "zonder",
438 distanceFilterTooltip: "{villageType} die {filterType} dan het aangegeven aantal velden liggen wegfilteren",
439 distanceFilterTooltipFilterTypeCloser: "dichter",
440 distanceFilterTooltipFilterTypeFurther: "verder",
441
442 totalFromOtherVillages: "totaal uit andere dorpen",
443 totalInOtherVillages: "totaal in andere dorpen",
444 freeText: "Vrij tekstveld (wordt niet opgeslagen!):",
445 fieldsPrefix: "F{0}",
446 thousandSuffix: "k",
447 totalVillages: "Dorpen ({0})",
448 distanceToVillageNoneEntered: "Geef een coördinaat! (eerste tekstveld)",
449 distanceToVillage: "Afstand tot {0}",
450 filterUnderAttack: "Filter onder aanval"
451 },
452 commands: {
453 filterReturn: "Filter terugkeer",
454 filterReturnTooltip: "'Teruggestuurd' en 'Terugkeer' bevelen verbergen",
455 totalRows: "Somlijn",
456 group: "Groeperen",
457 totalRowsText: "{0}x OS = {1} pop",
458 totalVillagesSupport: "Ondersteunde dorpen:",
459 totalVillagesAttack: "Aangevallen dorpen:",
460 totalSupport: "Ondersteuningen",
461 totalAttack: "Aanvallen",
462 bbCodeExport: "BBCode Export",
463 bbCodeExportTooltip: "Overblijvende aanvallen exporteren",
464 supportPlayerExport: "Ondersteuning exporteren",
465 supportPlayerExportTooltip: "Geef de naam van de speler waarvoor je de ondersteuning wil exporteren "
466 + "(of laat leeg om alle ondersteuningen te exporteren). Door de export als mededeling "
467 + "naar de andere speler door te sturen "
468 + "kan deze jouw gestuurde troepen als bevelnaam zetten. (Hij heeft daarvoor natuurlijk"
469 + " ook het Sangu Package nodig :)",
470 filtersReverse: "De filtering omdraaien",
471 filtersReverseInfo: "Filters omdraaien",
472 freeTextFilter: "Tekst filter",
473 freeTextFilterTooltip: "Aanvallen {filterType} de tekst wegfilteren",
474 freeTextFilterTooltipFilterTypeWith: "met",
475 freeTextFilterTooltipFilterTypeWithout: "zonder",
476 nobleFilter: "Alle edelaanvallen tonen",
477 nobleFilterRev: "Alle edelaanvallen wegfilteren",
478 spyFilter: "Alle verkenneraanvallen tonen",
479 spyFilterRev: "Alle verkenneraanvallen wegfilteren",
480 tableTotal: "Bevel ({0})",
481 fakeFilter: "Alle fake aanvallen wegfilteren",
482 fakeFilterRev: "Alle fake aanvallen tonen",
483 continentFilter: "Continent",
484 continentFilterTooltip: "Alle dorpen in continent wegfilteren",
485 continentFilterTooltipReverse: "Alle dorpen in continent tonen",
486 exportAttackHeader: "{village} {#} aanvallen, laatste [b]{lastAttack}[/b]",
487 exportDefenseHeader: "{village} {support#} ondersteuningen voor [b]{totalStack} pop[/b]",
488 exportCompleteHeader: "{village} {#} aanvallen, laatste [b]{lastAttack}[/b]\n+ {support#} ondersteuningen voor [b]{totalStack} pop[/b]",
489 exportNone: "Geen ondersteuning gevonden!"
490 },
491 groups: {
492 villageFilter: "Dorpsnaam",
493 villageFilterTitle: "Alle dorpen met de tekst in de dorpsnaam wegfilteren",
494 villageFilterTitleRev: "Alle dorpen met de tekst in de dorpsnaam tonen",
495 pointsFilter: "Punten",
496 amountFilter: "Aantal",
497 groupNameFilter: "Groepsnaam",
498 amountFilterTitle: "Alle dorpen met minder groepen wegfilteren",
499 amountFilterTitleRev: "Alle dorpen met meer groepen wegfilteren",
500 pointsFilterTitle: "Alle dorpen met minder punten wegfilteren",
501 pointsFilterTitleRev: "Alle dorpen met meer punten wegfilteren",
502 farmFilterTitle: "Alle dorpen met minder populatie wegfilteren",
503 farmFilterTitleRev: "Alle dorpen met meer populatie wegfilteren",
504 groupNameFilterTitle: "Alle dorpen met de tekst in een groepsnaam wegfilteren",
505 groupNameFilterTitleRev: "Alle dorpen met de tekst in een groepsnaam tonen"
506 },
507 snob: {
508 canProduce: "Je kan meteen produceren:"
509 },
510 profile: {
511 twStatsMap: "TWStats Kaart",
512 externalPage: "(Extern)",
513 internalPage: "(Intern)",
514 conquers: "Overnames",
515 villages: "Dorpen:",
516 graphPoints: "Punten",
517 graphVillages: "Dorpen",
518 graphOD: "OD Totaal",
519 graphODD: "OD Verdediging",
520 graphODA: "OD Aanval",
521 graphODS: "OD Ondersteuning",
522 graphRank: "Rang",
523 graphMembers: "Leden",
524 graphTWMap: "TribalWarsMap.com"
525 },
526 incomings: {
527 dynamicGrouping: "Dynamisch groeperen",
528 dynamicGroupingTooltip: "Groepeert trager maar bevriest de pagina niet",
529 summation: "Somlijn",
530 fastGrouping: "Snel groeperen",
531 fastGroupingTooltip: "Groepeert sneller en bevriest de pagina (geen refreshs wanneer een aanval binnenkomt)",
532 showNewIncomings: "Toon nieuwe aanvallen",
533 sortByAttackId: "Sorteer op aanvalsid",
534 sortByAttackIdTooltip: "Een kleiner aanvalsid betekent een eerder verstuurde aanval",
535 amount: "Aanvallen:",
536 attackId: "Aanvalsid",
537 attackIdDifference: "Verschil",
538 filterColumnButton: "Kolom filter",
539 filterColumnButtonTooltip: "Alle bevelen waarbij de geselecteerde kolom de ingegeven tekst bevat {type}",
540 filterColumnButtonTooltipHide: "verbergen",
541 filterColumnButtonTooltipShow: "tonen",
542
543 indicator: {
544 lastTimeCheckHintBoxTooltip: "Klik op {img} om de laatste tijdcheck met de huidige tijd te vervangen.",
545 lastTimeCheckNotYetSet: "(nog niet)"
546 },
547 commandsImport: "Ondersteuning importeren",
548 commandsImportTooltip: "Ondersteuning naar jouw dorpen kan op jouw account ingelezen worden"
549 + " door de andere speler zijn bevelen te laten exporteren via Sangu Package (Pagina Overzicht: Bevelen)"
550 + " en die export hier te plakken.",
551 commandsImportError: "Fout bij het inladen van de ondersteuningen.\nHet zou er zoals dit moeten uitzien: \n"
552 + '[{"commandName": "702|459 (speler) Zw=1 (Pop: 1)", "commandId": "7538763"}]',
553 commandsImportSuccess: "{replaced} van de {total} ondersteuningen zijn hernoemd."
554 },
555 rest: {
556 sittingAttackTill: "Aanvallen en verdedigen van dorpen niet in eigen beheer tot:",
557 friendsOnline: "Vrienden {friends} ({onlineimg} {online#} | {offlineimg} {offline#})",
558 friendsOnlineTitle: "Online: {playerNames}"
559 }
560 }
561 };
562
563 /**
564 * Log the parameter to the console (print yaye when undefined)
565 */
566 function q(what) { console.log(typeof what === "undefined" ? "yaye" : what); }
567
568 /**
569 * Alert the parameter (yaye when undefined)
570 */
571 function qa(what) { alert(typeof what === "undefined" ? "yaye" : what); }
572
573 /**
574 * Show crash report
575 */
576 function sangu_alert(e, title) {
577 var activator = $("#sangu_activator");
578
579 activator
580 .attr("src", "graphic/dots/grey.png")
581 .attr("title", trans.sp.sp.packageCrashTooltip);
582
583 (function() {
584 var position = $("#storage").position(),
585 options = {
586 left: position.left - 150,
587 top: position.top + 35
588 },
589 content = {body: trans.sp.sp.packageCrashTooltip, title: trans.sp.sp.packageCrashTitle};
590
591 createFixedTooltip("sanguCrashTooltip", content, options);
592 }());
593
594 activator.click(function() {
595 var currentPageHtml = document.documentElement.innerHTML,
596 position = $("#storage").position(),
597 options = {
598 left: $(window).width() / 2 - 300,
599 top: position.top + 35,
600 width: 600,
601 showOnce: false
602 },
603 game_dataSubset = {
604 majorVersion: game_data.majorVersion,
605 market: game_data.market,
606 world: game_data.world,
607 sitter: game_data.player.sitter,
608 village_id: game_data.village.id,
609 player_id: game_data.player.id,
610 player_name: game_data.player.name,
611 ally_id: game_data.player.ally_id,
612 villages: game_data.player.villages,
613 premium: game_data.features.Premium.active/*,
614 account_manager: game_data.features.AccountManager.active,
615 farm_manager: game_data.features.FarmAssistent.active*/
616 },
617 content = {
618 title: trans.sp.sp.packageCrashTitle,
619 body: trans.sp.sp.packageCrash
620 .replace("{forum-url}", server_settings.helpdeskUrl)
621 .replace("{title}", title)
622 .replace(/\{error\}/g, e.message)
623 .replace("{page}", JSON.stringify(current_page))
624 .replace("{url}", document.location.href)
625 .replace("{version}", sangu_version)
626 .replace("{browser}", JSON.stringify($.browser))
627 .replace("{game_data}", JSON.stringify(game_dataSubset))
628 .replace("{stacktrace}", e.stack ? e.stack + "\n\n" + e.stacktrace : "assertion?")
629 .replace("{email}", server_settings.sanguEmail)
630 .replace("{html}", currentPageHtml)
631 };
632
633 createFixedTooltip("sanguCrash", content, options);
634 $("#crashArea").val($("#crashArea").val() + currentPageHtml);
635
636 return false;
637 });
638
639 for(i = 0; i < 7; i++) {
640 activator.fadeTo('slow', 0.2).fadeTo('slow', 1.0);
641 }
642 if (sangu_crash) {
643 activator.click();
644 }
645 }
646
647 /**
648 * Failed assertions show the crash report!
649 */
650 function assert(shouldBeTruthy, message) {
651 if (!shouldBeTruthy) {
652 sangu_alert({message: message || "(broken assertion)"});
653 }
654 }
655
656 /**
657 * Show crash report
658 */
659 function handleException(e, title) {
660 console.error('oepsie', title);
661 console.error(e);
662 sangu_alert(e, title);
663 }
664 function pad(number, length) {
665 var str = '' + number;
666 while (str.length < length) {
667 str = '0' + str;
668 }
669 return str;
670 }
671
672 /**
673 * Gets a value from the querystring (or returns "")
674 * @param {string} name the name of the querystring parameter
675 * @param {string} [url] when omitted, the current location.url is assumed
676 */
677 function getQueryStringParam(name, url) {
678 name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
679 var regexS = "[\\?&]" + name + "=([^&#]*)";
680 var regex = new RegExp(regexS);
681 if( url == undefined && name == "village" ) {
682 return game_data.village.id;
683 } else {
684 var results = regex.exec(url == undefined ? window.location.href : url);
685 if (results == null) {
686 return "";
687 } else {
688 return results[1];
689 }
690 }
691 }
692
693 /**
694 * Get a TW url taking account sitting etc in account
695 * @param {string} url provide the url starting from &screen=
696 * @param {number} [villageId] when omitted the current village is assumed
697 */
698 function getUrlString(url, villageId) {
699 if (url.indexOf("?") == -1) {
700 var link = location.href.substr(0, location.href.indexOf("?"));
701 link += "?village=" + (villageId ? villageId : getQueryStringParam("village"));
702 var isSit = getQueryStringParam("t");
703 if (isSit) {
704 link += "&t=" + isSit;
705 }
706
707 if (url.indexOf("=") == -1) {
708 return link + "&screen=" + url;
709 } else {
710 return link + "&" + url;
711 }
712 } else {
713 return url;
714 }
715 }
716
717 /**
718 * Perform an ajax call (if the server allows it)
719 * @param {string} screen passed to getUrlString. (start from &screen=)
720 * @param {function} strategy executed on success. Has parameter text (content of the parameter depends on opts.contentValue)
721 * @param {object} [opts] object with properties
722 * {false|number} [villageId] passed to getUrlString. Default is false which defaults to current village. Otherwise pass a village id.
723 * {boolean=true} [contentValue] true (default): only return the #content_value. false: return entire DOM HTML
724 * {boolean=true} [async] defaults to true
725 */
726 function ajax(screen, strategy, opts) {
727 if (!server_settings.ajaxAllowed) {
728 alert("Ajax is not allowed on this server.");
729 return;
730 }
731
732 opts = $.extend({}, { villageId: false, contentValue: true, async: false }, opts);
733
734 $.ajax({
735 url: getUrlString(screen, opts.villageId),
736 async: server_settings.asyncAjaxAllowed ? opts.async : false,
737 success: function(text) {
738 text = opts.contentValue ? $("#content_value", text) : text;
739 strategy(text);
740 }
741 });
742 }
743
744 function spSpeedCookie(setter) {
745 if (setter == undefined) {
746 var speedCookie = pers.get("targetVillageSpeed");
747 if (speedCookie == '') {
748 speedCookie = 'ram';
749 }
750 return speedCookie;
751 } else {
752 if (setter.indexOf('_') == 4) {
753 setter = setter.substr(setter.indexOf('_') + 1);
754 }
755 pers.set("targetVillageSpeed", setter);
756 return setter;
757 }
758 }
759
760 function spTargetVillageCookie(setter) {
761 if (setter == undefined) {
762 return pers.get("targetVillageCoord");
763 } else {
764 pers.set("targetVillageCoord", setter);
765 return setter;
766 }
767 }
768
769 function getDistance(x1, x2, y1, y2, speed) {
770 var dist = {};
771 dist.fields = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
772 dist.travelTime = dist.fields * (speed == '' ? world_data.unitsSpeed.unit_ram : world_data.unitsSpeed['unit_' + speed]);
773 dist.arrivalTime = getDateFromTW($("#serverTime").text(), true);
774 dist.arrivalTime.setTime(dist.arrivalTime.getTime() + (dist.travelTime * 60 * 1000));
775 dist.isNightBonus = isDateInNightBonus(dist.arrivalTime);
776
777 if (speed == 'snob' && dist.travelTime > world_config.maxNobleWalkingTime) {
778 dist.html = "<font color='" + user_data.colors.error + "'><b>" + twDurationFormat(dist.travelTime) + "</b></font>";
779 dist.isNightBonus = true;
780 } else {
781 var displayTime = twDateFormat(dist.arrivalTime);
782 if (speed != 'merchant' && dist.isNightBonus) {
783 displayTime = "<font color='" + user_data.colors.error + "'><b>" + displayTime + "</b></font>";
784 }
785 dist.html = user_data.walkingTimeDisplay
786 .replace("{duration}", twDurationFormat(dist.travelTime))
787 .replace("{arrival}", displayTime);
788 }
789 if (dist.fields == 0) {
790 dist.html = "";
791 }
792
793 return dist;
794 }
795
796 // _gaq.push(['b._setAccount', 'UA-30075487-3']);
797
798 /**
799 * Send click to google analytics
800 * @param {string} action
801 */
802 function trackClickEvent(action) {
803 trackEvent("ButtonClick", action);
804 }
805
806 /**
807 * google analytics event tracking
808 */
809 function trackEvent(category, action, label) {
810 // category: clicks (downloads, ...)
811 // action: which button clicked
812 if (typeof label === 'undefined') {
813 label = getQueryStringParam("screen");
814 var mode = getQueryStringParam("mode");
815 if (mode) label += "-" + mode;
816 }
817
818 //_gaq.push(['b._setAccount', 'UA-30075487-3']);
819 //_gaq.push(['b._trackPageview']);
820 // _gat._getTrackerByName('b')._trackEvent("SanguPackage", "Loaded", "withGetB");
821 // try
822 // {
823 // _gat._getTrackerByName('b')._trackEvent(category, action, label);
824 // }
825 // catch (e) {
826 // // no crash report for this
827 // }
828 }
829
830 function fillRallyPoint(units) {
831 var script = "";
832 $.each(world_data.units, function (i, v) {
833 if (units[v] != undefined && units[v] > 0) {
834 script += "document.forms[0]." + v + ".value=\"" + units[v] + "\";";
835 } else {
836 script += "document.forms[0]." + v + ".value=\"\";";
837 }
838 });
839
840 return script;
841 }
842
843 /**
844 * Tries to find village coords in str and convert it to a 'village' object
845 * @param {string} str the string to be converted to a village object
846 * @param {true|} looseMatch !!!Do not provide a value for looseMatch when converting a real village name.!!!
847 * It should be set to true when it was the user that provided the input str. When true,
848 * a str like 456-789 would also match. (so that Sangu Package users don't have to use | but can instead
849 * use anything to seperate the 2 coordinates).
850 * @returns {object} object with parameters isValid: false when the string could not be matched and true with extra properties
851 * x, y, coord, validName (=html friendly id name) and continent
852 */
853 function getVillageFromCoords(str, looseMatch) {
854 // if str is "villageName (X|Y) C54" then the villageName could be something like "456-321"
855 // the regex then thinks that the villageName are the coords
856 // looseMatch
857 var targetMatch = looseMatch != undefined ? str.match(/(\d+)\D(\d+)/g) : str.match(/(\d+)\|(\d+)/g);
858 if (targetMatch != null && targetMatch.length > 0) {
859 var coordMatch = targetMatch[targetMatch.length - 1].match(/(\d+)\D(\d+)/);
860 var village = { "isValid": true, "coord": coordMatch[1] + '|' + coordMatch[2], "x": coordMatch[1], "y": coordMatch[2] };
861
862 village.validName = function () { return this.x + '_' + this.y; };
863 village.continent = function () { return this.y.substr(0, 1) + this.x.substr(0, 1); };
864
865 return village;
866 }
867 return { "isValid": false };
868 }
869
870 function buildAttackString(villageCoord, unitsSent, player, isSupport, minimum, haulDescription) {
871 var seperator = " ";
872 if (minimum == undefined) {
873 minimum = 0;
874 }
875
876 var totalPop = 0;
877 var renamed = villageCoord == null ? "" : villageCoord + seperator;
878 var sent = "";
879 $.each(world_data.units, function (i, val) {
880 var amount = unitsSent[val];
881 if (amount != 0) {
882 if (val == "snob") {
883 renamed += trans.tw.units.names[val] + "! ";
884 }
885 else if (amount >= minimum) {
886 sent += ", " + trans.tw.units.shortNames[val] + "=" + amount;
887 }
888
889 totalPop += amount * world_data.unitsPositionSize[i];
890 }
891 });
892
893 if (player) {
894 renamed += '(' + player + ')' + seperator;
895 }
896 if (sent.length > 2) {
897 sent = sent.substr(2);
898 }
899
900 if (isSupport) {
901 sent += seperator + "(" + trans.sp.all.populationShort + ": " + formatNumber(totalPop) + ")";
902 }
903
904 if (user_data.attackAutoRename.addHaul && typeof haulDescription !== 'undefined') {
905 sent += " (" + trans.tw.command.haul + " " + haulDescription + ")";
906 }
907
908 return renamed + sent;
909 }
910
911 function calcTroops(units) {
912 // units is an array of numbers; keys are the unit names (without unit_)
913 var x = {};
914 x.totalDef = 0;
915
916 function removeElement(arr, element) {
917 var idx = arr.indexOf(element);
918 if (idx != -1) {
919 arr.splice(idx, 1);
920 }
921 return arr;
922 }
923
924 // heavy doesn't count in determining whether the village is def/off (since you got some crazy guys using hc as offense and defense:)
925 $.each(removeElement(world_data.units_def, 'heavy'), function (i, v) { x.totalDef += units[v] * world_data.unitsSize['unit_' + v]; });
926 x.totalOff = 0;
927 $.each(removeElement(world_data.units_off, 'heavy'), function (i, v) { x.totalOff += units[v] * world_data.unitsSize['unit_' + v]; });
928
929 x.isDef = x.totalDef > x.totalOff;
930 x.isScout = units.spy * world_data.unitsSize.unit_spy > x.totalDef + x.totalOff;
931 x.isMatch = function (type) { return (type == 'all' || (type == 'def' && this.isDef) || (type == 'off' && !this.isDef)); };
932
933 x.getSlowest =
934 function () {
935 var slowest_unit = null;
936 $.each(world_data.units, function (i, v) {
937 if (units[v] > 0 && (slowest_unit == null || world_data.unitsSpeed["unit_" + slowest_unit] < world_data.unitsSpeed["unit_" + v])) {
938 slowest_unit = v;
939 }
940 });
941 return slowest_unit;
942 };
943
944 x.colorIfNotRightAttackType =
945 function (cell, isAttack) {
946 var isSet = false;
947 if (units.snob != undefined && units.snob > 0) {
948 if (isAttack) {
949 if (units.snob > 1) {
950 isSet = true;
951 cell.css("background-color", user_data.colors.error).css("border", "1px solid black");
952 cell.animate({
953 width: "70%",
954 opacity: 0.4,
955 marginLeft: "0.6in",
956 fontSize: "3em",
957 borderWidth: "10px"
958 }, 5000, function () {
959 // Animation complete.
960 });
961 } else {
962 return;
963 }
964 } else {
965 isSet = true;
966 }
967 }
968 else if (x.totalDef + x.totalOff < user_data.command.filterFakeMaxPop) {
969 // fake
970 return;
971 }
972
973 if (!isSet && (x.isScout || x.isMatch(isAttack ? 'off' : 'def'))) {
974 return;
975 }
976 cell.css("background-color", user_data.colors.error);
977 };
978
979 return x;
980 }
981
982
983 function stackDisplay(totalFarm, stackOptions) {
984 // TODO: this function is only used on main village overview
985 if (stackOptions == undefined) {
986 stackOptions = {};
987 }
988 var farmSize = game_data.village.buildings.farm * world_config.farmLimit;
989
990 var stackDesc = '<b>' + formatNumber(totalFarm);
991 if (stackOptions.showFarmLimit && world_config.farmLimit > 0) {
992 stackDesc += ' / ' + formatNumber(farmSize);
993 }
994
995 if (stackOptions.percentage) {
996 stackDesc += ' (' + stackOptions.percentage + ')</b>';
997 }
998
999 var bgColor = getStackColor(totalFarm, farmSize);
1000 if (stackOptions.cell == undefined) {
1001 return {
1002 color: bgColor,
1003 desc: stackDesc,
1004 cssColor: "style='background-color:" + bgColor + "'"
1005 };
1006 } else {
1007 if (stackOptions.appendToCell) {
1008 stackOptions.cell.append(" » " + stackDesc);
1009 } else {
1010 stackOptions.cell.html(stackDesc);
1011 }
1012 if (!stackOptions.skipColoring) {
1013 stackOptions.cell.css("background-color", bgColor);
1014 }
1015 }
1016 }
1017
1018 /**
1019 * Gets the configured stack backgroundcolor for the given stackTotal
1020 * @param stackTotal {number}
1021 * @returns {color}
1022 */
1023 function getStackColor(stackTotal) {
1024 var color = null,
1025 arrayToIterate,
1026 farmLimitModifier;
1027
1028 if (world_config.farmLimit > 0) {
1029 arrayToIterate = user_data.farmLimit.acceptableOverstack;
1030 farmLimitModifier = 30 * world_config.farmLimit;
1031 } else {
1032 arrayToIterate = user_data.farmLimit.unlimitedStack;
1033 farmLimitModifier = 1; // = No modifier
1034 }
1035
1036 if (arrayToIterate.length > 0) {
1037 $.each(arrayToIterate, function (index, configValue) {
1038 if (color == null && stackTotal < farmLimitModifier * configValue) {
1039 if (index === 0) {
1040 color = "";
1041 } else {
1042 color = user_data.farmLimit.stackColors[index - 1];
1043 //q(stackTotal +"<"+ farmLimitModifier +"*"+ configValue);
1044 //q("return " + (index - 1) + "->" + color);
1045 }
1046 return false;
1047 }
1048 });
1049
1050 if (color != null) {
1051 //q(stackTotal + " -> " + color);
1052 return color;
1053 }
1054 return user_data.farmLimit.stackColors[user_data.farmLimit.stackColors.length - 1];
1055 }
1056
1057 return "";
1058 }
1059 var modernizr = (function () {
1060 // Difference in capital letter with the Modernizr library
1061 // So nothing will break should TW start making use of it
1062 return {
1063 localstorage: (function supports_html5_storage() {
1064 try {
1065 return 'localStorage' in window && window['localStorage'] !== null;
1066 } catch (e) {
1067 return false;
1068 }
1069 })()
1070 };
1071 })();
1072
1073 var pers;
1074 (function (pers) {
1075 function getKey(key) {
1076 return 'sangu_' + key;
1077 }
1078
1079 function getWorldKey(key) {
1080 return 'sangu_' + game_data.world + '_' + key;
1081 }
1082
1083 function getCookie(key) {
1084 key = getWorldKey(key);
1085 return (function() {
1086 var x, cooks, cookie;
1087 if (document.cookie.match(/;/)) {
1088 cooks = document.cookie.split("; ");
1089 for (x = 0; x < cooks.length; x++) {
1090 cookie = cooks[x];
1091 if (cookie.match(key + "=")) {
1092 return cookie.replace(key + "=", "");
1093 }
1094 }
1095 } else {
1096 if (document.cookie.match(key + "=")) {
1097 return document.cookie.replace(key + "=", "");
1098 }
1099 }
1100
1101 return '';
1102 })();
1103 }
1104
1105 function getGlobal(key) {
1106 key = getKey(key);
1107 if (modernizr.localstorage) {
1108 var value = localStorage[key];
1109 return typeof value === 'undefined' ? '' : value;
1110 } else {
1111 return getCookie(key);
1112 }
1113 }
1114
1115 function getSession(key) {
1116 key = getWorldKey(key);
1117 if (modernizr.localstorage) {
1118 var value = sessionStorage[key];
1119 return typeof value === 'undefined' ? '' : value;
1120 } else {
1121 return getCookie(key);
1122 }
1123 }
1124
1125 function get(key) {
1126 return getGlobal(key);
1127 }
1128
1129 function setCookie(key, value, expireMinutes) {
1130 key = getWorldKey(key);
1131 (function() {
1132 var date_obj = new Date(),
1133 time = date_obj.getTime();
1134 if (typeof expireMinutes === 'undefined') {
1135 time += 60 * 1000 * 24 * 356;
1136 } else {
1137 time += expireMinutes * 1000 * 60;
1138 }
1139 date_obj.setTime(time);
1140
1141 document.cookie = key + "=" + value + ";expires=" + date_obj.toGMTString() + ";";
1142 })();
1143 }
1144
1145 function setGlobal(key, value) {
1146 key = getKey(key);
1147 if (modernizr.localstorage) {
1148 localStorage[key] = value;
1149 } else {
1150 setCookie(key, value);
1151 }
1152 }
1153
1154 function setSession(key, value) {
1155 key = getWorldKey(key);
1156 if (modernizr.localstorage) {
1157 sessionStorage[key] = value;
1158 } else {
1159 setCookie(key, value);
1160 }
1161 }
1162
1163 function set(key, value) {
1164 setGlobal(key, value);
1165 }
1166
1167 function removeSessionItem(key) {
1168 key = getKey(key);
1169 if (modernizr.localstorage) {
1170 sessionStorage.removeItem(key);
1171 }
1172 // fuck cookies
1173 }
1174
1175 function clear() {
1176 if (modernizr.localstorage) {
1177 sessionStorage.clear();
1178 localStorage.clear();
1179 }
1180 }
1181
1182 pers.removeSessionItem = removeSessionItem;
1183 pers.getWorldKey = getWorldKey;
1184 pers.getKey = getKey;
1185 pers.set = set;
1186 pers.setCookie = setCookie;
1187 pers.setGlobal = setGlobal;
1188 pers.setSession = setSession;
1189 pers.get = get;
1190 pers.getCookie = getCookie;
1191 pers.getGlobal = getGlobal;
1192 pers.getSession = getSession;
1193 pers.clear = clear;
1194 })(pers || (pers = {}));
1195 $.fn.sortElements = (function () {
1196 var sort = [].sort;
1197 return function (comparator, getSortable) {
1198 getSortable = getSortable || function () { return this; };
1199 var placements = this.map(function () {
1200 var sortElement = getSortable.call(this),
1201 parentNode = sortElement.parentNode,
1202 // Since the element itself will change position, we have
1203 // to have some way of storing its original position in
1204 // the DOM. The easiest way is to have a 'flag' node:
1205 nextSibling = parentNode.insertBefore(
1206 document.createTextNode(''),
1207 sortElement.nextSibling
1208 );
1209
1210 return function () {
1211 if (parentNode === this) {
1212 throw new Error("You can't sort elements if any one is a descendant of another.");
1213 }
1214
1215 // Insert before flag:
1216 parentNode.insertBefore(this, nextSibling);
1217 // Remove flag:
1218 parentNode.removeChild(nextSibling);
1219 };
1220 });
1221
1222 return sort.call(this, comparator).each(function (i) {
1223 placements[i].call(getSortable.call(this));
1224 });
1225 };
1226 })();
1227
1228 $.fn.outerHTML =
1229 function () {
1230 return $('<div>').append(this.clone()).remove().html();
1231 };
1232
1233 /**
1234 * Create a dialog box on a fixed position with self closing functionality
1235 * @param {string} id The DOM ID of the div
1236 * @param content .title: Short title. Defaults to Sangu Package.
1237 * .body: The HTML to show in the body of the tooltip
1238 * @param options .top: CSS top in px
1239 * .left: CSS left in px
1240 * .width: CSS width in px. Defaults to 350.
1241 * .showOnce: If true the tooltip will never be shown again once closed. Defaults to true.
1242 */
1243 function createFixedTooltip(id, content, options) {
1244 if (typeof options.width === 'undefined') {
1245 options.width = 350;
1246 }
1247 if (typeof options.showOnce === 'undefined') {
1248 options.showOnce = true;
1249 }
1250 if (typeof content.title === 'undefined') {
1251 content.title = "Sangu Package";
1252 }
1253
1254 var persKey = "fixedToolTip_"+id; // Other implementations depend on this naming
1255 if (!options.showOnce || pers.getGlobal(persKey) == '') {
1256 content_value.after('<div id="' + id + '" class="vis" style="z-index: 100001; margin: 2px; '
1257 + 'width: '+options.width+'px; display: block; position:absolute; top: '+options.top+'px; left: '+options.left+'px; border: 1px solid black; background-color: #F4E4BC">'
1258 + '<h4>' + '<img class="'+id+'closeTooltip" style="float: right; cursor: pointer;" src="graphic/minus.png">' + content.title + '</h4>'
1259 + '<div style="display: block; text-align: left; margin: 2px;">' + content.body + '</div>'
1260 + '</div>');
1261
1262 $("."+id+"closeTooltip", "#" + id).click(function() {
1263 $("#" + id).hide();
1264 if (options.showOnce) {
1265 pers.setGlobal(persKey, "1");
1266 }
1267 });
1268 }
1269 }
1270
1271 function createSpoiler(button, content, opened) {
1272 return "<div id='spoiler'><input type='button' value='" + button + "' onclick='toggle_spoiler(this)' /><div><span style='display:" + (opened ? 'block' : 'none') + "'>" + content + "</span></div></div>";
1273 }
1274
1275 function createMoveableWidget(id, title, content) {
1276 return '<div id=' + id + '+ class="vis moveable widget"><h4><img style="float: right; cursor: pointer;"'
1277 + ' onclick="return VillageOverview.toggleWidget(\'' + id + '\', this);" src="graphic/minus.png">'
1278 + title + '</h4><div style="display: block;">' + content + '</div></div>';
1279 }
1280
1281 function printCoord(village, desc) {
1282 if (server_settings.coordinateLinkAllowed) {
1283 return "<a href=# onclick=\"$('#inputx').val("+village.x+"); $('#inputy').val("+village.y+"); return false;\">" + desc + "</a>";
1284 } else {
1285 return "<b>" + desc + "</b> <input type=text onclick='this.select(); this.focus()' size=7 value='" + village.x + '|' + village.y + "'>";
1286 }
1287 }
1288
1289 // Activate / deactivate the tool
1290 var isSanguActive = pers.get("sanguActive") == "true";
1291 if (location.href.indexOf('changeStatus=') > -1) {
1292 isSanguActive = location.href.indexOf('changeStatus=true') > -1;
1293 pers.set("sanguActive", isSanguActive);
1294 pers.setGlobal("fixedToolTip_sanguActivatorTooltip", 1);
1295 }
1296
1297 var activatorImage = isSanguActive ? "green" : 'red';
1298 var activatorTitle = (!isSanguActive ? trans.sp.sp.activatePackage : trans.sp.sp.deactivatePackage) + " (v" + sangu_version + ")";
1299
1300 function isSanguCompatible() {
1301 return sangu_version.indexOf(game_data.majorVersion) === 0;
1302 }
1303
1304 // Check for new version
1305 var loginMonitor = pers.get("sanguLogin");
1306 if (typeof GM_xmlhttpRequest !== "undefined" && !isSanguCompatible() && loginMonitor !== '') {
1307 var parts = loginMonitor.match(/(\d+)/g);
1308 if (parseInt(parts[2], 10) != (new Date()).getDate()) {
1309 GM_xmlhttpRequest({
1310 method: "GET",
1311 url: "http://www.sangu.be/api/sangupackageversion.php",
1312 onload: function (response) {
1313 console.log(response.status, response.responseText.substring (0, 80));
1314 }
1315 });
1316
1317 }
1318 }
1319
1320 if (pers.get("forceCompatibility") === '' || pers.get("forceCompatibility") === 'false') {
1321 if (isSanguActive) {
1322 // Check compatibility with TW version
1323 if (!isSanguCompatible()) {
1324 try {
1325 ScriptAPI.register('Sangu Package', sangu_version, 'Laoujin', server_settings.sanguEmail);
1326 } catch (e) {
1327 $("#script_list a[href$='mailto:"+server_settings.sanguEmail+"']").after(" <a href='' id='removeScriptWarning'>"+trans.sp.sp.removeScriptWarning+"</a>");
1328 $("#removeScriptWarning").click(function() {
1329 pers.set("forceCompatibility", "true");
1330 });
1331 }
1332 }
1333 }
1334
1335 // gray icon when tw version doesn't match
1336 if (!isSanguCompatible()) {
1337 activatorImage = "grey";
1338 activatorTitle = trans.sp.sp.activatePackageWithCompatibility.replace("{version}", sangu_version);
1339 }
1340 }
1341
1342 $("#storage").parent()
1343 .after(
1344 "<td class='icon-box' nowrap><a href=" + location.href.replace("&changeStatus=" + isSanguActive, "")
1345 + "&changeStatus=" + (!isSanguActive) + "><img src='graphic/dots/" + activatorImage
1346 + ".png' title='" + activatorTitle
1347 + "' id='sangu_activator' /></a> </td>");
1348
1349 // First time run message - Position beneath resource/storage display
1350 if (!isSanguActive) {
1351 (function() {
1352 var position = $("#storage").position(),
1353 options = {
1354 left: position.left - 150,
1355 top: position.top + 35
1356 },
1357 content = {body: trans.sp.sp.firstTimeRun.replace("{img}", "<img src='graphic/dots/red.png' />")};
1358
1359 createFixedTooltip("sanguActivatorTooltip", content, options);
1360 }());
1361 } else {
1362 (function() {
1363 var position = $("#storage").position(),
1364 options = {
1365 left: position.left - 150,
1366 top: position.top + 35
1367 },
1368 content = {body: '<b>Sangu stelt zijn nieuwste tool voor: <a href="http://sangu.be">TW Tactics</a>!</b><br><br>Probeer het zeker eens voordat je vijanden het tegen jou beginnen te gebruiken!'};
1369
1370 createFixedTooltip("twTacticsTooltip", content, options);
1371 }());
1372 }
1373
1374 // User config
1375 // Configure the Sangu Package
1376
1377 /*
1378 user_data = pers.get('sangusettings');
1379 if (user_data !== '') {
1380 user_data = JSON.parse(user_data);
1381
1382 } else {*/
1383 user_data = {
1384 proStyle: true,
1385 displayDays: false, /* true: display (walking)times in days when > 24 hours. false: always displays in hours */
1386 walkingTimeDisplay: "{duration} || {arrival}",
1387
1388 colors: {
1389 error: "#FF6347",
1390 good: "#32CD32",
1391 special: "#00FFFF",
1392 neutral: "#DED3B9"
1393 },
1394
1395 global: {
1396 resources: {
1397 active: true, /* All pages: true/false: color the resources based on how much the storage is filled */
1398 backgroundColors: ['#ADFF2F', '#7FFF00', '#32CD32', '#3CB371', '#228B22', '#FFA500', '#FF7F50', '#FF6347', '#FF4500', '#FF0000'], /* All pages: Colors used for the previous setting. First is least filled, last is most filled storage place */
1399 blinkWhenStorageFull: true /* All pages: Blink the resources if the storage is full */
1400 },
1401 incomings: {
1402 editLinks: true, /* All pages: Edit the incoming attacks/support links: add "show all groups" and "show all pages" to the original links */
1403 track: true,
1404 indicator: "({current} <small>{difference}</small>)",
1405 indicatorTooltip: "Laatste tijdcheck: {elapsed} geleden",
1406 lastTimeCheckWarning: "Aanvallen: {difference}. Laatste tijdcheck: {elapsed} geleden"
1407 },
1408 visualizeFriends: true,
1409 duplicateLogoffLink: false
1410 },
1411
1412 scriptbar: {
1413 editBoxCols: 700,
1414 editBoxRows: 12
1415 },
1416
1417 main: {
1418 villageNames: [], /* Add village names to the village headquarters to quickly edit the village name to a preset name. Set to [] or null to disable, for 1 village name use ['MyVillageName'] or for more names: ['name1', 'name2', 'name3'] */
1419 villageNameClick: true, /* true: one of the previous button clicked automatically changes the village name. false: only fills in the name in the textbox but does not click the button */
1420 ajaxLoyalty: true /* Get the loyalty at the building construction/destruction page */
1421 },
1422
1423 other: {
1424 calculateSnob: true, /* nobles: calculates how many nobles can be produced immediately */
1425 reportPublish: ["own_units", "own_losses", "opp_units", "opp_losses", "carry", "buildings", "own_coords", "opp_coords", "belief"] /* Publishing report: automatically check the 'show' checkboxes */
1426 },
1427
1428 market: {
1429 resizeImage: true,
1430 autoFocus: true
1431 },
1432
1433 farmLimit: {
1434 stackColors: ['#DED3B9', '#3CB371', '#FF6347'],
1435 acceptableOverstack: [0.5, 1.2, 1.35], /* Different pages: % of acceptable overstack (only relevant for farmlimit worlds) */
1436 unlimitedStack: [24000, 60000, 100000] /* Different pages: Calculate stacks based on total troops (for non farmlimit worlds) */
1437 },
1438
1439 command: { /* features for the own troops overview page */
1440 changeTroopsOverviewLink: true, /* Change the link to the own troops overview */
1441 middleMouseClickDeletesRow2: false, /* Let the new default overwrite the old one */
1442
1443 filterMinPopulation: 18000, /* Default number filled in to filter on village stack */
1444 filterMinDefaultType: 'axe', /* This unit type is by default selected in the filter dropdown */
1445 filterMinDefault: 5000, /* The default number filled in to filter on troop amounts */
1446 filterMin: { axe: 7000, spear: 3000, archer: 3000, heavy: 500, catapult: 50, spy: 50, light: 2000, marcher: 2000, ram: 1, catapult: 50, snob: 2 }, /* Default filter numbers for the other units */
1447 filterMinOther: 5000, /* Use this number as the default when the unit is not present in filterMin */
1448 filterAutoSort: true, /* Automatically sort the list on walking distance when entering a target village */
1449
1450 /* These features apply to the commands overview page */
1451 sumRow: true, /* Add a totalrow between different villages */
1452 filterFakeMaxPop: 300, /* Commands fake filter: Everything below 300 pop is considered a fake attack */
1453 bbCodeExport: { /* BB code export */
1454 requiredTroopAmount: 100
1455 }
1456 },
1457
1458 incomings: {
1459 attackIdDescriptions: [
1460 {minValue: 10, text: " "},
1461 {minValue: 50, text: "10-50"},
1462 {minValue: 100, text: "50-100"},
1463 {minValue: 200, text: "100-200"},
1464 {minValue: 500, text: "200-500"},
1465 {minValue: 1000, text: "500-1000"},
1466 {minValue: 5000, text: "1000-5000"}
1467 ],
1468 attackIdHigherDescription: "5000+"
1469 },
1470
1471
1472 overviews: {
1473 addFancyImagesToOverviewLinks: true
1474 },
1475
1476 incoming: { /* Features for the built in TW tagger */
1477 autoOpenTagger: true, /* Open the tagger automatically if the incoming attack has not yet been renamed */
1478 forceOpenTagger: true, /* Always open the tagger automatically */
1479 renameInputTexbox: "{unit} ({xy}) {player} F{fields}{night}", /* Possibilities: {id}:internal tw attack id {unit}: short unitname {xy}: coordinates {player} {village}: full village name {c}: continent {fields} distance between the villages {night} indication when attack arrives during the nightbonus. Set to "" to disable. */
1480 villageBoxSize: 600, /* Adjust the width of the table with the village information (support for 2-click) */
1481 invertSort: true /* true=noblemen at the top and scouts at the bottom of the table */
1482 },
1483
1484 overview: { /* The default village overview page */
1485 ajaxSeperateSupport: true, /* Village overview: Seperate own and supported troops */
1486 ajaxSeperateSupportStacks: true, /* Village overview: Calculate stacks for own and supported troops */
1487 canHideDiv: true
1488 },
1489
1490 mainTagger2: {
1491 active: true,
1492 autoOpen: true,
1493 inputBoxWidth: 300,
1494 defaultDescription: "{xy} OK",
1495 otherDescs:
1496 [
1497 { active: true, name: "Dodgen", hitKey: "D", renameTo: "{xy}----------------------------------------- DODGE THIS" },
1498 { active: true, name: "Nacht", hitKey: "N", renameTo: "{xy} NIGHTBONUS" },
1499 { active: true, name: "Check stack", hitKey: "P", renameTo: "{xy}----------------------------------------- CHECK STACK" },
1500 { active: true, name: "Timen!", hitKey: "T", renameTo: "{xy}***************************************** TIME IT!" },
1501 { active: true, name: "Edelen!", hitKey: "E", renameTo: "{xy}----------------------------------------- NOBLE!!" },
1502 { active: false, name: "Leeg1", hitKey: "L", renameTo: "It has to be, automatically" },
1503 { active: false, name: "Leeg2", hitKey: "U", renameTo: "Check it out, you'd better work it out" },
1504 { active: false, name: "Leeg3", hitKey: "Y", renameTo: "Change to another route" },
1505 { active: false, name: "Leeg4", hitKey: "O", renameTo: "My techniques, strategies, abilities" }
1506 ],
1507 keepReservedWords: true,
1508 reservedWords: [
1509 "Edel.", "Edelman",
1510 "Ram", "Kata.", "Katapult",
1511 "Zcav.", "Zware cavalerie",
1512 "Lcav.", "Lichte Cavalerie", "Bereden boog", "Bboog.",
1513 "Verk.", "Verkenner",
1514 "Bijl", "Zwaard", "Speer", "Boog",
1515 "Ridder"
1516 ],
1517 autoOpenCommands: false,
1518 minutesDisplayDodgeTimeOnMap: 3,
1519 minutesWithoutAttacksDottedLine: 3 * 60,
1520 colorSupport: '#FFF5DA' /* Main village overview: give incoming support a different background color */
1521 },
1522
1523 villageInfo4: [
1524 {
1525 /* On info_village page add extra link to attack. */
1526 active: true,
1527 off_link: {
1528 name: "Aanvalleuh!",
1529 group: 0,
1530 filter: {
1531 active: true,
1532 unit: "axe",
1533 amount: 5000
1534 },
1535 sort: true,
1536 changeSpeed: "ram",
1537 icon: "graphic/unit/unit_knight.png"
1538 },
1539 def_link: {
1540 name: "Verdedigen!",
1541 group: 0,
1542 filter: {
1543 active: true,
1544 unit: "spear",
1545 amount: 4000
1546 },
1547 sort: true,
1548 changeSpeed: "spear",
1549 icon: "graphic/command/support.png"
1550 }
1551 },
1552 {
1553 /* On info_village page add extra link to attack. */
1554 active: false,
1555 off_link: {
1556 name: "» off2",
1557 group: 0,
1558 filter: {
1559 active: false,
1560 unit: "axe",
1561 amount: 4000
1562 },
1563 sort: true,
1564 changeSpeed: "ram"
1565 },
1566 def_link: {
1567 name: "» Snelle Os!",
1568 group: 0,
1569 filter: {
1570 active: true,
1571 unit: "spear",
1572 amount: 1000
1573 },
1574 sort: true,
1575 changeSpeed: "spear"
1576 }
1577 }
1578 ],
1579
1580 resources: {
1581 requiredResDefault: 250000,
1582 requiredMerchants: 50,
1583 filterMerchants: true,
1584 filterRows: false,
1585 bbcodeMinimumDiff: 50000,
1586 highlightColor: "#FF7F27"
1587 },
1588
1589 jumper: {
1590 enabled: true,
1591 autoShowInputbox: false
1592 },
1593
1594 attackAutoRename: {
1595 active: true,
1596 addHaul: false
1597 },
1598
1599 confirm: {
1600 addExtraOkButton: false,
1601 replaceNightBonus: true,
1602 replaceTribeClaim: true,
1603 addCatapultImages: true
1604 },
1605
1606 place: {
1607 attackLinks: {
1608 scoutVillage: 100,
1609 scoutPlaceLinks: [5, 100, 500],
1610 scoutPlaceLinksName: "Scout{amount}",
1611
1612 fakePlaceLink: true,
1613 fakePlaceExcludeTroops: [],
1614 fakePlaceLinkName: "Fake",
1615
1616 noblePlaceLink: true, /* (de)Activate all noble links */
1617 noblePlaceLinkFirstName: "NobleFirst", /* Name for the first noble which has most troops */
1618
1619 noblePlaceLinkSupportName: "NobleMin", /* snob with only minimal support */
1620 noblePlaceLinksForceShow: true, /* Show NobleMin also where is only one 1 snob in the village */
1621 nobleSupport: [
1622 { amount: 50, unit: 'light', villageType: 'off' },
1623 { amount: 50, unit: 'heavy', villageType: 'def'}
1624 ],
1625
1626 noblePlaceLinkDivideName: "NobleDivide",
1627 noblePlaceLinkDivideAddRam: false /* false: Rams are not sent along with NobleDivide */
1628 },
1629 customPlaceLinks:
1630 [
1631 // use minus zero numbers to leave so many units at home
1632 { active: true, type: 'def', name: 'AllDef', spear: 25000, heavy: 5000, archer: 25000, sword: 25000, sendAlong: 0 },
1633 { active: true, type: 'def', name: '1/2-Zc', spear: 4000, heavy: 1000, sendAlong: 500 },
1634 { active: true, type: 'off', name: 'Smart'/*, spear: 25000*/, sword: -10, axe: 25000, spy: 1, light: 5000/*, heavy: 5000*/, marcher: 5000, ram: 5000, catapult: 5000, sendAlong: 0 },
1635 { active: true, type: 'off', name: 'Bijl', spear: 25000, axe: 25000, spy: 1, light: 5000, heavy: 5000, marcher: 5000, sendAlong: 0 },
1636 { active: true, type: 'off', name: 'Zwaard', spear: 25000, sword: -10, axe: 25000, spy: 1, light: 5000, heavy: 5000, marcher: 5000, sendAlong: 0, required: ['sword', 1] },
1637
1638 { active: false, type: 'def', name: 'AlleDef', spear: 25000, sword: 25000, heavy: 5000, archer: 25000, sendAlong: 0 },
1639 { active: false, type: 'def', name: '3deZc', spear: 2500, heavy: 650, sendAlong: 0 },
1640 { active: false, type: 'def', name: '4deZc', spear: 2000, heavy: 500, sendAlong: 0 },
1641 { active: false, type: 'def', name: 'HelftZw', spear: 5000, sword: 5000, sendAlong: 500 },
1642 { active: false, type: 'def', name: '3deZw', spear: 3300, sword: 3300, sendAlong: 0 },
1643 { active: false, type: 'def', name: '4deZw', spear: 2500, sword: 2500, sendAlong: 0 }
1644 ]
1645 },
1646
1647 /**
1648 * units_support_detail: options on the 2 def troop overview pages
1649 * on bbcode restack - and others!!)
1650 */
1651 restack: {
1652 to: 72000,
1653 requiredDifference: 1000,
1654 fieldsDistanceFilterDefault: 30,
1655 filterReverse: true,
1656 autohideWithoutSupportAfterFilter: true,
1657 calculateDefTotalsAfterFilter: true,
1658 defaultPopulationFilterAmount: 80000, /* this isn't related to restack */
1659 removeRowsWithoutSupport: false
1660 },
1661
1662 showPlayerProfileOnVillage: false,
1663 profile: {
1664 show: true,
1665 moveClaim: true,
1666 mapLink: {
1667 show: true,
1668 fill: '#000000',
1669 zoom: '200',
1670 grid: true,
1671 playerColor: '#ffff00',
1672 tribeColor: '#0000FF',
1673 centreX: 500,
1674 centreY: 500,
1675 ownColor: '#FFFFFF',
1676 markedOnly: true,
1677 yourTribeColor: "#FF0000"
1678 },
1679 playerGraph: [["points", false], ["villages", false], ["od", false], ["oda", false], ["odd", false], ["rank", false]], // small / big / false
1680 tribeGraph: [["points", false], ["villages", false], ["od", false], ["oda", false], ["odd", false], ["rank", false], ["members", 'big', true]],
1681 twMapPlayerGraph: { player: [true, true], p_player: [false, false], oda_player: [true, false], odd_player: [true, false], ods_player: [true, false] },
1682 twMapTribeGraph: { tribe: [true, true], p_tribe: [false, false], oda_tribe: [true, false], odd_tribe: [true, false] },
1683
1684 popup: {
1685 show: true,
1686 width: 900,
1687 height: 865,
1688 left: 50,
1689 top: 50
1690 }
1691 },
1692 smithy:
1693 [
1694 ['offense', { spear: [3, 3], sword: [1, 1], axe: [3, 3], spy: [0, 0], light: [3, 3], heavy: [3, 3], ram: [2, 2], catapult: [0, 0]}],
1695 ['defense', { spear: [3, 3], sword: [1, 1], axe: [0, 3], spy: [0, 3], light: [0, 3], heavy: [3, 3], ram: [0, 1], catapult: [1, 3]}],
1696 ['catapult', { spear: [2, 3], sword: [1, 1], axe: [3, 3], spy: [0, 3], light: [2, 3], heavy: [3, 3], ram: [0, 0], catapult: [2, 3]}]
1697 ],
1698 buildings: {
1699 main: [20, 20],
1700 barracks: [25, 25],
1701 stable: [20, 20],
1702 garage: [1, 5],
1703 church: [0, 1],
1704 church_f: [0, 1],
1705 snob: [1, 3],
1706 smith: [20, 20],
1707 place: [1, 1],
1708 statue: [0, 1],
1709 market: [10, 20],
1710 wood: [30, 30],
1711 stone: [30, 30],
1712 iron: [30, 30],
1713 farm: [30, 30],
1714 storage: [30, 30],
1715 hide: [0, 10],
1716 wall: [20, 20]
1717 }
1718 };
1719 //}
1720
1721 (function() {
1722 var saved_data = pers.get('sangusettings');
1723 if (saved_data !== '') {
1724 user_data = $.extend(true, user_data, JSON.parse(saved_data));
1725 }
1726 }());
1727
1728 if (isSanguActive) {
1729 // world config: global game settings
1730 world_config = {
1731 hasMilitia: false,
1732 nightbonus: {
1733 active: false,
1734 from: 0,
1735 till: 0
1736 },
1737 smithyLevels: true,
1738 hasChurch: false,
1739 hasArchers: false,
1740 hasKnight: false,
1741 speed: 1,
1742 unitSpeed: 1,
1743 farmLimit: 0,
1744 minFake: 0,
1745 hasMinFakeLimit: false,
1746 coins: false,
1747 maxNobleWalkingTime: 999
1748 };
1749
1750 if (pers.get('worldconfig') !== '') {
1751 world_config = JSON.parse(pers.get("worldconfig"));
1752
1753 } else {
1754 // load new world through tw API
1755 if (server_settings.ajaxAllowed) {
1756 function world_config_setter_unit(configBag, unitInfoXml) {
1757 configBag.hasMilitia = $("config militia", unitInfoXml).length !== 0;
1758 }
1759
1760 function world_config_setter(configBag, infoXml) {
1761 configBag.nightbonus = {
1762 active: $("night active", infoXml).text() === "1",
1763 from: parseInt($("night start_hour", infoXml).text(), 10),
1764 till: parseInt($("night end_hour", infoXml).text(), 10)
1765 };
1766 configBag.smithyLevels = $("game tech", infoXml).text() === "1" || $("game tech", infoXml).text() === "0";
1767 configBag.hasChurch = $("game church", infoXml).text() !== "0";
1768 configBag.hasArchers = $("game archer", infoXml).text() !== "0";
1769 configBag.hasKnight = $("game knight", infoXml).text() !== "0";
1770 configBag.speed = parseFloat($("config speed", infoXml).text());
1771 configBag.unitSpeed = parseFloat($("config unit_speed", infoXml).text());
1772 configBag.farmLimit = parseInt($("game farm_limit", infoXml).text(), 10);
1773 configBag.minFake = parseInt($("game fake_limit", infoXml).text(), 10) / 100;
1774 configBag.hasMinFakeLimit = configBag.minFake > 0;
1775 configBag.coins = $("snob gold", infoXml).text() === "1";
1776 configBag.maxNobleWalkingTime = parseInt($("snob max_dist", infoXml).text(), 10) * configBag.speed * configBag.unitSpeed;
1777 }
1778
1779 function world_config_getter(world) {
1780 // world nl: http://nl16.tribalwars.nl/
1781 // world de: http://de90.die-staemme.de/
1782 if (typeof world === 'undefined') world = '';
1783
1784 var world_config = {};
1785 $.ajax({
1786 url: world + "interface.php?func=get_unit_info",
1787 async: false,
1788 success: function(xml) {
1789 world_config_setter_unit(world_config, xml);
1790 }
1791 });
1792
1793 $.ajax({
1794 url: world + "interface.php?func=get_config",
1795 async: false,
1796 success: function(xml) {
1797 world_config_setter(world_config, xml);
1798 }
1799 });
1800 return world_config;
1801 }
1802 world_config = world_config_getter();
1803
1804 } else {
1805 // Not allowed to get data with ajax: need to store the configuration here
1806 //world_config = (function() {
1807 // paste the world configurations for all worlds on servers that disallow ajax
1808 //})();
1809 alert("No configurations present for this server! (see world_config.js)\nContinueing with default settings.");
1810 }
1811
1812 pers.set("worldconfig", JSON.stringify(world_config));
1813 }
1814 // world config
1815 // RESOURCES
1816 world_data.resources = ['holz', 'lehm', 'eisen'];
1817 world_data.resources_en = ['wood', 'stone', 'iron'];
1818
1819 // BUILDINGS
1820 world_data.buildingsSize =
1821 [
1822 ["main", [5, 6, 7, 8, 9, 11, 13, 15, 18, 21, 24, 28, 33, 38, 45, 53, 62, 72, 84, 99, 116, 135, 158, 185, 216, 253, 296, 347, 406, 475]],
1823 ["barracks", [7, 8, 10, 11, 13, 15, 18, 21, 25, 29, 34, 39, 46, 54, 63, 74, 86, 101, 118, 138, 162, 189, 221, 259, 303]],
1824 ["stable", [8, 9, 11, 13, 15, 18, 21, 24, 28, 33, 38, 45, 53, 62, 72, 84, 99, 115, 135, 158]],
1825 ["garage", [8, 9, 11, 13, 15, 18, 21, 24, 28, 33, 38, 45, 53, 62, 72]],
1826 ["snob", [80, 94, 110]],
1827 ["smith", [20, 23, 27, 32, 37, 44, 51, 60, 70, 82, 96, 112, 132, 154, 180, 211, 247, 289, 338, 395]],
1828 ["place", [0]],
1829 ["market", [20, 23, 27, 32, 37, 44, 51, 60, 70, 82, 96, 112, 132, 154, 180, 211, 247, 289, 338, 395, 462, 541, 633, 740, 866]],
1830 ["wood", [5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 21, 24, 28, 33, 38, 43, 50, 58, 67, 77, 89, 103, 119, 138, 159, 183, 212, 245, 283, 326]],
1831 ["stone", [10, 11, 13, 15, 17, 19, 22, 25, 29, 33, 37, 42, 48, 55, 63, 71, 81, 93, 106, 121, 137, 157, 179, 204, 232, 265, 302, 344, 392, 447]],
1832 ["iron", [10, 12, 14, 16, 19, 22, 26, 30, 35, 41, 48, 56, 66, 77, 90, 105, 123, 144, 169, 197, 231, 270, 316, 370, 433, 507, 593, 696, 811, 949]],
1833 ["farm", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
1834 ["storage", [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
1835 ["hide", [2, 2, 3, 3, 4, 4, 5, 6, 7, 8]],
1836 ["wall", [5, 6, 7, 8, 9, 11, 13, 15, 18, 21, 24, 28, 33, 38, 45, 53, 62, 72, 84, 99]]
1837 ];
1838
1839 world_data.buildingsPoints =
1840 [
1841 ["main", [10, 12, 14, 17, 21, 25, 30, 36, 43, 52, 62, 74, 89, 107, 128, 145, 185, 222, 266, 319, 383, 460, 552, 662, 795, 954, 1145, 1648, 1978]],
1842 ["barracks", [16, 19, 23, 28, 33, 40, 48, 57, 69, 83, 99, 119, 143, 171, 205, 247, 296, 355, 426, 511, 613, 736, 883, 1060, 1272]],
1843 ["stable", [20, 24, 29, 35, 41, 50, 60, 72, 86, 103, 124, 149, 178, 214, 257, 308, 370, 444, 532, 639]],
1844 ["garage", [24, 29, 35, 41, 50, 60, 72, 86, 103, 124, 149, 178, 214, 257, 308]],
1845 ["snob", [512, 614, 737]],
1846 ["smith", [19, 23, 27, 33, 39, 47, 57, 68, 82, 98, 118, 141, 169, 203, 244, 293, 351, 422, 506, 607]],
1847 ["place", [0]],
1848 ["market", [10, 12, 14, 17, 21, 25, 30, 36, 43, 52, 62, 74, 89, 107, 128, 154, 185, 222, 266, 319, 383, 460, 552, 662, 795]],
1849 ["wood", [6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 45, 53, 64, 77, 92, 111, 133, 160, 192, 230, 276, 331, 397, 477, 572, 687, 824, 989, 1187]],
1850 ["stone", [6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 45, 53, 64, 77, 92, 111, 133, 160, 192, 230, 276, 331, 397, 477, 572, 687, 824, 989, 1187]],
1851 ["iron", [6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 45, 53, 64, 77, 92, 111, 133, 160, 192, 230, 276, 331, 397, 477, 572, 687, 824, 989, 1187]],
1852 ["farm", [5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 45, 53, 64, 77, 92, 111, 133, 160, 192, 230, 276, 331, 397, 477, 572, 687, 824, 989]],
1853 ["storage", [6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 45, 53, 64, 77, 92, 111, 133, 160, 192, 230, 276, 331, 397, 477, 572, 687, 824, 989, 1187]],
1854 ["hide", [5, 6, 7, 9, 10, 12, 15, 18, 21, 26]],
1855 ["wall", [8, 10, 12, 14, 17, 20, 24, 29, 34, 41, 50, 59, 71, 86, 103, 123, 148, 177, 213, 256]]
1856 ];
1857
1858 world_data.buildings = ["main", "barracks", "stable", "garage"];
1859 if (world_config.hasChurch) {
1860 world_data.buildingsSize.push(["church", [5000, 7750, 12013]]);
1861 world_data.buildingsSize.push(["church_f", [5]]);
1862 world_data.buildings.push("church");
1863 }
1864 world_data.buildings = world_data.buildings.concat(["snob", "smith", "place"]);
1865 if (world_config.hasKnight) {
1866 world_data.buildingsSize.push(["statue", [10]]);
1867 world_data.buildingsPoints.push(["statue", [24]]);
1868 world_data.buildings.push("statue");
1869 }
1870 world_data.buildings = world_data.buildings.concat(["market", "wood", "stone", "iron", "farm", "storage", "hide", "wall"]);
1871
1872
1873 // UNITS
1874 world_data.unitsSize = { "unit_spear": 1, "unit_sword": 1, "unit_axe": 1, "unit_spy": 2, "unit_light": 4, "unit_heavy": 6, "unit_ram": 5, "unit_catapult": 8, "unit_snob": 100 };
1875 world_data.unitsSpeed = { "unit_spear": 18, "unit_sword": 22, "unit_axe": 18, "unit_spy": 9, "unit_light": 10, "unit_heavy": 11, "unit_ram": 30, "unit_catapult": 30, "unit_snob": 35, "unit_merchant": 6 };
1876
1877 world_data.units_def = ["spear", "sword", "heavy"];
1878 world_data.units_off = ["axe", "light", "heavy"];
1879 if (!world_config.hasArchers && !world_config.hasKnight) {
1880 world_data.unitsPositionSize = [1, 1, 1, 2, 4, 6, 5, 8, 100];
1881 world_data.units = ["spear", "sword", "axe", "spy", "light", "heavy", "ram", "catapult", "snob"];
1882 } else {
1883 world_data.units = ["spear", "sword", "axe"];
1884 world_data.unitsPositionSize = [1, 1, 1];
1885 if (world_config.hasArchers) {
1886 world_data.units_off.push("marcher");
1887 world_data.units_def.push("archer");
1888 $.extend(world_data.unitsSize, { "unit_archer": 1 }, { "unit_marcher": 5 });
1889 $.extend(world_data.unitsSpeed, { "unit_archer": 18 }, { "unit_marcher": 10 });
1890 world_data.units.push("archer");
1891 world_data.unitsPositionSize.push(1);
1892 }
1893 world_data.units.push("spy");
1894 world_data.unitsPositionSize.push(2);
1895 world_data.units.push("light");
1896 world_data.unitsPositionSize.push(4);
1897 if (world_config.hasArchers) {
1898 world_data.units.push("marcher");
1899 world_data.unitsPositionSize.push(5);
1900 }
1901 world_data.units.push("heavy");
1902 world_data.unitsPositionSize.push(6);
1903 world_data.units.push("ram");
1904 world_data.unitsPositionSize.push(5);
1905 world_data.units.push("catapult");
1906 world_data.unitsPositionSize.push(8);
1907 if (world_config.hasKnight) {
1908 $.extend(world_data.unitsSize, { "unit_knight": 10 });
1909 $.extend(world_data.unitsSpeed, { "unit_knight": 10 });
1910 world_data.units.push("knight");
1911 world_data.unitsPositionSize.push(10);
1912 }
1913 world_data.units.push("snob");
1914 world_data.unitsPositionSize.push(100);
1915 }
1916
1917 // Unit speed adjustments
1918 world_config.maxNobleWalkingTime *= world_data.unitsSpeed.unit_snob;
1919 var speedModifier = world_config.speed * world_config.unitSpeed;
1920 if (speedModifier != 1) {
1921 $.each(world_data.unitsSpeed, function (index, value) {
1922 world_data.unitsSpeed[index] = world_data.unitsSpeed[index] / speedModifier;
1923 });
1924 }
1925
1926 /**
1927 * Adds a . thousands separator
1928 */
1929 function formatNumber(nStr) {
1930 nStr += '';
1931 var x = nStr.split('.');
1932 var x1 = x[0];
1933 var x2 = x.length > 1 ? '.' + x[1] : '';
1934 var rgx = /(\d+)(\d{3})/;
1935 while (rgx.test(x1)) {
1936 x1 = x1.replace(rgx, '$1' + '.' + '$2');
1937 }
1938 return x1 + x2;
1939 }
1940 // DATETIME FUNCTIONS
1941 function prettyDate(diff, showSeconds) {
1942 diff = diff / 1000;
1943 if (diff < 0) {
1944 return " ";
1945 }
1946 if (diff < 60) {
1947 if (showSeconds) {
1948 return diff + " " + trans.sp.tagger.sentSeconds;
1949 }
1950 return trans.sp.tagger.sentNow;
1951 }
1952 if (diff < 120) {
1953 return trans.sp.tagger.sent1Minute;
1954 }
1955 if (diff < 3600) {
1956 return Math.floor(diff / 60) + " " + trans.sp.tagger.sentMinutes;
1957 }
1958 if (diff < 7200) {
1959 return trans.sp.tagger.sent1Hour + ", " + Math.floor((diff - 3600) / 60) + " " + trans.sp.tagger.sentMinutes;
1960 }
1961 return Math.floor(diff / 3600) + " " + trans.sp.tagger.sentHours + ", " + Math.floor((diff % 3600) / 60) + " " + trans.sp.tagger.sentMinutes;
1962 }
1963
1964 function twDurationFormat(num) {
1965 var days = 0;
1966 if (user_data.displayDays) {
1967 days = Math.floor(num / 1440);
1968 }
1969 num -= days * 1440;
1970 var hours = Math.floor(num / 60);
1971 num -= hours * 60;
1972 var mins = Math.floor(num);
1973 num -= mins;
1974 var secs = Math.round(num * 60);
1975
1976 if (days > 0) {
1977 return days + '.' + pad(hours, 2) + ':' + pad(mins, 2) + ':' + pad(secs, 2);
1978 } else {
1979 return pad(hours, 2) + ':' + pad(mins, 2) + ':' + pad(secs, 2);
1980 }
1981 }
1982
1983 function twDateFormat(dat, alwaysPrintFullDate, addYear) {
1984 var day = dat.getDate();
1985 var cur = new Date().getDate();
1986
1987 if (!alwaysPrintFullDate && day == cur) {
1988 return trans.tw.all.today + " " + pad(dat.getHours(), 2) + ':' + pad(dat.getMinutes(), 2) + ':' + pad(dat.getSeconds(), 2);
1989 }
1990 else if (!alwaysPrintFullDate && day == cur + 1) {
1991 return trans.tw.all.tomorrow + " " + pad(dat.getHours(), 2) + ':' + pad(dat.getMinutes(), 2) + ':' + pad(dat.getSeconds(), 2);
1992 }
1993 else if (addYear) {
1994 return trans.tw.all.dateOn + " " + dat.getDate() + "." + pad(dat.getMonth() + 1, 2) + "." + (dat.getFullYear() + '').substr(2) + " " + pad(dat.getHours(), 2) + ':' + pad(dat.getMinutes(), 2) + ':' + pad(dat.getSeconds(), 2); // + "(" + dat.getFullYear() + ")";
1995 } else {
1996 return trans.tw.all.dateOn + " " + dat.getDate() + "." + pad(dat.getMonth() + 1, 2) + ". " + pad(dat.getHours(), 2) + ':' + pad(dat.getMinutes(), 2) + ':' + pad(dat.getSeconds(), 2); // + "(" + dat.getFullYear() + ")";
1997 }
1998 }
1999
2000 function getTimeFromTW(str) {
2001 // NOTE: huh this actually returns the current date
2002 // with some new properties with the "str" time
2003 //17:51:31
2004 var timeParts = str.split(":");
2005 var seconds = timeParts[2];
2006 var val = {};
2007 val.hours = parseInt(timeParts[0], 10);
2008 val.minutes = parseInt(timeParts[1], 10);
2009 if (seconds.length > 2) {
2010 var temp = seconds.split(".");
2011 val.seconds = parseInt(temp[0], 10);
2012 val.milliseconds = parseInt(temp[1], 10);
2013 } else {
2014 val.seconds = parseInt(seconds, 10);
2015 }
2016 val.totalSecs = val.seconds + val.minutes * 60 + val.hours * 3600;
2017 return val;
2018 }
2019
2020 function getDateFromTW(str, isTimeOnly) {
2021 //13.02.11 17:51:31
2022 var timeParts, seconds;
2023 if (isTimeOnly) {
2024 timeParts = str.split(":");
2025 seconds = timeParts[2];
2026 var val = new Date();
2027 val.setHours(timeParts[0]);
2028 val.setMinutes(timeParts[1]);
2029 if (seconds.length > 2) {
2030 var temp = seconds.split(".");
2031 val.setSeconds(temp[0]);
2032 val.setMilliseconds(temp[1]);
2033 } else {
2034 val.setSeconds(seconds);
2035 }
2036 return val;
2037 } else {
2038 var parts = str.split(" ");
2039 var dateParts = parts[0].split(".");
2040 timeParts = parts[1].split(":");
2041 seconds = timeParts[2];
2042 var millis = 0;
2043 if (seconds.length > 2) {
2044 var temp = seconds.split(".");
2045 seconds = temp[0];
2046 millis = temp[1];
2047 } if (dateParts[2].length == 2) {
2048 dateParts[2] = (new Date().getFullYear() + '').substr(0, 2) + dateParts[2];
2049 }
2050
2051 return new Date(dateParts[2], (dateParts[1] - 1), dateParts[0], timeParts[0], timeParts[1], seconds, millis);
2052 }
2053 }
2054
2055 function getDateFromTodayTomorrowTW(str) {
2056 var currentT = new Date();
2057 var dateParts = [];
2058 var parts = $.trim(str).split(" ");
2059 if (str.indexOf(trans.tw.all.tomorrow) != -1) {
2060 // morgen om 06:35:29 uur
2061 dateParts[0] = currentT.getDate() + 1;
2062 dateParts[1] = currentT.getMonth();
2063 } else if (str.indexOf(trans.tw.all.today) != -1) {
2064 // vandaag om 02:41:40 uur
2065 dateParts[0] = currentT.getDate();
2066 dateParts[1] = currentT.getMonth();
2067 } else {
2068 // op 19.05. om 11:31:51 uur
2069 dateParts = parts[1].split(".");
2070 dateParts[1] = parseInt(dateParts[1], 10) - 1;
2071 }
2072
2073 // last part is "hour" but there is a script from lekensteyn that
2074 // corrects the projected arrival time each second
2075 // the script has not been updated to add the word "hour" after the time.
2076 var timeParts = parts[parts.length - 2].split(":");
2077 if (timeParts.length === 1) {
2078 timeParts = parts[parts.length - 1].split(":");
2079 }
2080
2081 var seconds = timeParts[2];
2082 var millis = 0;
2083 if (seconds.length > 2) {
2084 var temp = seconds.split(".");
2085 seconds = temp[0];
2086 millis = temp[1];
2087 }
2088
2089 return new Date(new Date().getFullYear(), dateParts[1], dateParts[0], timeParts[0], timeParts[1], seconds, millis);
2090 }
2091
2092 function isDateInNightBonus(date) {
2093 if (!world_config.nightbonus.active) return false;
2094 return date.getHours() >= world_config.nightbonus.from && date.getHours() < world_config.nightbonus.till;
2095 }
2096 function getBuildingSpace() {
2097 var total = 0;
2098 for (var building = 0; building < world_data.buildingsSize.length; building++) {
2099 var b = world_data.buildingsSize[building];
2100 if (parseInt(game_data.village.buildings[b[0]], 10) > 0) {
2101 total += b[1][parseInt(game_data.village.buildings[b[0]], 10) - 1];
2102 }
2103 }
2104 return total;
2105 }
2106
2107 function getBuildingPoints() {
2108 var total = 0;
2109 for (var building = 0; building < world_data.buildingsPoints.length; building++) {
2110 var b = world_data.buildingsPoints[building];
2111 if (parseInt(game_data.village.buildings[b[0]], 10) > 0) {
2112 total += b[1][parseInt(game_data.village.buildings[b[0]], 10) - 1];
2113 }
2114 }
2115 return total;
2116 }
2117
2118 if (user_data.jumper.enabled) {
2119 (function() {
2120 //console.time("jumper");
2121 try {
2122 var cell = "<span style='display: none;' id=sanguJumperFrame>";
2123 cell += "<input type=text type=text size=6 id=sangujumper style='height: 16px; border: 0; top: -2px; position: relative'>";
2124 cell += "</span>";
2125 cell += " <a href=# id=sangujumperOpen><span class='icon ally internal_forum' title='" + trans.sp.jumper.goToMap + "'></span></a>";
2126 $("#menu_row2").append("<td>" + cell + "</td>");
2127
2128 $("#sangujumper").keyup(function (e) {
2129 if (e.which == 13) {
2130 $("#sangujumperOpen").click();
2131 }
2132 });
2133
2134 $("#sangujumperOpen").click(function () {
2135 var input = $("#sangujumper");
2136 if ($("#sanguJumperFrame").is(":visible")) {
2137 var village = getVillageFromCoords(input.val(), true);
2138 if (village.isValid) {
2139 trackClickEvent("JumperOpen_RealValue");
2140 // Jump to coordinates on the map
2141 location.href = getUrlString("&screen=map&x=" + village.x + "&y=" + village.y);
2142
2143 } else {
2144 // incorrect coordinates
2145 if (!$("#sangujumperpos").is(":visible")) {
2146 $("#sangujumperpos").show();
2147 input.css("border", "1px solid red");
2148 } else
2149 $("#sangujumperpos").hide();
2150 }
2151 } else {
2152 // activate mapJumper
2153 var input = $("#sangujumper");
2154 if (input.val() == "") {
2155 $("#sanguJumperFrame").fadeIn();
2156 } else {
2157 $("#sanguJumperFrame").show();
2158 $("#sangujumperOpen").click();
2159 }
2160 }
2161
2162 return false;
2163 });
2164
2165 if (user_data.jumper.autoShowInputbox) {
2166 $("#sangujumperOpen").click();
2167 }
2168 } catch (e) { handleException(e, "jumper"); }
2169 //console.timeEnd("jumper");
2170 }());
2171 }
2172 // Send usage statistics to GA once/day
2173 (function() {
2174 //console.time("ga");
2175 try {
2176 var loginMonitor = pers.get("sanguLogin");
2177 if (loginMonitor !== '') {
2178 var parts = loginMonitor.match(/(\d+)/g);
2179 loginMonitor = new Date(parts[0], parts[1]-1, parts[2]);
2180
2181 //if (Math.abs(loginMonitor.getTime() - (new Date()).getTime()) > 1000 * 3600 * 24) {
2182 if (parseInt(parts[2], 10) != (new Date()).getDate()) {
2183 loginMonitor = '';
2184 }
2185 }
2186 if (loginMonitor === '') {
2187 loginMonitor = new Date();
2188 loginMonitor.setHours(0, 0, 0);
2189 loginMonitor = loginMonitor.getFullYear() + '-' + pad(loginMonitor.getMonth()+1, 2) + '-' + pad(loginMonitor.getDate(), 2);
2190 trackEvent("ScriptUsage", "DailyUsage", loginMonitor);
2191 pers.set("sanguLogin", loginMonitor);
2192
2193 // also log world/tribe usage
2194 trackEvent("ScriptUsage", "WorldUsage", game_data.world);
2195 trackEvent("ScriptUsage", "TribeUsage", game_data.world + " " + game_data.player.ally_id);
2196 trackEvent("ScriptUsage", "HasPremium", game_data.features.Premium.active ? "Yes" : "No"); // Do we need to support non PA users?
2197 trackEvent("ScriptUsage", "HasAM", game_data.features.AccountManager.active ? "Yes" : "No"); // Do we need to do stuff on the AM pages?
2198 }
2199 } catch (e) { handleException(e, "ga"); }
2200 //console.timeEnd("ga");
2201 }());
2202
2203 q("-------------------------------------------------------------------- Start: "+sangu_version);
2204
2205 // BEGIN PAGE PROCESSING
2206 switch (current_page.screen) {
2207 case "overview":
2208 // MAIN VILLAGE OVERVIEW
2209 (function() {
2210 /**
2211 * The slowest unit in the village in the form unit_spear
2212 */
2213 var slowest_unit = null;
2214
2215 (function() {
2216 /**
2217 * Each key is in the form unit_sword and holds the total amount of the type in the village
2218 * (own and supporting troops combined)
2219 */
2220 var totalUnits = {},
2221 /**
2222 * Total population of all units (own + supporting)
2223 */
2224 totalFarm = 0,
2225 /**
2226 * Own population only (total - supporting)
2227 */
2228 ownFarmTotal = 0,
2229 /**
2230 * jQuery div with the troops in the village (becomes the own troops only div)
2231 */
2232 unitTable = $("#show_units"),
2233 /**
2234 * HTML table builder string for the supporting troops div
2235 */
2236 supportingTroopsTable = "<table class=vis width='100%'>";
2237
2238 try {
2239 $("#show_units > h4").prepend(trans.sp.main.unitsReplacement);
2240
2241 // calculate current stack
2242 $("table:first tr.all_unit td", unitTable).each(function () {
2243 if (!$('img', this)[0]) {
2244 // Cell containing: "< Eigen/Ander/Alle >" toggles
2245 return;
2246 }
2247
2248 var unit = $('img', this)[0].src,
2249 unitsSize,
2250 unitAmount;
2251
2252 unit = unit.substr(unit.lastIndexOf('/') + 1);
2253 unit = unit.substr(0, unit.lastIndexOf('.'));
2254 unitsSize = world_data.unitsSize[unit];
2255 unitAmount = $('strong', this);
2256 unitAmount[0].id = "spAmount" + unit;
2257 unitAmount = unitAmount[0].innerHTML;
2258 if( unit.match("knight") && !unitAmount ) {
2259 unitAmount = 1;
2260 }
2261 totalUnits[unit] = unitAmount;
2262 totalFarm += unitsSize * unitAmount;
2263
2264 if (slowest_unit == null || world_data.unitsSpeed[slowest_unit] < world_data.unitsSpeed[unit]) {
2265 slowest_unit = unit;
2266 }
2267 });
2268
2269 // fetch own troops
2270 if (user_data.overview.ajaxSeperateSupport && totalFarm > 0) {
2271 if (server_settings.ajaxAllowed) {
2272 ajax("place",
2273 function (placeText) {
2274 if (placeText.find(".unitsInput").size() > 0) {
2275 slowest_unit = null;
2276 placeText.find(".unitsInput").each(function () {
2277 // separate own / supporting troops
2278 var unit = 'unit_' + this.id.substr(this.id.lastIndexOf("_") + 1);
2279 var unitAmount = $(this).next().text().substr(1);
2280 unitAmount = parseInt(unitAmount.substr(0, unitAmount.length - 1), 10);
2281 var unitsSize = world_data.unitsSize[unit];
2282 ownFarmTotal += unitsSize * unitAmount;
2283
2284 var unitLabel = $("#spAmount" + unit);
2285 var supportingTroopsAmount = totalUnits[unit] - unitAmount;
2286 if (supportingTroopsAmount > 0) {
2287 var unitDesc = $.trim(unitLabel.parent().text());
2288 unitDesc = unitDesc.substr(unitDesc.indexOf(" ") + 1);
2289 supportingTroopsTable +=
2290 "<tr><td>" + unitLabel.prev().outerHTML()
2291 + " <b>" + formatNumber(supportingTroopsAmount)
2292 + "</b> "
2293 + unitDesc + "</td></tr>";
2294 }
2295
2296 if (unitAmount > 0) {
2297 unitLabel.text(unitAmount);
2298 if (slowest_unit == null || world_data.unitsSpeed[slowest_unit] < world_data.unitsSpeed[unit]) {
2299 slowest_unit = unit;
2300 }
2301 } else {
2302 unitLabel.parent().parent().hide();
2303 }
2304 });
2305
2306 } else {
2307 ownFarmTotal = totalFarm; // No rally point
2308 }
2309 }, {async: false});
2310
2311 } else {
2312 ownFarmTotal = totalFarm; // No ajax
2313 }
2314
2315 if (slowest_unit != null) {
2316 $("#slowestUnitCell").html("<img title='"+trans.sp.tagger.slowestTip+"' src='graphic/unit/" + slowest_unit + ".png'>").attr("slowestUnit", slowest_unit);
2317 }
2318
2319 if (ownFarmTotal > 0 && user_data.overview.ajaxSeperateSupportStacks) {
2320 // stack in the village
2321 unitTable.find("table tfoot").append("<tr><td><span class='icon header population' title='" + trans.sp.main.ownStackTitle + "'></span>" + stackDisplay(ownFarmTotal).desc + "</td></tr>");
2322 }
2323 if (totalFarm - ownFarmTotal > 0) {
2324 // stack from other villages
2325 supportingTroopsTable += "<tr><td><a href='" + getUrlString("screen=place&mode=units") + "'>» " + trans.sp.main.rallyPointTroops + "</a></td></tr>";
2326 if (user_data.overview.ajaxSeperateSupportStacks) {
2327 (function() {
2328 var supportDisplay = stackDisplay(totalFarm - ownFarmTotal, { showFarmLimit: true });
2329 supportingTroopsTable +=
2330 '<tr><td style="border-top: 1px solid #85550d ;background-color: ' + supportDisplay.color + '">'
2331 + '<span class="icon header population" title="' + trans.sp.main.supportingStackTitle
2332 + '"></span>'
2333 + '<b>' + supportDisplay.desc + '</b>' + '</td></tr>';
2334 }());
2335 }
2336
2337 unitTable.after(createMoveableWidget("os_units", trans.sp.main.unitsOther, supportingTroopsTable + "</table>"));
2338 }
2339
2340 // total stack
2341 (function() {
2342 var cell = $("#order_level_farm"),
2343 isClassicOverview = cell.length !== 0,
2344 percentage,
2345 stackDetails,
2346 cellContent;
2347
2348 if (isClassicOverview) {
2349 cell = cell.parent();
2350 if (game_data.features.Premium.active) {
2351 cell = cell.next();
2352 }
2353 percentage = world_config.farmLimit == 0 ? "" : cell.children().html();
2354 stackDisplay(
2355 totalFarm, {
2356 showFarmLimit: true,
2357 percentage: percentage ? percentage.substr(0, percentage.indexOf('%') + 1) : "",
2358 cell: cell,
2359 appendToCell: !game_data.features.Premium.active
2360 });
2361
2362 } else {
2363 stackDetails = stackDisplay(
2364 totalFarm, {
2365 showFarmLimit: true,
2366 percentage: $("#l_farm .building_extra").html()
2367 });
2368
2369 //cellContent = '<tr><td style="border-top: 1px solid #85550d ;background-color: ' + stackDetails.color + '">' + '<b>' + trans.tw.all.farm + ': ' + stackDetails.desc + '</b>' + '</td></tr>';
2370 cellContent = ' | <b>' + trans.tw.all.farm + ': ' + stackDetails.desc + '</b>';
2371 $("#show_units tfoot:first td:last").append(cellContent).css("border-top", "1px solid #85550d").css("background-color", stackDetails.color);
2372 }
2373 }());
2374 }
2375 }
2376 catch (e) {
2377 handleException(e, "supportingunits");
2378 }
2379 }());
2380 // Incoming/outgoing attacks
2381 var mainTable = $("#overviewtable");
2382 var incomingTable = $("#show_incoming_units table.vis:first");
2383 var outgoingTable = $("#show_outgoing_units");
2384 if (incomingTable.size() == 1 || outgoingTable.size() == 1) {
2385 if (incomingTable.size() == 1) {
2386 // tagger - add header
2387 // inputBoxWidth : clicking the button focusses the newly created inputbox
2388 // solution is to no longer show inputboxes on screen load
2389 /*if (user_data.mainTagger2.inputBoxWidth != null) {
2390 $("a.rename-icon", incomingTable).click();
2391 $("span.quickedit", incomingTable).each(function() {
2392 var renameSpan = this;
2393 //setTimeout(function() {
2394 $("span.quickedit-edit input:first", renameSpan).width(user_data.mainTagger2.inputBoxWidth);
2395 //}, 1);
2396 });
2397 }*/
2398
2399 if (user_data.mainTagger2.active && incomingTable.has("img[src*='attack']").size() != 0) {
2400 $("th:first", incomingTable).append("<input type=button value='" + trans.sp.tagger.openButton + "' id=openTaggerButton>");
2401 $("#openTaggerButton").click(function () {
2402 $(this).hide();
2403
2404 incomingTable.click(function (e) {
2405 if (e.target.nodeName === 'IMG') {
2406 var direction = $(e.target).attr("direction");
2407 if (direction.length > 0) {
2408 var rowIndex = parseInt($(e.target).attr("rowIndex"), 10);
2409 direction = direction == "up";
2410 $("input.incAt", incomingTable).each( function () {
2411 var rowIndexAttributeValue = parseInt($(this).attr("rowIndex"), 10);
2412 if ((direction && rowIndexAttributeValue <= rowIndex) || (!direction && rowIndexAttributeValue >= rowIndex)) {
2413 $(this).prop("checked", true);
2414 } else {
2415 $(this).prop("checked", false);
2416 }
2417 });
2418 }
2419 }
2420 });
2421
2422 var rows = $("tr", incomingTable);
2423 var dodgeMenu = "<tr><td>";
2424 dodgeMenu += '<img src="graphic/command/support.png" alt="" id="checkSupport" title="' + trans.sp.tagger.checkAllSupport + '" />';
2425 dodgeMenu += " ";
2426 dodgeMenu += '<img src="graphic/command/return.png" alt="" id="uncheckSupport" title="' + trans.sp.tagger.uncheckAllSupport + '" />';
2427 dodgeMenu += "<th colspan=3>";
2428 dodgeMenu += trans.sp.tagger.renameTo + "<input type=textbox size=30 id=commandInput value='" + user_data.mainTagger2.defaultDescription + "'></th>";
2429 dodgeMenu += "<th>" + trans.sp.tagger.slowest + "</th>";
2430 dodgeMenu += "</td>";
2431 dodgeMenu += "<td colspan=1 id=slowestUnitCell>";
2432 if (slowest_unit != null) {
2433 dodgeMenu += "<img title='"+trans.sp.tagger.slowestTip+"' src='graphic/unit/" + slowest_unit + ".png' slowestunit='" + slowest_unit + "'>";
2434 }
2435 dodgeMenu += "</td></tr>";
2436 incomingTable.find("tbody:first").prepend(dodgeMenu);
2437
2438 // checkbox manipulation
2439 $("#uncheckSupport").click(function () {
2440 $("input.incSupport", incomingTable).prop("checked", false);
2441 });
2442
2443 $("#checkSupport").click(function () {
2444 $("input.incSupport", incomingTable).prop("checked", true);
2445 });
2446
2447 var buttonParent = $("#commandInput").parent();
2448 var commandIdToCoordCache = []; // No Ajax call on multiple renames with {xy}
2449 function renameCommand(commandName) {
2450 var dodgeCell; // capture last cell for dodgeCell coloring
2451
2452 function getCommandIdFromDodgeCell(dodgeCell) {
2453 return Number(dodgeCell.find("span.quickedit").first().attr("data-id"));
2454 }
2455
2456 function getVillageCoordsFromCommandId(commandId, callback) {
2457 if (server_settings.ajaxAllowed) {
2458 if (commandIdToCoordCache[commandId]) {
2459 callback(commandIdToCoordCache[commandId]);
2460
2461 } else {
2462 ajax('screen=info_command&type=other&id='+commandId, function (overview) {
2463 var originVillageLink = $(".village_anchor:first", overview).find("a[href]"),
2464 originVillageDesc = originVillageLink.html(),
2465 originVillage = getVillageFromCoords(originVillageDesc);
2466
2467 commandIdToCoordCache[commandId] = originVillage.coord;
2468
2469 callback(originVillage.coord);
2470 });
2471 }
2472 }
2473 callback('');
2474 }
2475
2476 function executeRename(dodgeCell, commandName) {
2477 function keepTwIcon(dodgeCell, commandName) {
2478 var oldName = $(".quickedit-label", dodgeCell).text().toUpperCase(),
2479 newName = commandName,
2480 i,
2481 unitName;
2482
2483 for (i = 0; i < user_data.mainTagger2.reservedWords.length; i++) {
2484 unitName = user_data.mainTagger2.reservedWords[i];
2485 if (oldName.indexOf(unitName.toUpperCase()) !== -1) {
2486 newName = unitName + ' ' + newName;
2487 return newName; // Only one icon possible
2488 }
2489 }
2490 return newName;
2491 }
2492
2493 var button = dodgeCell.find("input[type='button']"),
2494 newName = user_data.mainTagger2.keepReservedWords ? keepTwIcon(dodgeCell, commandName) : commandName;
2495
2496 button.prev().val(newName);
2497 button.click();
2498 }
2499
2500 $("input.taggerCheckbox", incomingTable).each(function () {
2501 var openRenameButton;
2502
2503 if ($(this).is(":checked")) {
2504 dodgeCell = $(this).parent().next();
2505
2506 openRenameButton = $("a.rename-icon", dodgeCell);
2507 if (openRenameButton.is(":visible")) {
2508 openRenameButton.click();
2509 }
2510
2511 if (commandName.indexOf("{xy}") !== -1) {
2512 getVillageCoordsFromCommandId(getCommandIdFromDodgeCell(dodgeCell), function(vilCoords) {
2513 var nameWithCoords = commandName.replace("{xy}", vilCoords);
2514 setTimeout(executeRename(dodgeCell, nameWithCoords),200);
2515 });
2516
2517 } else {
2518 setTimeout(executeRename(dodgeCell, commandName),200);
2519 }
2520 }
2521 });
2522
2523 if (dodgeCell != null) {
2524 var unitSpeed = $("#slowestUnitCell img").attr("slowestunit");
2525 if (unitSpeed != undefined) {
2526 dodgeCell = dodgeCell.parent().find("td").last().prev();
2527 pers.setCookie("sanguDodge" + getQueryStringParam("village"), unitSpeed + "~" + dodgeCell.text(), user_data.mainTagger2.minutesDisplayDodgeTimeOnMap);
2528
2529 $(".dodgers", incomingTable).css("background-color", "").attr("title", "");
2530 dodgeCell.css("background-color", user_data.colors.good).attr("title", trans.sp.tagger.activeDodgeTime);
2531 }
2532 }
2533 }
2534
2535 // std tag button
2536 var button = $("<input type=button title='" + trans.sp.tagger.renameTooltip + "' value='" + trans.sp.tagger.rename + "' onclick='select();'>");
2537 button.click(function () {
2538 trackClickEvent("MainTagger-CustomRename");
2539 var tagName = $("#commandInput").val();
2540 renameCommand(tagName);
2541 });
2542 buttonParent.append(button);
2543
2544 if (user_data.mainTagger2.otherDescs != null && user_data.mainTagger2.otherDescs != false) {
2545 $.ctrl = function(key, callback, args) {
2546 $(document).keydown(function(e) {
2547 if(!args) args=[]; // IE barks when args is null
2548 if(e.keyCode == key.charCodeAt(0) && e.ctrlKey) {
2549 e.preventDefault();
2550 e.stopPropagation();
2551 callback.apply(this, args);
2552 return false;
2553 }
2554 });
2555 };
2556 // custom buttons
2557 $.each(user_data.mainTagger2.otherDescs, function (index, val) {
2558 if (val.active) {
2559 var button = $("<input type=button title='" + trans.sp.tagger.renameButtonShortcutTooltip.replace("{hitkey}", val.hitKey)
2560 + "' data-rename-to='" + val.renameTo + "' value='" + val.name
2561 + "' class=\"mainTaggerButtons\">").click(
2562 function () {
2563 // Cannot use input:checked : this works for Firefox but there is a bug in Opera
2564 trackClickEvent("MainTagger-ConfigRename");
2565 renameCommand($(this).attr("data-rename-to"));
2566 });
2567
2568 buttonParent.append(button);
2569 }
2570 $.ctrl(val.hitKey, function(s) {
2571 trackClickEvent("MainTagger-ConfigRename");
2572 renameCommand(val.renameTo);
2573 });
2574 });
2575 }
2576
2577 // add checkboxes
2578 var lastRowIndex = rows.size(),
2579 lastSend = 0,
2580 prevSendTime = 0,
2581 firstNight = true,
2582 amountOfAttacks = 0;
2583
2584 rows.each(function (rowIndex, rowValue) {
2585 var row = $(rowValue);
2586 if (rowIndex == 0) {
2587 // headerrow
2588 var header = "<td width=1% nowrap>";
2589 header += "<img src='graphic/command/attack.png' title='" + trans.sp.tagger.checkAllAttacks + "' id=checkAll> <img src='graphic/command/cancel.png' title='" + trans.sp.tagger.uncheckAllAttacks + "' id=uncheckAll>";
2590 header += "</td>";
2591
2592 row.replaceWith("<tr>" + header + "<th width='68%'>" + trans.sp.tagger.incomingTroops + "</th><th width='30%'>" + trans.sp.tagger.arrival + "</th><th width='10%'>" + trans.sp.tagger.arrival + "</th><th width=10% nowrap>" + trans.sp.tagger.dodgeTime + "</th><th width='1%'> </th>" + "</tr>");
2593
2594 $("#checkAll").click(function () {
2595 $("input.incAt", incomingTable).prop("checked", true);
2596 });
2597
2598 $("#uncheckAll").click( function () {
2599 $("input.incAt", incomingTable).prop("checked", false);
2600 });
2601
2602 } else {
2603 // non header row types
2604 if (row.find("th").size() != 0) {
2605 // this part is only executed when attacks can be ignored
2606 // select all checkbox row (right above link rows)
2607 $("th:first", row).replaceWith("<th><input type=checkbox id=selectAllIgnore> " + $("th:first", row).text() + "</th>");
2608 $("#selectAllIgnore").click(function () {
2609 var ingoreBoxes = $("input[name^='id_']", incomingTable);
2610 var isChecked = $("#selectAllIgnore").is(":checked");
2611 ingoreBoxes.each(function() {
2612 $(this).attr("checked", isChecked);
2613 });
2614 });
2615
2616 row.prepend("<td title='" + trans.sp.tagger.totalAttacksOnVillage + "' align=center><b># " + amountOfAttacks + "</b></td>").find("td:last").attr("colspan", 4);
2617
2618 } else if (row.find("td").size() == 1) {
2619 // link-rows (bottom)
2620 if ($("#switchModus").size() == 0) {
2621 if ($("#selectAllIgnore").size() == 0) {
2622 // attack hiding disabled in tw settings -> there is not yet a totalrow
2623 row.prepend("<td title='" + trans.sp.tagger.totalAttacksOnVillage + "' align=center><b># " + amountOfAttacks + "</b></td>");
2624 } else {
2625 row.prepend("<td> </td>");
2626 }
2627
2628 row.before("<tr><td> </td><td colspan=5><a href='' id=switchModus>" + trans.sp.tagger.switchModus + "</a></td></tr>");
2629 $("#switchModus").click(function () {
2630 trackClickEvent("MainTagger-OpenClose");
2631 var editSpans = $("input.incAt", incomingTable).parent().parent().find("span.quickedit"),
2632 isInDisplayMode = function (editSpan) {
2633 return editSpan.find("span:first").is(":visible");
2634 },
2635 switchToOpen = isInDisplayMode(editSpans.first());
2636
2637 editSpans.each(function() {
2638 var editSpan = $(this),
2639 isDisplayMode = isInDisplayMode(editSpan);
2640
2641 if (switchToOpen && isDisplayMode) {
2642 // make input form visible
2643 $("a.rename-icon", editSpan).click();
2644 //setTimeout(function() {
2645 $("span.quickedit-edit input:first", editSpan).width(user_data.mainTagger2.inputBoxWidth);
2646 //}, 1);
2647
2648 } else if (!switchToOpen && !isDisplayMode) {
2649 // make label display visible
2650 editSpan.find("span:first").show();
2651 editSpan.find("span:last").remove();
2652 }
2653 });
2654
2655 return false;
2656 });
2657 } else {
2658 row.prepend("<td> </td>");
2659 }
2660 row.find("td:last").attr("colspan", 5);
2661 } else {
2662 // normal incoming rows
2663 var checkboxCell = "<td><input type=checkbox rowIndex=" + rowIndex + " class='taggerCheckbox ";
2664 var incomingType = $("img[src*='graphic/command/support.png']", this).size() == 1 ? 'incSupport' : "incAt";
2665 checkboxCell += incomingType + "'";
2666 if (rowIndex == 1) {
2667 checkboxCell += " id=checkFirst";
2668 }
2669
2670 var currentArrivalTime = getDateFromTodayTomorrowTW($("td:eq(1)", this).text());
2671 if (incomingType == 'incAt' && isDateInNightBonus(currentArrivalTime)) {
2672 // nightbonus
2673 row.find("td:eq(1)").css("background-color", user_data.colors.error);
2674 }
2675
2676 // extra column with dodge time
2677 if (incomingType == 'incAt') {
2678 var dodgeTime = getTimeFromTW($("td:eq(2)", this).text());
2679 row.find("td:last").before("<td class=dodgers>" + twDurationFormat(dodgeTime.totalSecs / 2 / 60) + "</td>");
2680 amountOfAttacks++;
2681 } else {
2682 row.append("<td> </td>");
2683 }
2684
2685 // dotted line after x hours no incomings
2686 if (prevSendTime == 0 || (currentArrivalTime - prevSendTime) / 1000 / 60 > user_data.mainTagger2.minutesWithoutAttacksDottedLine) {
2687 if (prevSendTime != 0) {
2688 row.find("td").css("border-top", "1px dotted black");
2689 }
2690
2691 prevSendTime = currentArrivalTime;
2692 }
2693
2694 // black line after each nightbonus
2695 if (lastSend == 0 || currentArrivalTime > lastSend) {
2696 if (lastSend != 0) {
2697 row.find("td").css("border-top", "1px solid black");
2698 firstNight = false;
2699 }
2700
2701 lastSend = new Date(currentArrivalTime);
2702 if (lastSend.getHours() >= world_config.nightbonus.till) {
2703 lastSend.setDate(lastSend.getDate() + 1);
2704 lastSend.setHours(world_config.nightbonus.from);
2705 lastSend.setMinutes(0);
2706 lastSend.setSeconds(0);
2707 } else if (lastSend.getHours() < world_config.nightbonus.from) {
2708 lastSend.setHours(world_config.nightbonus.from);
2709 lastSend.setMinutes(0);
2710 lastSend.setSeconds(0);
2711 } else {
2712 lastSend.setHours(world_config.nightbonus.till);
2713 lastSend.setMinutes(0);
2714 lastSend.setSeconds(0);
2715 }
2716 }
2717
2718 // Automatically select?
2719 if (incomingType == "incAt") {
2720 if (firstNight) {
2721 var isDefaultDesc = false;
2722 if (!isDefaultDesc) {
2723 checkboxCell += " checked=true";
2724 }
2725 }
2726
2727 $("span:eq(2)", row).find("input:first").click(function () {
2728 $(this).select();
2729 });
2730
2731 // extra buttons
2732 $("td:eq(0)", row).append("<img src='graphic/oben.png' title='" + trans.sp.tagger.allAbove + "' rowIndex=" + rowIndex + " direction='up'> <img src='graphic/unten.png' title='" + trans.sp.tagger.allBelow + "' rowIndex=" + rowIndex + " direction='down'>");
2733 }
2734
2735 row.prepend(checkboxCell + "></td>");
2736
2737 if (user_data.mainTagger2.colorSupport != null && incomingType != "incAt") {
2738 row.find("td").css("background-color", user_data.mainTagger2.colorSupport);
2739 }
2740 }
2741 }
2742 });
2743 });
2744 }
2745 }
2746
2747 // show tagger?
2748 if (user_data.mainTagger2.autoOpen) {
2749 $("#openTaggerButton").click();
2750 }
2751
2752 // Show attack rename inputboxes
2753 if (user_data.mainTagger2.autoOpenCommands) {
2754 $("#switchModus").click();
2755 }
2756
2757 // BUG: This breaks the TW remembering of the div positions!!
2758 var newLayout = "<tbody><tr><td colspan=2><div class='outerBorder' id=myprettynewcell>";
2759 newLayout += "</div></td></tr></tbody>";
2760 mainTable.append(newLayout);
2761
2762 var prettyCell = $("#myprettynewcell");
2763 prettyCell.append($("#show_incoming_units"));
2764 prettyCell.append($("#show_outgoing_units"));
2765 }
2766 if (user_data.overview.canHideDiv) {
2767 //console.time("main_overview_deletebuttons");
2768
2769 /**
2770 * Array with domIds of the hideable divs
2771 * @type {Array}
2772 */
2773 var currentlyHidden = pers.get("mainvillage_hiddendivs");
2774 currentlyHidden = currentlyHidden ? JSON.parse(currentlyHidden) : [];
2775
2776 // add the X images
2777 $("#leftcolumn,#rightcolumn").find("div.moveable").each(function() {
2778 var self = $(this),
2779 domId = this.id;
2780
2781 if (!self.hasClass("hidden_widget")) {
2782 if (currentlyHidden.indexOf(domId) !== -1) {
2783 self.hide();
2784 } else {
2785 var header = self.find("h4:first");
2786 header.prepend(
2787 '<span class="sanguHide" '
2788 + " title='" + trans.sp.main.hideDiv + "'"
2789 + ' data-divid="' + domId + '"></span>');
2790 }
2791 }
2792 });
2793
2794 // X image event
2795 $(".sanguHide", content_value).click(function() {
2796 var toHideId = $(this).attr("data-divid");
2797 currentlyHidden.push(toHideId);
2798 $("#" + toHideId).hide();
2799 q(currentlyHidden);
2800
2801 pers.set("mainvillage_hiddendivs", JSON.stringify(currentlyHidden));
2802 });
2803
2804 // css for X image
2805 var deleteImage = "data:image/png;base64,"
2806 + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAAXNSR0IArs4c6QAAAARnQU1BAACx"
2807 + "jwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41"
2808 + "LjExR/NCNwAAAT5JREFUOE9jmBqv1R8uD0F9oTI9wZJdAaLI7A5fwTYv3g4fgU4/4VZ3Lgag6OYV"
2809 + "fUd3zj13aAkeBFQAVFZrx8DQGyIN5Nw6t+7p9W14EFABUFm9AwMD0GqgAUChDw/340FABUBljY5M"
2810 + "DN0BYsRrADkJ6Bs0DZe2NL68sfHN3R1XtrfCBSEaKm0YGIAeR9awoj22M1p5z+SIHX0hczI0t/fF"
2811 + "oGtodGJG1vD8+ubqYPXOEMnJMTI9EYqPz69E1oDFDw/PreyPUkw1YiiwYV9Z5fDq1lZkDVj8sKgh"
2812 + "NFiTIcdHPd5RIc2Se/eUZGQNWPwARH1VMU+vbb51akV7UQhcEKEBzQ+4EERDqRUDA9BZxGsotGBg"
2813 + "AMY28UkDpKHJmYX4xAfSAPQH0GXlNlAGEBVbMQAlkNn55gz5QNKCIdOUAQAxTOqhn6cegQAAAABJ"
2814 + "RU5ErkJggg==";
2815
2816 var css = document.createElement("style");
2817 css.type = "text/css";
2818 css.innerHTML = ".sanguHide { margin-left: 2px; float: right; cursor: pointer; "
2819 + "background: url(" + deleteImage + "); width: 16px; height: 16px; }";
2820 document.body.appendChild(css);
2821
2822 // show everything link
2823 content_value.append(
2824 "<br><a href='#' id='resetSanguMenu'>"
2825 + trans.sp.main.showHiddenDivs.replace("{amount}", currentlyHidden.length)
2826 + "</a>"
2827 );
2828
2829 $("#resetSanguMenu").click(function() {
2830 pers.set("mainvillage_hiddendivs", "");
2831 location.reload();
2832 });
2833
2834
2835
2836 //console.timeEnd("main_overview_deletebuttons");
2837 }
2838 }());
2839 break;
2840
2841 case "map":
2842 (function() {
2843 //console.time("dodge_fromMainTagger");
2844 try {
2845 var isDodge = pers.getCookie("sanguDodge" + getQueryStringParam("village"));
2846 if (isDodge) {
2847 // Display dodge time and slowest unit in the village (cookied from the mainTagger)
2848 isDodge = isDodge.split("~");
2849 var header = $("h2:first", content_value);
2850 $("tbody:first", content_value)
2851 .prepend(
2852 "<tr><td><table width=100% cellpadding=0 cellspacing=0><tr><td width=99% style='font-size: 18pt'><b>" + header.html()
2853 + "</b></td><td nowrap width=250><div title='" + trans.sp.map.dodgeLastTagged + "' style='border: 1px solid black; padding: 2px; background-color: "
2854 + (isDodge[0] == 'unit_snob' ? user_data.colors.special : user_data.colors.good) + "'><img src=graphic/unit/" + isDodge[0] + ".png> <b>" + isDodge[1]
2855 + "</b></div></td></tr></table></td></tr>");
2856 header.remove();
2857 }
2858 } catch (e) { handleException(e, "dodge_fromMainTagger-"); }
2859 //console.timeEnd("dodge_fromMainTagger");
2860 }());
2861 break;
2862
2863 case "report":
2864 if (current_page.mode === 'publish') {
2865 // Nice to haves when publishing a report
2866 (function() {
2867 try {
2868 if (location.href.indexOf('published=1') == -1 && user_data.other.reportPublish != null) {
2869 $.each(user_data.other.reportPublish, function (i, v) { $("#" + v).prop("checked", true); });
2870 } else {
2871 $("h3~p:nth-child(4)").each(function () {
2872 var input = $("h3~p a")[0].href;
2873 if (input.indexOf("?t=") != -1) {
2874 input = input.substr(0, input.indexOf("?"));
2875 }
2876 $(this).append('<br><input type="text" size="75" onclick="this.select(); this.focus()" value="[url]' + input + '[/url]" />');
2877 input = input.substr(input.lastIndexOf('/') + 1);
2878 $(this).append('<br><input type="text" size="75" onclick="this.select(); this.focus()" value="[report_display]' + input + '[/report_display]" />');
2879 $(this).append('<br><input type="text" size="75" onclick="this.select(); this.focus()" value="[report]' + input + '[/report]" />');
2880 });
2881 }
2882 } catch (e) { handleException(e, "report"); }
2883 }());
2884 }
2885 break;
2886
2887 case "main":
2888 // Alternating row colors
2889 $("#buildings,#build_queue").find("tr:odd").addClass("row_b");
2890 (function() {
2891 //console.time("main-renamevillage");
2892 try {
2893 if (user_data.main.villageNames != null && user_data.main.villageNames.length > 0) {
2894 var showButtons = true;
2895 $.each(user_data.main.villageNames, function (i, v) { if (game_data.village.name == v) showButtons = false; });
2896
2897 if (showButtons) {
2898 var submitButton = $("input[type='submit']:last");
2899 $.each(user_data.main.villageNames, function (i, v) {
2900 // rename village to one of the provided villageNames options
2901 var button = $("<input type=button class='btn' value='" + v + "'>")
2902 .click(function () {
2903 trackClickEvent("RenameVillage");
2904 $("input[name='name']").val(v);
2905 if (user_data.main.villageNameClick) {
2906 $("input[type='submit']").click();
2907 }
2908 });
2909 var input = submitButton.parent().append(button);
2910 });
2911 }
2912 }
2913 } catch (e) { handleException(e, "place-"); }
2914 //console.timeEnd("main-renamevillage");
2915 }());
2916 // show loyalty when building
2917 // destroy button is disabled now (but for how long?)
2918 if (server_settings.ajaxAllowed && user_data.main.ajaxLoyalty) {
2919 ajax("overview", function (overview) {
2920 var loyalty = $("#show_mood div.vis_item", overview);
2921 if (loyalty.size() == 1) {
2922 $(".modemenu tr:first").append("<td><b>" + trans.tw.main.loyaltyHeader + "</b> " + loyalty.html() + "</td>");
2923 }
2924 });
2925 }
2926 break;
2927
2928 case "snob":
2929 if (current_page.mode === "train" || current_page.mode === null || current_page.mode === "produce") {
2930 if (user_data.other.calculateSnob && !world_config.coins) {
2931 // Calculate for how many nobles/snobs we've got packages
2932 (function() {
2933 try {
2934 //var table = $("table.vis:eq(1)", content_value);
2935 var table = $("table.vis[width='100%']", content_value).first();
2936 var cost = $("td:eq(1)", table).html();
2937 cost = parseInt(cost.substr(0, cost.indexOf(" ")), 10);
2938 var stored = $("tr:eq(1) td:eq(1)", table).html();
2939 stored = parseInt(stored.substr(0, stored.indexOf(" ")), 10);
2940 var canProduce = 0;
2941 while (stored > cost) {
2942 stored -= cost;
2943 cost++;
2944 canProduce++;
2945 }
2946
2947 var sumtable = $("table.main #content_value > table table.vis:last");
2948 assert(sumtable.length, "no snob sumtable");
2949 sumtable.append("<tr><th>" + trans.sp.snob.canProduce
2950 + "</th><td style='border: 1px solid black'><img src='/graphic/unit/unit_snob.png'><b>"
2951 + canProduce + "</b> " +
2952 "+ <img src='graphic/res.png'>"
2953 + stored + "</td></tr>");
2954
2955 } catch (e) { handleException(e, "snob"); }
2956 }());
2957 }
2958 }
2959 break;
2960
2961 case "info_command":
2962 if ($("#running_times").size() > 0) {
2963 // ---------------------------------------INCOMING ATTACK
2964 (function() {
2965 //console.time("info_command-incoming");
2966 try {
2967 var link = $("#contentContainer tr:eq(10) a:last");
2968 link.one('click', function () {
2969 var infoTable = $("#contentContainer");
2970 var table = $("#running_times");
2971
2972 // convert runningtime to seconds
2973 // TODO: there is a function for this: getTimeFromTW
2974 function convertTime(cell) {
2975 var time = $(cell).find("td:eq(1)").text();
2976 time = time.match(/(\d+):(\d+):(\d+)/);
2977
2978 var obj = {};
2979 obj.hours = parseInt(time[1], 10);
2980 obj.minutes = parseInt(time[2], 10);
2981 obj.seconds = parseInt(time[3], 10);
2982 obj.totalSeconds = obj.hours * 3600 + obj.minutes * 60 + obj.seconds;
2983
2984 return obj;
2985 }
2986
2987 // Sort on runningtime
2988 var unitRows = $("tr:gt(1)", table);
2989 unitRows.sortElements(function (a, b) {
2990 return convertTime(a).totalSeconds > convertTime(b).totalSeconds ? 1 : -1;
2991 });
2992
2993 // header sent times
2994 $("th:first", table).attr("colspan", 5);
2995 $("th:eq(2)", table).after("<th>" + trans.sp.tagger.sentOn + "</th><th>" + trans.sp.tagger.ago + "</th>");
2996
2997 var infoCell = $("td", infoTable);
2998 var attacker = infoCell.eq(5).text();
2999 var attackerVillageName = infoCell.eq(7).text();
3000 var attackerVillage = getVillageFromCoords(attackerVillageName);
3001 var defender = infoCell.eq(10).text();
3002 var defenderVillage = getVillageFromCoords(infoCell.eq(12).text());
3003 var arrivalTime = getDateFromTW(infoCell.eq(14).text());
3004 var fields = parseInt(getDistance(attackerVillage.x, defenderVillage.x, attackerVillage.y, defenderVillage.y).fields, 10);
3005
3006 var isNightbonus = isDateInNightBonus(arrivalTime);
3007 if (isNightbonus) {
3008 infoCell.eq(14).css("background-color", user_data.colors.error);
3009 }
3010
3011 var remainingRunningTime = convertTime($("tr:eq(9)", infoTable)),
3012 plausibleSpeedFound = false;
3013
3014 unitRows.each(function () {
3015 var unit = $("img:first", this).attr("src");
3016 unit = unit.substr(unit.lastIndexOf("unit_") + 5);
3017 unit = unit.substr(0, unit.indexOf("."));
3018
3019 if (unit == "spear") {
3020 $(this).hide();
3021 } else {
3022 var runningTime = convertTime(this),
3023 newDate = new Date(arrivalTime.getTime() - runningTime.totalSeconds * 1000),
3024 sendAt = prettyDate((new Date()).getTime() - newDate.getTime()),
3025 troopsRow = this,
3026 str;
3027
3028 // Extra column with time sent
3029 $("td:eq(2)", troopsRow).before("<td>" + twDateFormat(newDate, true) + "</td><td>" + sendAt + "</td>");
3030
3031 // Rename default command name for each speed
3032 if (user_data.incoming.renameInputTexbox) {
3033 str = user_data.incoming.renameInputTexbox;
3034
3035 var attackId = $("span.quickedit", this).attr("data-id");
3036 str = str.replace("{village}", attackerVillageName).replace("{c}", attackerVillage.continent()).replace("{id}", attackId);
3037 str = str.replace("{player}", attacker).replace("{xy}", attackerVillage.coord).replace("{unit}", trans.tw.units.twShortNames[unit]);
3038 str = str.replace("{fields}", fields);
3039 if (str.indexOf("{night}") != -1) {
3040 if (isNightbonus) {
3041 str = str.replace("{night}", trans.sp.tagger.arrivesInNightBonus);
3042 } else {
3043 str = str.replace("{night}", "");
3044 }
3045 }
3046
3047 if (false) {
3048 // don't show rename inputs, just the labels
3049 $("span.quickedit-label", troopsRow).text(str).show();
3050 } else {
3051 // show the rename inputboxes on form load
3052 $("span.quickedit-label", troopsRow).text(str);
3053 setTimeout(function() {
3054 $("a.rename-icon", troopsRow).click();
3055 $("#focusPlaceHolder").focus();
3056 }, 1);
3057 }
3058
3059 if (runningTime.totalSeconds > remainingRunningTime.totalSeconds && !plausibleSpeedFound) {
3060 plausibleSpeedFound = true;
3061
3062 $("table:first", content_value).prepend(
3063 "<input type=submit class='btn' id=focusPlaceHolder value='"
3064 + trans.sp.tagger.tagIt
3065 + " (" + trans.tw.units.twShortNames[unit] + ")'"
3066 + " data-command-name='" + str + "'"
3067 + ">");
3068
3069 $("#focusPlaceHolder").click(function () {
3070 trackClickEvent("TagDefault");
3071 $("#command_comment").text($(this).attr("data-command-name"));
3072 $("#command_comment+a").click();
3073 setTimeout(function() {
3074 $("#quickedit-rename input:last").click();
3075 }, 1);
3076 $(this).val(trans.sp.tagger.tagged).attr("disabled", "disabled");
3077 });
3078
3079 if (unit == "snob") {
3080 $("tr:last td", table).css("background-color", user_data.colors.error);
3081 }
3082 }
3083 }
3084
3085 // Possible send times (now) in bold
3086 if (runningTime.totalSeconds > remainingRunningTime.totalSeconds) {
3087 $(this).css("font-weight", "bold");
3088 }
3089 }
3090 });
3091
3092 // nobles can only walk so far
3093 var nobles = $("tr:last", table);
3094 if (convertTime(nobles).totalSeconds / 60 > world_config.maxNobleWalkingTime) {
3095 nobles.find("td").css("text-decoration", "line-through");
3096 }
3097
3098 if (user_data.incoming.invertSort) {
3099 unitRows.sortElements(function (a, b) {
3100 return convertTime(a).totalSeconds < convertTime(b).totalSeconds ? 1 : -1;
3101 });
3102 }
3103 });
3104
3105 // AUTO OPEN TAGGER
3106 if (user_data.incoming.forceOpenTagger || (user_data.incoming.autoOpenTagger && $("#labelText").text() == trans.tw.incoming.defaultCommandName)) {
3107 link.click();
3108 }
3109
3110 if (user_data.proStyle && user_data.incoming.villageBoxSize != null && user_data.incoming.villageBoxSize != false) {
3111 $("table:first", content_value).css("width", user_data.incoming.villageBoxSize);
3112 }
3113
3114 } catch (e) { handleException(e, "info_command-incoming"); }
3115 //console.timeEnd("info_command-incoming");
3116 }());
3117
3118 } else {
3119 (function() {
3120 //console.time("info_command-command");
3121 try {
3122 // Own attack/support/return ---------------------------------------------------------------------------------- Own attack/support/return
3123 var infoTable = $("table.vis:first", content_value);
3124 var type = $("h2:first", content_value).text();
3125 var catapultTargetActive = infoTable.find("tr:eq(5) td:eq(0)").text() == trans.tw.command.catapultTarget;
3126
3127 infoTable.width(600);
3128
3129 // Add troop returntime and annulation return time
3130 var isSupport = type.indexOf(trans.tw.command.support) == 0;
3131 var offset = 5;
3132 if (catapultTargetActive) {
3133 offset += 1;
3134 }
3135 var arrivalCell = infoTable.find("tr:eq(" + (offset + 1) + ") td:last");
3136
3137 if (type.indexOf(trans.tw.command.returnText) == -1
3138 && type.indexOf(trans.tw.command.abortedOperation) == -1) {
3139
3140 var duration = getTimeFromTW(infoTable.find("tr:eq(" + offset + ") td:last").text());
3141 var imgType = !isSupport ? "attack" : "support";
3142 arrivalCell.prepend("<img src='graphic/command/" + imgType + ".png' title='" + trans.sp.command.arrival + "'> " + trans.tw.all.dateOn + " ").css("font-weight", "bold");
3143 var stillToRun = getTimeFromTW(infoTable.find("tr:eq(" + (offset + 2) + ") td:last").text());
3144
3145 var cancelCell = infoTable.find("tr:last").prev();
3146 var canStillCancel = cancelCell.has("a").length;
3147 if (canStillCancel) {
3148 cancelCell.find("td:first").attr("colspan", "1").attr("nowrap", "nowrap");
3149 var returnTime = getDateFromTW($("#serverTime").text(), true);
3150 returnTime = new Date(returnTime.valueOf() + (duration.totalSecs - stillToRun.totalSecs) * 1000);
3151 cancelCell.append("<td>" + trans.sp.command.returnOn + "</td><td id=returnTimer>" + twDateFormat(returnTime, true, true).substr(3) + "</td>");
3152
3153 setInterval(function timeCounter() {
3154 var timer = $("#returnTimer");
3155 var newTime = new Date(getDateFromTW(timer.text()).valueOf() + 2000);
3156 timer.text(twDateFormat(newTime, true, true).substr(3));
3157 }, 1000);
3158
3159 cancelCell = cancelCell.prev();
3160 }
3161
3162 if (type.indexOf(trans.tw.command.attack) == 0) {
3163 var returnTimeCell = cancelCell.find("td:last");
3164 returnTimeCell.html("<img src='graphic/command/return.png' title='" + cancelCell.find("td:first").text() + "'> <b>" + returnTimeCell.text() + "</b>");
3165 }
3166 } else {
3167 var imgType = type.indexOf(trans.tw.command.abortedOperation) == 0 ? imgType = "cancel" : "return";
3168 arrivalCell.prepend("<img src='graphic/command/" + imgType + ".png' title='" + trans.sp.command.arrival + "'> " + trans.tw.all.dateOn + " ").css("font-weight", "bold");
3169 }
3170
3171 var player = infoTable.find("td:eq(7) a").text();
3172 var village = getVillageFromCoords(infoTable.find("td:eq(9) a").text());
3173 var second = infoTable.find("td:eq(" + (13 + (catapultTargetActive ? 2 : 0)) + ")").text();
3174 var haulDescription = "";
3175
3176 if (type.indexOf(trans.tw.command.returnText) == 0) {
3177 infoTable = $("> table.vis:last", content_value);
3178 if (infoTable.find("td:first").text() == trans.tw.command.haul) {
3179 haulDescription = infoTable.find("td:last").text().match(/\s(\d+)\/(\d+)$/);
3180 if (haulDescription) {
3181 haulDescription = formatNumber(haulDescription[1]) + " / " + formatNumber(haulDescription[2]);
3182 } else {
3183 assert(infoTable.find("td:last").text() + " didn't match regexp for tw.command.haul");
3184 }
3185 infoTable = infoTable.prev();
3186 }
3187 infoTable = infoTable.find("tr:last");
3188 } else {
3189 infoTable = $("> table.vis:last", content_value);
3190 }
3191
3192 var unitsSent = {};
3193 $.each(world_data.units, function (i, val) {
3194 unitsSent[val] = parseInt($("td:eq(" + i + ")", infoTable).text(), 10);
3195 });
3196 var unitsCalc = calcTroops(unitsSent);
3197 unitsCalc.colorIfNotRightAttackType($("h2:first", content_value), !isSupport);
3198
3199 if (user_data.attackAutoRename.active) {
3200 $.each($('.quickedit'), function(){
3201 var renamed = buildAttackString(village.coord, unitsSent, player, isSupport, 0, haulDescription),
3202 commandID = $(this).attr('data-id'),
3203 $this = $(this);
3204
3205 if (server_settings.ajaxAllowed) {
3206 $.ajax({
3207 url: game_data.link_base_pure+'info_command&ajaxaction=edit_other_comment&id='+commandID+'&h='+game_data.csrf+'&',
3208 method: 'post',
3209 data: { text: renamed },
3210 success:function() {
3211 $this.find(".quickedit-label:first").text(renamed);
3212 }
3213 });
3214 }
3215 });
3216 }
3217
3218 /*if (server_settings.ajaxAllowed) {
3219 ajax("overview", function(overviewtext) {
3220 var idnumberlist = [];
3221 var index = 0;
3222 var links = $(overviewtext).find("#show_outgoing_units").find("table").find("td:first-child").find("a:first-child").find("span");
3223 //^enkel 'find codes, dus alles wegselecteren wat onnodig is.
3224
3225 links.each(function(){
3226 var idgetal = $(this).attr('id').match(/\d+/);
3227 idnumberlist[index]=idgetal[0];
3228 index++;
3229 $.trim(idnumberlist[index]);
3230 });
3231
3232 idthisattack= location.href.match(/id=(\d+)/);// deze aanval ophalen
3233 var idthisattacktrim = $.trim(idthisattack[1]); //eerste callback: Datgeen tussen haakjes dus. En gelijk maar trimmen, voor het geval dat.
3234 var counter=$.inArray(idthisattacktrim, idnumberlist);
3235 var arraylength = idnumberlist.length;
3236 var arraylengthminusone = arraylength -1;
3237 if (counter != arraylengthminusone) {
3238 var nextcommandID = idnumberlist[(counter +1)];}
3239 if (counter != 0) {
3240 var lastcommandID = idnumberlist[(counter - 1)];
3241 }
3242 villageid = location.href.match(/village=(\d+)/);
3243 //alert(villageid[1]);
3244 if (counter != 0) {
3245 content_value.find("h2").after('<table><tr><td id="lastattack" style="width:83%"><a href="/game.php?village=' + villageid + '&id=' + lastcommandID + '&type=own&screen=info_command">'+ trans.sp.command.precedingAttack + '</a></td> </tr> </table>');
3246 }
3247 else {
3248 content_value.find("h2").after('<table><tr><td id="lastattack" style="width:83%"><b> XX</b></td> </tr> </table>');
3249 }
3250 if (counter != arraylengthminusone){
3251 $("#lastattack").after('<td id="nextcommand" ><a href="/game.php?village=' + villageid + '&id=' + nextcommandID + '&type=own&screen=info_command">'+ trans.sp.command.nextAttack+ '</a></td>');
3252 }
3253 else {
3254 $("#lastattack").after('<td id="nextcommand"><b>XX</b></td>');
3255 }
3256
3257 //alert("Hoi");
3258 }, {});
3259 }*/
3260
3261 // When sending os, calculate how much population in total is sent
3262 if (isSupport) {
3263 var totalPop = 0;
3264 $.each(world_data.units, function (i, val) {
3265 var amount = unitsSent[val];
3266 if (amount != 0) {
3267 totalPop += amount * world_data.unitsPositionSize[i];
3268 }
3269 });
3270
3271 var unitTable = $("table.vis:last", content_value);
3272 unitTable.find("tr:first").append('<th width="50"><span class="icon header population" title="' + trans.sp.all.population + '"></span></th>');
3273 unitTable.find("tr:last").append('<td>' + formatNumber(totalPop) + '</td>');
3274 }
3275 } catch (e) { handleException(e, "info_command-command"); }
3276 //console.timeEnd("info_command-command");
3277 }());
3278 }
3279 break;
3280
3281 case "market":
3282 (function() {
3283 try {
3284 if (location.href.indexOf('try=confirm_send') > -1) {
3285 if (user_data.proStyle && user_data.market.autoFocus) {
3286 $("input[type='submit']").focus();
3287 }
3288 }
3289 else if (location.href.indexOf('&mode=') == -1 || location.href.indexOf('&mode=send') > -1) {
3290 if (location.href.indexOf('try=confirm_send') == -1) {
3291 // Spice up market:
3292 // 120 x 106 pixels: There are market images that are smaller
3293 // Making all images equally large results in the OK button remaining on the same place
3294 if (user_data.proStyle && user_data.market.resizeImage) {
3295 $("img[src*='big_buildings/market']").width(120).height(106);
3296 }
3297
3298 // New last village:
3299 $("input[type='submit']").click(function () {
3300 var village = getVillageFromCoords($("#inputx").val() + "|" + $("#inputy").val());
3301 if (village.isValid) {
3302 pers.set("lastVil", village.coord);
3303 }
3304 });
3305
3306 // Add last & target
3307 var vilHome = getVillageFromCoords(game_data.village.coord);
3308
3309 var targetLocation = $("#inputx").parent().parent().parent();
3310 var cookie = pers.get("lastVil");
3311 var coord = getVillageFromCoords(cookie);
3312 var htmlStr = '';
3313 if (coord.isValid) {
3314 var dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, 'merchant');
3315 htmlStr = printCoord(coord, "» " + trans.sp.all.last + ": " + coord.x + "|" + coord.y);
3316 htmlStr += " <span id=lastVilTime>" + dist.html + "</span>";
3317 }
3318
3319 // Add target village
3320 var target = getVillageFromCoords(spTargetVillageCookie());
3321 if (target.isValid) {
3322 var dist = getDistance(target.x, vilHome.x, target.y, vilHome.y, 'merchant');
3323 if (htmlStr.length > 0) {
3324 htmlStr += "<br>";
3325 }
3326 htmlStr += printCoord(target, "» " + trans.sp.all.target + ": " + target.x + "|" + target.y) + " <span id=targetVilTime>" + dist.html + "</span>";
3327 }
3328
3329 if (htmlStr.length > 0) {
3330 targetLocation.append("<tr><td colspan=2>" + htmlStr + "</td></tr>");
3331 }
3332
3333 // Calculate total resources sent
3334 var table = $("table.vis:last");
3335 if (table.prev().text() == trans.tw.market.incomingTransports) {
3336 var sent = { stone: 0, wood: 0, iron: 0 };
3337 table.find("tr:gt(0)").each(function () {
3338 var cell = $(this).find("td:eq(1)");
3339 var resources = $.trim(cell.text().replace(/\./g, "").replace(/\s+/g, " ")).split(" ");
3340
3341 for (var i = 0; i < resources.length; i++) {
3342 if (resources[i]) {
3343 var restype = cell.find("span.icon:eq(" + i + ")");
3344 for (var resIndex = 0; resIndex < world_data.resources_en.length; resIndex++) {
3345 if (restype.hasClass(world_data.resources_en[resIndex])) {
3346 sent[world_data.resources_en[resIndex]] += parseInt(resources[i], 10);
3347 }
3348 }
3349 }
3350 }
3351 });
3352
3353 table.append("<tr><th>" + trans.sp.all.total + ":</th><td colspan=3><img src=graphic/holz.png> " + formatNumber(sent.wood) + " <img src=graphic/lehm.png> " + formatNumber(sent.stone) + " <img src=graphic/eisen.png> " + formatNumber(sent.iron) + "</td></tr>");
3354 }
3355 }
3356 }
3357 } catch (e) { handleException(e, "market"); }
3358 }());
3359 break;
3360
3361 case "settings":
3362 // Add sangu to the menu
3363 (function() {
3364 var settingsMenu = $("table.vis:first", content_value);
3365 settingsMenu.append(
3366 "<tr><td> </td></tr><tr><th><a href='"
3367 + getUrlString("screen=settings&mode=sangu")
3368 + "'>Sangu Package</a></th></tr>");
3369
3370 settingsMenu.append(
3371 "<tr id='sanguImportRow'><td>"
3372 + "<a href='#' id='sanguImport'>" + trans.sp.sp.settings.importSettings + "</a>"
3373 + "</td></tr>"
3374 + "<tr id='sanguExportRow'><td>"
3375 + "<a href='#' id='sanguExport'>" + trans.sp.sp.settings.exportSettings + "</a>"
3376 + "</td></tr>");
3377
3378 settingsMenu.after(
3379 "<br>"
3380 + "<a target='_blank' href='http://"+server_settings.sangu+"'>"
3381 + "<div style='width: 100%; text-align: center; border: 1px solid black; background-color: yellow; padding: 10px 0 10px;'>"
3382 + "Sangu Website"
3383 + "</div>"
3384 + "</a>");
3385
3386 /**
3387 * Creates the textarea (and other UI elements) for displaying the user_data
3388 * @param activate {string} either Import or Export
3389 * @param deactivate {string} either Export or Import
3390 * @param textAreaValue {string} the content to assign to the textarea
3391 */
3392 function importExportHandler(activate, deactivate, textAreaValue) {
3393 var settingsContainer = $("#sanguSettingsTextArea");
3394 $("#sangu"+activate+"Row").addClass("row_b");
3395 $("#sangu"+deactivate+"Row").hide();
3396
3397 $("#sanguSettingsForm").hide();
3398 if (settingsContainer.length === 0) {
3399 //sanguConfigTitle is the h3 defined in inject.js
3400 $("#sanguConfigTitle").parent().append(
3401 trans.sp.sp.settings.importSettingsDesc + "<br><br>"
3402 + "<textarea id='sanguSettingsTextArea' style='width: 100%; height: 500px'>"
3403 + textAreaValue
3404 + "</textarea>");
3405 } else {
3406 if (textAreaValue.length > 0) {
3407 settingsContainer.val(textAreaValue);
3408 }
3409 }
3410 }
3411
3412 $("#sanguExport").click(function() {
3413 importExportHandler("Export", "Import", JSON.stringify(user_data, null, 4));
3414 $("#sanguSettingsTextArea").select();
3415 return false;
3416 });
3417
3418 $("#sanguImport").click(function() {
3419 var importSanguSettings = $("#importSanguSettings");
3420 importExportHandler("Import", "Export", "");
3421
3422 if (importSanguSettings.length === 0) {
3423 $("#sanguSettingsTextArea")
3424 .after("<br><input type='button' id='importSanguSettings' value='" + trans.sp.sp.settings.importSettings + "'>");
3425
3426 $("#importSanguSettings").click(function() {
3427 var overwriteCurrentSettings = true,
3428 newUserData;
3429
3430 try {
3431 newUserData = JSON.parse($("#sanguSettingsTextArea").val());
3432
3433 if (typeof newUserData.proStyle === 'undefined') {
3434 overwriteCurrentSettings = confirm(trans.sp.sp.settings.importError + trans.sp.sp.settings.importErrorContinueAnyway);
3435 }
3436
3437 if (overwriteCurrentSettings) {
3438 user_data = $.extend({}, user_data, newUserData);
3439 pers.set("sangusettings", JSON.stringify(user_data));
3440 alert(trans.sp.sp.settings.importSettingsSuccess);
3441 }
3442
3443 } catch (ex) {
3444 alert(trans.sp.sp.settings.importError + "\n" + ex.message);
3445 }
3446 });
3447 }
3448 $("#sanguSettingsTextArea").focus();
3449
3450 return false;
3451 });
3452 })();
3453
3454 switch (current_page.mode) {
3455 case "vacation":
3456 var maxSitDays = server_settings.maxSitDays;
3457 var daysTable = $("table.vis:eq(1)", content_value);
3458 var days = $("td:last", daysTable).text();
3459 days = maxSitDays - parseInt(days.substr(0, days.indexOf(" ")), 10);
3460 if (days > 0) {
3461 var tillTime = new Date();
3462 tillTime.setDate(tillTime.getDate() + days);
3463 daysTable.append("<tr><td>" + trans.sp.rest.sittingAttackTill + "</td><td>" + (tillTime.getDate() + "." + pad(tillTime.getMonth() + 1, 2) + "." + tillTime.getFullYear()) + "</td></tr>");
3464 } else {
3465 daysTable.find("td:last").css("background-color", user_data.colors.error);
3466 }
3467 break;
3468
3469 case "quickbar_edit":
3470 if (user_data.scriptbar.editBoxCols != null && user_data.scriptbar.editBoxCols != false) {
3471 // TODO: textareaIfy: This might be useful on other places aswell. Move to func/UI?
3472 function textareaIfy(element) {
3473 var textarea =
3474 $('<textarea>')
3475 .attr('cols', Math.round(user_data.scriptbar.editBoxCols / 9))
3476 .attr('rows', user_data.scriptbar.editBoxRows)
3477 .val($(element).val());
3478
3479 textarea.change(function () {
3480 element.val($(this).val());
3481 });
3482
3483 element.before(textarea);
3484 $(element).hide();
3485 }
3486
3487 var url = $("form :input[type='text']").css("width", user_data.scriptbar.editBoxCols).last();
3488 textareaIfy(url);
3489 }
3490 break;
3491 }
3492
3493 // SANGU SETTING EDITOR
3494 if (location.href.indexOf('mode=sangu') > -1) {
3495
3496
3497 // settings.editor: : delimited: "array:string" or "required:boolean" etc
3498
3499 function createArraySettingType(inputHandler, index, editor) {
3500 var propertyValueType = editor.split("|")[0];
3501
3502 function deleter() {
3503 inputHandler.getValue().splice(index, 1);
3504 }
3505
3506 switch (propertyValueType) {
3507 case "number":
3508 return new FormInputHandler(inputHandler.formConfig, {
3509 getter: function() {
3510 return inputHandler.getValue()[index];
3511 },
3512 setter: function(value) {
3513 value = parseInt(value, 10);
3514 if (!isNaN(value)) {
3515 inputHandler.getValue()[index] = value;
3516 } else {
3517 inputHandler.getValue()[index] = 0;
3518 }
3519 },
3520 deleter: deleter,
3521 editor: editor
3522 });
3523
3524 case "text":
3525 case "color":
3526 return new FormInputHandler(inputHandler.formConfig, {
3527 getter: function() {
3528 return inputHandler.getValue()[index];
3529 },
3530 setter: function(value) {
3531 inputHandler.getValue()[index] = value;
3532 },
3533 deleter: deleter,
3534 editor: editor
3535 });
3536
3537 case "float":
3538 return new FormInputHandler(inputHandler.formConfig, {
3539 getter: function() {
3540 return inputHandler.getValue()[index];
3541 },
3542 setter: function(value) {
3543 value = parseFloat(value.replace(",", "."));
3544 if (!isNaN(value)) {
3545 inputHandler.getValue()[index] = value;
3546 } else {
3547 inputHandler.getValue()[index] = 0;
3548 }
3549 },
3550 deleter: deleter,
3551 editor: editor
3552 });
3553 }
3554
3555 alert(propertyValueType + " not supported");
3556 }
3557
3558 /**
3559 * Factory for creating different representations of a property
3560 * @type {string}
3561 */
3562 function createSettingType(inputHandler, editors, editorIndex, arrayOptions) {
3563 var value = inputHandler.getValue(),
3564 decorators,
3565 inputType,
3566 propName;
3567
3568 //array|addNew:number|delete|step=1000
3569 //color=color+number=stack
3570
3571 //q("with -> " + editors + ". isArray: " + isArrayType);
3572 //q(arrayOptions);
3573
3574 if (!arrayOptions.isArrayType) {
3575 decorators = editors.split("|");
3576 inputType = decorators[0];
3577 if (inputType.indexOf("=") > -1) {
3578 propName = inputType.split("=")[1];
3579 inputType = inputType.split("=")[0];
3580 }
3581
3582 //q("isArray: " + propName + "=> " + inputType);
3583 //q(decorators);
3584
3585 switch (inputType) {
3586 case "bool":
3587 return {
3588 build: function(id) {
3589 //assert(typeof value === 'boolean', (typeof value) + ": not a boolean");
3590 return "<input type='checkbox' id='"+id+"' "+(value ? " checked" : "")+" />";
3591 },
3592 bind: function(id) {
3593 $("#" + id).click(function() {
3594 inputHandler.setValue($(this).is(":checked"));
3595 });
3596 }
3597 };
3598 case "unit":
3599 return {
3600 build: function(id) {
3601 var i,
3602 html = "<select id='"+id+"'>";
3603
3604 for (i = 0; i < world_data.units.length; i++) {
3605 html += "<option "+(value == world_data.units[i] ? " selected" : "")+">"+world_data.units[i]+"</option>";
3606 }
3607 html += "</select>";
3608
3609 return html;
3610 },
3611 bind: function(id) {
3612 $("#" + id).click(function() {
3613 inputHandler.setValue($(this).val());
3614 });
3615 }
3616 };
3617 case "text":
3618 case "color":
3619 case "number":
3620 case "float":
3621 return (function() {
3622 var htmlString = "",
3623 index,
3624 inputBoxSize = 13,
3625 extraInputAttributes = "",
3626 extraHtml = "",
3627 inputTypeAttribute = inputType === "float" ? "number" : inputType;
3628
3629 switch (inputType) {
3630 case "text":
3631 if (typeof value === 'string') {
3632 value = value.toString().replace(/'/g, "'");
3633 }
3634 inputBoxSize = 50;
3635 break;
3636 }
3637 if (decorators.length > 1) {
3638 (function() {
3639 var keyValuePair;
3640 for (index = 0; index < decorators.length; index++) {
3641 keyValuePair = decorators[index].split("=");
3642 switch (keyValuePair[0]) {
3643 case "delete":
3644 extraHtml += " <a href='#' id='{domId}_delete'><img src='graphic/delete.png' title='"+trans.sp.sp.settings.deleteTooltip+"' /></a>";
3645 break;
3646 case "step":
3647 assert(inputType === "float" || inputType === "number", "step only works with numeric inputs");
3648 assert(keyValuePair.length === 2, "expected input: step=value");
3649 extraInputAttributes += " step='"+keyValuePair[1]+"'";
3650 break;
3651 case "width":
3652 inputBoxSize = keyValuePair[1];
3653 break;
3654 }
3655 }
3656 })();
3657 }
3658
3659 htmlString +=
3660 "<input type='" + inputTypeAttribute + "' id='{domId}' size='" + inputBoxSize +"' "
3661 + (typeof value !== 'undefined' ? " value='"+value+"'" : "")
3662 + extraInputAttributes +" />"
3663 + extraHtml;
3664
3665 return {
3666 build: function(id) {
3667 return htmlString.replace(/\{domId\}/g, id);
3668 },
3669 bind: function(id) {
3670 $("#" + id).change(function() {
3671 var newValue = $("#" + id).val();
3672 inputHandler.setValue(newValue, editorIndex);
3673 return false;
3674 });
3675
3676 $("#" + id + "_delete").click(function() {
3677 inputHandler.deleteValue();
3678 location.reload(false);
3679 });
3680 }
3681 };
3682 })();
3683 }
3684
3685 } else {
3686 return (function() {
3687 var typesArray = [],
3688 arrayIndex,
3689 canAddNew = false,
3690 inlineDiv = false;
3691
3692 decorators = arrayOptions.decorators;
3693
3694 //q(editors);
3695 //q(decorators);
3696 //q("----");
3697
3698 if (decorators.length > 0) {
3699 for (arrayIndex = 0; arrayIndex < decorators.length; arrayIndex++) {
3700 switch (decorators[arrayIndex]) {
3701 case "addNew":
3702 canAddNew = true;
3703 break;
3704 case "inline":
3705 inlineDiv = true;
3706 break;
3707 }
3708 }
3709 }
3710
3711 for (arrayIndex = 0; arrayIndex < value.length; arrayIndex++) {
3712 (function() {
3713 var fixedArrayIndex = arrayIndex;
3714 //q("createArraySettingType for" + fixedArrayIndex + "=" +editors);
3715 typesArray.push(createArraySettingType(inputHandler, fixedArrayIndex, editors));
3716 })();
3717 }
3718
3719 return {
3720 build: function(id) {
3721 var htmlString = "",
3722 arrayIndex,
3723 domId;
3724
3725 assert(typeof value === 'object', (typeof value) + ": not an object (array)");
3726
3727 for (arrayIndex = 0; arrayIndex < typesArray.length; arrayIndex++) {
3728 domId = id + "_" + arrayIndex;
3729
3730 htmlString += "<div" + (inlineDiv ? " style='display: inline'> " : ">");
3731 htmlString += typesArray[arrayIndex].build(domId);
3732 htmlString += "</div>";
3733 }
3734
3735 if (canAddNew) {
3736 htmlString += "<a href='#' id='"+id+"_new'>" + trans.sp.sp.settings.addRecord + "</a>";
3737 }
3738
3739 return htmlString;
3740 },
3741 bind: function(id) {
3742 var domId,
3743 arrayIndex;
3744
3745 if (canAddNew) {
3746 $("#" + id + "_new").click(function() {
3747 var domId = id + "_" + typesArray.length,
3748 newType;
3749
3750 newType = createArraySettingType(inputHandler, typesArray.length, editors);
3751 $(this).before("<div>" + newType.build(domId) + "</div>");
3752 newType.bind(domId);
3753 typesArray.push(newType);
3754
3755 $("#"+domId).focus();
3756 return false;
3757 });
3758 }
3759
3760 if (typesArray.length === 0 && canAddNew) {
3761 $("#" + id + "_new").click();
3762 } else {
3763 for (arrayIndex = 0; arrayIndex < typesArray.length; arrayIndex++) {
3764 domId = id + "_" + arrayIndex;
3765 typesArray[arrayIndex].bind(domId);
3766 }
3767 }
3768 }
3769 };
3770 })();
3771 }
3772
3773 assert(false, editors + " is not a valid editor");
3774 return;
3775 }
3776
3777 /**
3778 * @constructor
3779 */
3780 function FormInputHandler(propertyFormConfig, propSettings, editorIndex) {
3781 var arraySplit = propSettings.editor.split(":"),
3782 editors,
3783 arrayOptions = {isArrayType: arraySplit[0].indexOf('array') === 0},
3784 strategy;
3785
3786 assert(typeof propSettings.getter === 'function', 'getter should be a function');
3787 assert(typeof propSettings.setter === 'function', 'setter should be a function');
3788
3789 if (arrayOptions.isArrayType) {
3790 editors = arraySplit[1].split("+");
3791 } else {
3792 editors = arraySplit[0].split("+");
3793 }
3794
3795 //q(editors);
3796
3797 this.formConfig = propertyFormConfig;
3798 if (typeof propertyFormConfig.save === 'undefined') {
3799 this.setValue = propSettings.setter;
3800 this.deleteValue = propSettings.deleter;
3801 } else {
3802 this.setValue = function(value, editorIndex) {
3803 propSettings.setter(value, editorIndex);
3804 propertyFormConfig.save();
3805 };
3806
3807 this.deleteValue = function() {
3808 propSettings.deleter();
3809 propertyFormConfig.save();
3810 };
3811 }
3812
3813 this.getValue = propSettings.getter;
3814 if (true) {
3815 //q("createSettingType for " + editors[0] + " index " + editorIndex);
3816 if (arrayOptions.isArrayType) {
3817 arrayOptions.decorators = arraySplit[0].split("|");
3818 arrayOptions.decorators.splice(0, 1);
3819 }
3820
3821 strategy = createSettingType(this, editors[0], editorIndex, arrayOptions);
3822 this.build = strategy.build;
3823 this.bind = strategy.bind;
3824 } else {
3825 (function(inputHandler) {
3826 var handlers = [],
3827 index;
3828
3829 for (index = 0; index < editors.length; index++) {
3830 handlers.push(new FormInputHandler(propertyFormConfig, propSettings, index));
3831 }
3832
3833 inputHandler.build = function(id) {
3834 var i, htmlString = "";
3835 for (i = 0; i < handlers.length; i++) {
3836 htmlString += handlers[i].build(id + '_col' + i);
3837 htmlString += " ";
3838 }
3839 return htmlString;
3840 };
3841
3842 inputHandler.bind = function(id) {
3843 var i;
3844 for (i = 0; i < handlers.length; i++) {
3845 handlers[i].bind(id + '_col' + i);
3846 }
3847 };
3848 })(this);
3849 }
3850 }
3851
3852 function buildConfigForm(contentPage, propertyFormConfig) {
3853 var config = propertyFormConfig.properties,
3854 prop,
3855 properties = [],
3856 propIndex,
3857 form = "",
3858 formRow,
3859 container;
3860
3861 // show only relevant properties
3862 // has side-effects
3863 for (prop in config) {
3864 if (config.hasOwnProperty(prop)) {
3865 if (typeof config[prop].show === "undefined" || config[prop].show) {
3866 config[prop].ownName = prop;
3867 if (typeof config[prop].type === 'undefined') {
3868 // this is a variable <-> input form mapping
3869 config[prop].type = "propertyEditor";
3870 config[prop].propUI = new FormInputHandler(propertyFormConfig, config[prop].propUI);
3871
3872 } else {
3873 // these are other visual indications
3874 // ui is handled with if / else below
3875 }
3876
3877 properties.push(config[prop]);
3878 }
3879 }
3880 }
3881
3882 // build form
3883 form = "<table class='vis' width='100%'>";
3884 form += "<tr><th colspan='2'>" + propertyFormConfig.title + "</th>";
3885 form += "</table>";
3886 form = $(form);
3887
3888 container = $("<div class='propertyEditFormContainer' id='"+propertyFormConfig.id+"' style='display: none' />");
3889 container.append(form).append("<br>");
3890
3891 contentPage.append(container);
3892
3893 for (propIndex = 0; propIndex < properties.length; propIndex++) {
3894 var propUI = properties[propIndex];
3895 if (propUI.type === 'propertyEditor') {
3896 formRow = "<tr>";
3897
3898 // label
3899 formRow += "<td width='25%'>";
3900 if (typeof propUI.tooltip !== "undefined") {
3901 formRow += "<img src='graphic/questionmark.png' title='"+propUI.tooltip+"' /> ";
3902 }
3903 formRow += propUI.label;
3904 formRow += "</td>";
3905
3906 //editor
3907 if(propUI.label == sangu_trans.mainTagger.otherButtons.hitKey) {
3908 formRow += "<td width='75%'>ctrl + ";
3909 } else {
3910 formRow += "<td width='75%'>";
3911 }
3912 formRow += propUI.propUI.build(propertyFormConfig.id+"_"+propUI.ownName);
3913 formRow += "</td>";
3914
3915 formRow += "</tr>";
3916
3917 form.append(formRow);
3918
3919 // bind the form to the js variable
3920 if (typeof propUI.propUI.bind === 'function') {
3921 propUI.propUI.bind(propertyFormConfig.id+"_"+propUI.ownName);
3922 }
3923 } else {
3924 switch (propUI.type) {
3925 case "subtitle":
3926 form.append("<tr class='row_b'><td colspan='2'><b>"+propUI.label+"</b></td></tr>");
3927 break;
3928 }
3929 }
3930 }
3931 }
3932 /**
3933 * Contains all translations for the property setting editors
3934 */
3935 var sangu_trans = (function() {
3936 var sangu_trans = {};
3937 sangu_trans.nl = {
3938 main: {
3939 title: "Hoofdgebouw",
3940 villageNames: "Standaard dorpsnamen:",
3941 villageNamesTooltip: "Voeg je veelgebruikte dorpsnamen toe om een dorp met 1 klik te hernoemen.",
3942 villageNameClick: "Autoclick?",
3943 villageNameClickTooltip: "Schakel deze feature uit indien je bijvoorbeeld nog een nummer aan een standaard dorpsnaam wil toevoegen.",
3944 ajaxLoyalty: "Toestemming tonen?"
3945 },
3946 global: {
3947 title: "Op alle pagina's",
3948 tw_version: "Compatibiliteit met TW versie {version} afdwingen",
3949 tw_versionTooltip: "Dit gaat enkel de grijze Sangu bol niet meer tonen. Bugs door de TW update gaan niet op een magische manier opgelost zijn!",
3950 resources: {
3951 title: "Met kleuren aanduiden hoe vol de opslagplaats is",
3952 activate: trans.sp.sp.settings.activate,
3953 blinkWhenStorageFull: "Grondstoffen knipperen wanneer de opslagplaats vol is",
3954 colors: "Kleurenschakering"
3955 },
3956 incomingsTitle: "Binnenkomende aanvallen/ondersteuning links",
3957 incomingsEditLinks: "Linkdoelwit wijzigen",
3958 incomingsEditLinksTooltip: "De binnenkomende aanval/ondersteuning link wijzigen zodat de eerste 1000 bevelen getoond worden.",
3959 incomingsTrack: "Tijdchecker activeren",
3960 incomingsIndicator: "Tijdchecker tekst",
3961 incomingsIndicatorTooltip: "Gebruik {current} voor het huidig aantal binnenkomende aanvallen. "
3962 + "{difference} voor het aantal nieuwe aanvallen. "
3963 + "{saved} voor het laatst opgeslaan aantal aanvallen.",
3964 incomingsIndicatorTooltip2: "Tijdchecker tooltip",
3965 incomingsLastTimeCheckWarning: "Tijdchecker tooltip",
3966 incomingsLastTimeCheckWarningTooltip: "Gebruik {elapsed} voor de verstreken tijd. Gebruik {time} voor de laatste tijdcheck.",
3967 otherSettingsTitle: "Overige configuratie",
3968 visualizeFriends: "Aangeven welke vrienden momenteel online zijn",
3969 duplicateLogoffLink: "Voeg links onderaan een extra 'Afmelden' link toe.",
3970 colorsTitle: "Sangu achtergrondkleuren",
3971 colorsError: "Waarschuwingen",
3972 colorsNeutral: "Neutrale indicaties",
3973 colorsGood: "Positieve indicaties",
3974 colorsSpecial: "Speciale indicaties",
3975 jumperTitle: "Kaartspringer",
3976 jumperAutoOpen: "Het inputveld om coördinaten in te geven direct openen"
3977 },
3978 incoming: {
3979 title: "De standaard TW binnenkomende aanvallen tagger",
3980 autoOpenTagger: "De tagger direct openen indien het bevel nog niet hernoemd is",
3981 forceOpenTagger: "De tagger altijd openen",
3982 renameInputTexbox: "De standaard hernoemde bevelnaam",
3983 renameInputTexboxTooltip: "Legende: {unit}: korte eenheidnaam; {xy} coördinaten; {player}; {village}; {c} Continent; {fields} Afstand in velden; {night} Indicatie wanneer in nachtbonus. Maak leeg om te deactiveren.",
3984 invertSort: "De snelheid mogelijkheden sorteren",
3985 invertSortTooltip: "Vink dit aan om de traagste eenheid bovenaan te plaatsen"
3986 },
3987 overviews: {
3988 addFancyImagesToOverviewLinks: "Icons toevoegen aan de overzichtslinks",
3989 command: {
3990 title: "Overzichtsscherm: Troepenoverzicht",
3991 titleOwnTroopsPage: "Pagina's 'Eigen' en 'In het dorp'",
3992 middleMouseClickDeletesRow: "Actie bij <img src='graphic/command/attack.png'>"
3993 + " aanklikken met de middelste muisknop: Aangevinkt=rij verwijderen. Uitgevinkt: rode rand rond de \"Opdracht\" cell.",
3994 middleMouseClickDeletesRowTooltip: "Dit werkt enkel in Opera. Vink dit NIET AAN in Firefox of Chrome!! (De rode rand werkt ook niet in Firefox)",
3995 titleDefensePage: "Pagina's 'Verdediging' en 'Ondersteuning'",
3996 changeTroopsOverviewLink: "Link wijzigen om direct 'Eigen troepen' te openen",
3997 filterMinPopulation: "De standaard ingevulde waarde om te filteren op populatie",
3998 filterOnUnitTypeSeperator: "Eigen/In het dorp: Filteren op aantal eenheden",
3999 filterMinDefaultType: "De eenheid om te filteren die standaard geselecteerd is",
4000 filterMinDefault: "Het aantal eenheden om te filteren dat standaard ingevuld is",
4001 filterMinDefaultTooltip: "Dit aantal wordt ingevuld wanneer de pagina opent. Bij het selecteren van een andere eenheid worden de waarden hieronder gebruikt.",
4002 filterMinOther: "De standaard waarde voor de overige eenheden",
4003 filterAutoSort: "De dorpenlijst automatisch sorteren na het ingeven van een doeldorp"
4004 },
4005 troopsRestack: {
4006 title: "Alle pagina's: Stack BBCodes generatie",
4007 to: "Stack een dorp tot hoeveel populatie",
4008 requiredDifference: "Vereist verschil in huidige populatie in het dorp en de waarde hierboven",
4009 fieldsDistanceFilterDefault: "Het standaard ingevuld aantal velden waarop gefilterd wordt",
4010 filterReverse: "Aangevinkt: Rijen die voldoen aan de zoekopdracht tonen. Anders de rijen verbergen.",
4011 filterReverseTooltip: "Dit kan op de pagina zelf nog aangepast worden",
4012 defaultPopulationFilterAmount: "Het standaard ingevuld aantal voor de populatie filter",
4013 removeRowsWithoutSupport: "Bij het berekenen van de totalen dorpen zonder ondersteuning direct verbergen",
4014 autohideWithoutSupportAfterFilter: "Automatisch dorpen zonder overige ondersteuning wegfilteren na het toepassen van een filter",
4015 autohideWithoutSupportAfterFilterTooltip: "Bij de aanvalsfilter worden de dorpen die niet onder aanval zijn sowieso verborgen.",
4016 calculateDefTotalsAfterFilter: "Automatisch de totale ondersteuning per dorp berekenen na het toepassen van een filter",
4017 calculateDefTotalsAfterFilterTooltip: "Voor sommige filters moeten de totalen sowieso toch eerst berekend worden."
4018 },
4019 commands: {
4020 title: "Overzichtsscherm: Bevelen",
4021 sumRow: "Een scheidingsrij tussen verschillende dorpen toevoegen",
4022 filterFakeMaxPop: "Een bevel met minder dan deze populatie is een fake aanval (en wordt verborgen)",
4023 requiredTroopAmount: "Bij de export naar BBCodes worden bevelen met minder dan deze populatie overgeslagen."
4024 },
4025 resources: {
4026 title: "Overzichtsscherm: Productie",
4027 requiredResDefault: "Het aantal grondstoffen dat standaard in het invoerveld ingevuld is",
4028 requiredMerchants: "Het aantal handelaren dat standaard ingevuld is",
4029 filterMerchants: "Ook filteren op aantal beschikbare handelaren",
4030 filterRows: "Aanvinken om rijen te verbergen. Wanneer uitgevinkt wordt achtergrondkleur van de grondstoffen gewijzigd",
4031 bbcodeMinimumDiff: "Het minimum verschil in grondstoffen tussen het aantal in het dorp en het aantal waarop gefilterd wordt voordat het dorp in de BBcode export opgenomen wordt",
4032 highlightColor: "De achtergrondkleur die gebruikt wordt om de grondstoffen aan te duiden die voldoen aan de filtercriteria"
4033 },
4034 buildings: {
4035 title: "Overzichtsscherm: Gebouwen",
4036 minMaxTitle: "Geef de laagst en hoogst aanvaardbare levels voor je gebouwen",
4037 minLevel: "Min {building}",
4038 maxLevel: "Max {building}"
4039 },
4040 incomings: {
4041 title: "Overzichtsscherm: Aankomend",
4042 attackIdTitle: "Groeperen op aanvalsid",
4043 minValueTooltip: "De te tonen tekst wanneer het verschil in aanvalsid tussen de vorige binnenkomende aanval meer is dan het aangegeven verschil",
4044 seperatorTitle: "Bij verschil < {minValue}",
4045 minValue: "Minimum verschil",
4046 text: "Tekst",
4047 attackIdHigherDescription: "Te tonen tekst bij groter verschil in aanvalsid"
4048 }
4049 },
4050 place: {
4051 title: "Plaats: Speciale troepen invul links",
4052 titleCustom: "Plaats: Extra troepen invul links",
4053 linkText: "Link tekst",
4054 link: "Link: {name}",
4055
4056 scoutTitle: "Verkenner links",
4057 scoutVillage: "Een dorp krijgt verkenner links als er meer verkenners zijn dan dit",
4058 scoutPlaceLinks: "Links om zoveel verkenners in te vullen",
4059
4060 fakePlaceLinkTitle: "Fake troepen link",
4061 fakePlaceExcludeTroops: "Type troepen te negeren bij selecteren",
4062 fakePlaceExcludeTroopsTooltip: "Gebruik de namen: spear, sword, axe, archer, sword, spy, light, marcher, heavy, ram, catapult",
4063
4064 noblePlaceLinkTitle: "Edel links",
4065 noblePlaceLinkFirstTitle: "Edel link met het meeste troepen",
4066 noblePlaceLinkFirstNameTooltip: "Er blijven genoeg troepen thuis om voor de resterende edels nog ondersteuning te kunnen sturen. Maak leeg om deze link niet te tonen.",
4067
4068 noblePlaceLinkSupportTitle: "Edel link met minimale ondersteuning",
4069 noblePlaceLinksForceShow: "Ook tonen wanneer er slechts 1 edel in het dorp is",
4070 nobleSupportOffTitle: "Edel ondersteuning voor offensief dorp",
4071 nobleSupportDefTitle: "Edel ondersteuning voor defensief dorp",
4072 nobleSupportUnit: "Eenheid",
4073 nobleSupportAmount: "Aantal eenheden",
4074
4075 noblePlaceLinkDivideTitle: "Edel link met gelijk verdeelde ondersteuning",
4076 noblePlaceLinkDivideAddRam: "Rammen mee selecteren",
4077
4078 customPlaceLinksTitle: "Andere links",
4079 customPlaceOneTimeTooltip: "Vul een getal in om zoveel te sturen. Vul een negatief getal om zoveel te laten staan.",
4080 customPlaceSendAlong: "Meesturen tot",
4081 customPlaceSendAlongTooltip: "Indien er na selectie van bovenstaande troepen minder dan zoveel troepen in het dorp zou overblijven, selecteer dan alle troepen"
4082 },
4083 profile: {
4084 title: "Verfraaien van het profiel van spelers en stammen",
4085 moveClaim: "Verplaats dorpsclaim zodat alle andere links op dezelfde plaats blijven staan",
4086 mapLink: {
4087 title: "Kaarteigenschappen van link naar TWMaps kaart generator",
4088 fill: "Achtergrondkleur",
4089 zoom: 'Inzoom niveau',
4090 grid: 'Continentlijnen',
4091 gridContinentNumbers: "Continent nummers",
4092 playerColor: 'Spelerskleur',
4093 tribeColor: 'Zijn stam kleur',
4094 centreX: "Centreren op X coördinaat",
4095 centreY: "Centreren op Y coördinaat",
4096 ownColor: 'Eigen kleur',
4097 markedOnly: "Alleen gemarkeerde",
4098 yourTribeColor: "Eigen stam kleur",
4099 bigMarkers: "Grotere aanduidingen"
4100 },
4101 popup: {
4102 title: "Overnames popup",
4103 width: "Breedte van de popup",
4104 height: "Hoogte van de popup",
4105 left: "Horizontale positie",
4106 top: "Verticale positie"
4107 }
4108 },
4109 mainTagger: {
4110 title: "Tagger op dorpsoverzicht",
4111 autoOpen: "De tagger automatisch openen bij binnenkomende aanvallen",
4112 inputBoxWidth: "De breedte van de bevel hernoemings inputvelden",
4113 defaultDescription: "De naam die standaard in het hernoemings inputveld geplaatst wordt",
4114 defaultDescriptionTooltip: "Gebruik {xy} voor de coordinaten van het herkomst dorp",
4115 autoOpenCommands: "De bevel hernoemings inputvelden direct tonen",
4116 minutesDisplayDodgeTimeOnMap: "Aantal minuten dat de laatste dodgetijd op de kaart getoond wordt",
4117 minutesDisplayDodgeTimeOnMapTooltip: "De laatste dodgetijd is de tijd van het laatste bevel, aangeduidt met gewijzigde achtergrondkleur na het herbenoemen van binnenkomende aanvallen.",
4118 minutesWithoutAttacksDottedLine: "Elke zoveel minuten zonder een tussenliggende binnenkomende aanval aanduiden met een stippelijn (180 = 3 uur)",
4119 colorSupport: "Binnenkomende ondersteuning een andere achtergrondkleur geven",
4120 keepReservedWords: "Tekst die vervangen wordt door een eenheid icon behouden bij hernoemen binnenkomende aanval",
4121 keepReservedWordsTooltip: "Bijvoorbeeld \"Verk.\" wordt vervangen door een verkenners icon",
4122 otherButtons: {
4123 title: "Andere hernoemings knoppen",
4124 renameTo: "Hernoemen naar",
4125 button: "Tekst knop",
4126 hitKey: "Sneltoets"
4127 }
4128 },
4129 confirm: {
4130 title: "Bevel comfirmatie pagina",
4131 addExtraOkButton: "Links bovenaan de pagina een extra OK knop toevoegen",
4132 replaceNightBonus: "Nachtbonus melding verwerken in de pagina titel",
4133 replaceTribeClaim: "Dorpsclaim melding verwerken in de pagina titel",
4134 addCatapultImages: "Gebouws iconen tonen om snel het katapult doelwit te wijzigen"
4135 },
4136 villageInfo: {
4137 title: "Extra links naar het troepenoverzicht",
4138 title2: "Twee extra links naar het troepenoverzicht op elke dorpsinformatie pagina toevoegen",
4139 icon: "Kies een icoon",
4140 off_title: "Extra link voor aanvallen",
4141 def_title: "Extra link voor verdedigen",
4142 linkName: "De link die toegevoegd wordt",
4143 group: "Binnen welk groep id openen (kies 0 voor alle groepen)",
4144 groupTitle: "Zodra je meer dan 1000 dorpen bezit worden enkel die eerste 1000 getoond & gefilterd. Door een groep id in te geven (vb je groep \"aanvalsdorpen\" of \"verdedigingsdorpen\") wordt de troepenlijst binnen deze groep geopend.",
4145 activateFilter: "Filter activeren",
4146 filter: {
4147 title: "Direct filteren",
4148 unit: "Eenheid",
4149 amount: "Minimale hoeveelheid"
4150 },
4151 sort: "Dorpenlijst direct sorteren",
4152 changeSpeed: "Traagste eenheid snelheid wijzigen"
4153 },
4154 other: {
4155 title: "Overige configuratie",
4156 proStyle: "Pro Style?",
4157 proStyleTooltip: "Met deze setting worden een heleboel kleinere features aan of uitgeschakeld",
4158 timeDisplayTitle: "Hoe looptijden weergeven",
4159 displayDays: "Dagen tonen wanneer de troepen langer dan 24 uur lopen?",
4160 displayDaysTooltip: "Voorbeeld: toon \"1.18:01:36\" wanneer aangevinkt, zoniet wordt die looptijd als \"42:01:36\" weergegeven",
4161 walkingTimeDisplay: "Te tonen tekst",
4162 walkingTimeDisplayTooltip: "Gebruik {duration} voor het aantal uren en {arrival} voor de aankomstdatum",
4163 calculateSnob: "Berekenen hoeveel edels direct kunnen geproduceerd worden",
4164 showPlayerProfileOnVillage: "Het uitgebreide spelersprofiel tonen op een dorpsinformatie pagina",
4165 farmLimitTitle: "Dorpstacks achtergrondkleuren",
4166 farmLimitStackColors: "Kleurenschakering",
4167 farmLimitAcceptableOverstack: "Acceptabele overstack voor elke kleurschakering",
4168 farmLimitAcceptableOverstackTooltip: "Boerderijlimiet: {farmlimit}",
4169 farmLimitUnlimitedStack: "Aantal populatie voor elke kleurschakering",
4170 ajaxSeperateSupport: "Dorpsoverzicht: Visualiseer het verschil tussen eigen en ondersteunende troepen in het dorpsoverzicht",
4171 canHideDiv: "Dorpsoverzicht: Een extra X icon toevoegen om een info kader volledig te verwijderen",
4172 commandRenamer: "Bevelen automatisch hernoemen",
4173 commandRenamerActive: "De verzonden troepen in de bevelnaam weergeven",
4174 commandRenamerAddHaul: "De buit aan de bevelnaam toevoegen"
4175 }
4176 };
4177
4178 //sangu_trans.de = {};
4179
4180 /*sangu_trans.en = {
4181 main: {
4182 title: "Main building",
4183 villageNames: "Village names:",
4184 villageNamesTooltip: "Add village names to the village headquarters to quickly edit the village name to a preset name.",
4185 villageNameClick: "Autoclick?",
4186 villageNameClickTooltip: "true: one of the previous button clicked automatically changes the village name. false: only fills in the name in the textbox but does not click the button",
4187 ajaxLoyalty: "Show loyalty?",
4188 ajaxLoyaltyTooltip: "Get the loyalty at the building construction/destruction page"
4189 }
4190 };*/
4191
4192 return sangu_trans[game_data.market];
4193 }());
4194 /**
4195 * Configuration array containing the metadata for generating the different
4196 * property editor UIs
4197 */
4198 var user_data_configs = (function() {
4199 /**
4200 * Debug bool
4201 */
4202 var showConfigs = true,
4203 user_data_configs = [],
4204 sangu_saver = function() {
4205 pers.set('sangusettings', JSON.stringify(user_data));
4206 trackEvent("ScriptUsage", "SettingEdit", "1");
4207 };
4208
4209 if (showConfigs) {
4210 user_data_configs.push({
4211 id: "global",
4212 title: sangu_trans.global.title,
4213 save: sangu_saver,
4214 properties: {
4215 twVersion: {
4216 label: sangu_trans.global.tw_version.replace("{version}", game_data.majorVersion),
4217 tooltip: sangu_trans.global.tw_versionTooltip,
4218 propUI: {
4219 getter: function() { return pers.get("forceCompatibility") !== '' && pers.get("forceCompatibility") === 'true'; },
4220 setter: function(value) { pers.set("forceCompatibility", value); },
4221 editor: "bool"
4222 }
4223 },
4224 resourcesTitle: {
4225 type: "subtitle",
4226 label: sangu_trans.global.resources.title
4227 },
4228 resourcesActivate: {
4229 label: sangu_trans.global.resources.activate,
4230 propUI: {
4231 getter: function() { return user_data.global.resources.active; },
4232 setter: function(value) { user_data.global.resources.active = value; },
4233 editor: "bool"
4234 }
4235 },
4236 resourceColors: {
4237 label: sangu_trans.global.resources.colors,
4238 propUI: {
4239 getter: function() { return user_data.global.resources.backgroundColors; },
4240 setter: function(value) { user_data.global.resources.backgroundColors = value; },
4241 editor: "array|inline:color"
4242 }
4243 },
4244 resourcesBlinkWhenFull: {
4245 label: sangu_trans.global.resources.blinkWhenStorageFull,
4246 propUI: {
4247 getter: function() { return user_data.global.resources.blinkWhenStorageFull; },
4248 setter: function(value) { user_data.global.resources.blinkWhenStorageFull = value; },
4249 editor: "bool"
4250 }
4251 },
4252 incomingsTitle: {
4253 type: "subtitle",
4254 label: sangu_trans.global.incomingsTitle
4255 },
4256 incomingsEditLinks: {
4257 label: sangu_trans.global.incomingsEditLinks,
4258 tooltip: sangu_trans.global.incomingsEditLinksTooltip,
4259 propUI: {
4260 getter: function() { return user_data.global.incomings.editLinks; },
4261 setter: function(value) { user_data.global.incomings.editLinks = value; },
4262 editor: "bool"
4263 }
4264 },
4265 incomingsTrack: {
4266 label: sangu_trans.global.incomingsTrack,
4267 propUI: {
4268 getter: function() { return user_data.global.incomings.track; },
4269 setter: function(value) { user_data.global.incomings.track = value; },
4270 editor: "bool"
4271 }
4272 },
4273 incomingsIndicator: {
4274 label: sangu_trans.global.incomingsIndicator,
4275 tooltip: sangu_trans.global.incomingsIndicatorTooltip,
4276 propUI: {
4277 getter: function() { return user_data.global.incomings.indicator; },
4278 setter: function(value) { user_data.global.incomings.indicator = value; },
4279 editor: "text"
4280 }
4281 },
4282 incomingsIndicatorTooltip2: {
4283 label: sangu_trans.global.incomingsIndicatorTooltip2,
4284 propUI: {
4285 getter: function() { return user_data.global.incomings.indicatorTooltip; },
4286 setter: function(value) { user_data.global.incomings.indicatorTooltip = value; },
4287 editor: "text"
4288 }
4289 },
4290 lastTimeCheckWarning: {
4291 label: sangu_trans.global.incomingsLastTimeCheckWarning,
4292 tooltip: sangu_trans.global.incomingsLastTimeCheckWarningTooltip,
4293 propUI: {
4294 getter: function() { return user_data.global.incomings.lastTimeCheckWarning; },
4295 setter: function(value) { user_data.global.incomings.lastTimeCheckWarning = value; },
4296 editor: "text"
4297 }
4298 },
4299 jumperTitle: {
4300 type: "subtitle",
4301 label: sangu_trans.global.jumperTitle
4302 },
4303 jumperActivate: {
4304 label: trans.sp.sp.settings.activate,
4305 propUI: {
4306 getter: function() { return user_data.jumper.enabled; },
4307 setter: function(value) { user_data.jumper.enabled = value; },
4308 editor: "bool"
4309 }
4310 },
4311 jumperAutoOpen: {
4312 label: sangu_trans.global.jumperAutoOpen,
4313 propUI: {
4314 getter: function() { return user_data.jumper.autoShowInputbox; },
4315 setter: function(value) { user_data.jumper.autoShowInputbox = value; },
4316 editor: "bool"
4317 }
4318 },
4319 colorsTitle: {
4320 type: "subtitle",
4321 label: sangu_trans.global.colorsTitle
4322 },
4323 colorsError: {
4324 label: sangu_trans.global.colorsError,
4325 propUI: {
4326 getter: function() { return user_data.colors.error; },
4327 setter: function(value) { user_data.colors.error = value; },
4328 editor: "color"
4329 }
4330 },
4331 colorsGood: {
4332 label: sangu_trans.global.colorsGood,
4333 propUI: {
4334 getter: function() { return user_data.colors.good; },
4335 setter: function(value) { user_data.colors.good = value; },
4336 editor: "color"
4337 }
4338 },
4339 colorsNeutral: {
4340 label: sangu_trans.global.colorsNeutral,
4341 propUI: {
4342 getter: function() { return user_data.colors.neutral; },
4343 setter: function(value) { user_data.colors.neutral = value; },
4344 editor: "color"
4345 }
4346 },
4347 colorsSpecial: {
4348 label: sangu_trans.global.colorsSpecial,
4349 propUI: {
4350 getter: function() { return user_data.colors.special; },
4351 setter: function(value) { user_data.colors.special = value; },
4352 editor: "color"
4353 }
4354 },
4355 otherSettingsTitle: {
4356 type: "subtitle",
4357 label: sangu_trans.global.otherSettingsTitle
4358 },
4359 visualizeFriends: {
4360 label: sangu_trans.global.visualizeFriends,
4361 propUI: {
4362 getter: function() { return user_data.global.visualizeFriends; },
4363 setter: function(value) { user_data.global.visualizeFriends = value; },
4364 editor: "bool"
4365 }
4366 },
4367 duplicateLogoffLink: {
4368 label: sangu_trans.global.duplicateLogoffLink,
4369 propUI: {
4370 getter: function() { return user_data.global.duplicateLogoffLink; },
4371 setter: function(value) { user_data.global.duplicateLogoffLink = value; },
4372 editor: "bool"
4373 }
4374 }
4375 }
4376 });
4377 }
4378
4379 if (showConfigs) {
4380 user_data_configs.push({
4381 id: "main",
4382 title: sangu_trans.main.title,
4383 save: sangu_saver,
4384 properties: {
4385 villageNames: {
4386 tooltip: sangu_trans.main.villageNamesTooltip,
4387 label: sangu_trans.main.villageNames,
4388 propUI: {
4389 getter: function() { return user_data.main.villageNames; },
4390 setter: function(value) { user_data.main.villageNames = value; },
4391 editor: "array|addNew:text|delete"
4392 }
4393 },
4394 villageNameClick: {
4395 tooltip: sangu_trans.main.villageNameClickTooltip,
4396 label: sangu_trans.main.villageNameClick,
4397 propUI: {
4398 getter: function() { return user_data.main.villageNameClick; },
4399 setter: function(value) { user_data.main.villageNameClick = value; },
4400 editor: "bool"
4401 }
4402 },
4403 ajaxLoyalty: {
4404 label: sangu_trans.main.ajaxLoyalty,
4405 show: server_settings.ajaxAllowed,
4406 propUI: {
4407 getter: function() { return user_data.main.ajaxLoyalty; },
4408 setter: function(value) { user_data.main.ajaxLoyalty = value; },
4409 editor: "bool"
4410 }
4411 }
4412 }
4413 });
4414 }
4415
4416 if (showConfigs) {
4417 user_data_configs.push({
4418 id: "incoming",
4419 title: sangu_trans.incoming.title,
4420 save: sangu_saver,
4421 properties: {
4422 autoOpenTagger: {
4423 label: sangu_trans.incoming.autoOpenTagger,
4424 propUI: {
4425 getter: function() { return user_data.incoming.autoOpenTagger; },
4426 setter: function(value) { user_data.incoming.autoOpenTagger = value; },
4427 editor: "bool"
4428 }
4429 },
4430 forceOpenTagger: {
4431 label: sangu_trans.incoming.forceOpenTagger,
4432 propUI: {
4433 getter: function() { return user_data.incoming.forceOpenTagger; },
4434 setter: function(value) { user_data.incoming.forceOpenTagger = value; },
4435 editor: "bool"
4436 }
4437 },
4438 renameInputTexbox: {
4439 label: sangu_trans.incoming.renameInputTexbox,
4440 tooltip: sangu_trans.incoming.renameInputTexboxTooltip,
4441 propUI: {
4442 getter: function() { return user_data.incoming.renameInputTexbox; },
4443 setter: function(value) { user_data.incoming.renameInputTexbox = value; },
4444 editor: "text"
4445 }
4446 },
4447 invertSort: {
4448 label: sangu_trans.incoming.invertSort,
4449 tooltip: sangu_trans.incoming.invertSortTooltip,
4450 propUI: {
4451 getter: function() { return user_data.incoming.invertSort; },
4452 setter: function(value) { user_data.incoming.invertSort = value; },
4453 editor: "bool"
4454 }
4455 }
4456 }
4457 });
4458 }
4459
4460 if (showConfigs) {
4461 (function() {
4462 var properties = {
4463 activate: {
4464 label: sangu_trans.global.resources.activate,
4465 propUI: {
4466 getter: function() { return user_data.mainTagger2.active; },
4467 setter: function(value) { user_data.mainTagger2.active = value; },
4468 editor: "bool"
4469 }
4470 },
4471 autoOpen: {
4472 label: sangu_trans.mainTagger.autoOpen,
4473 propUI: {
4474 getter: function() { return user_data.mainTagger2.autoOpen; },
4475 setter: function(value) { user_data.mainTagger2.autoOpen = value; },
4476 editor: "bool"
4477 }
4478 },
4479 inputBoxWidth: {
4480 label: sangu_trans.mainTagger.inputBoxWidth,
4481 propUI: {
4482 getter: function() { return user_data.mainTagger2.inputBoxWidth; },
4483 setter: function(value) { user_data.mainTagger2.inputBoxWidth = value; },
4484 editor: "number|step=5"
4485 }
4486 },
4487 autoOpenCommands: {
4488 label: sangu_trans.mainTagger.autoOpenCommands,
4489 propUI: {
4490 getter: function() { return user_data.mainTagger2.autoOpenCommands; },
4491 setter: function(value) { user_data.mainTagger2.autoOpenCommands = value; },
4492 editor: "bool"
4493 }
4494 },
4495 minutesDisplayDodgeTimeOnMap: {
4496 label: sangu_trans.mainTagger.minutesDisplayDodgeTimeOnMap,
4497 tooltip: sangu_trans.mainTagger.minutesDisplayDodgeTimeOnMapTooltip,
4498 propUI: {
4499 getter: function() { return user_data.mainTagger2.minutesDisplayDodgeTimeOnMap; },
4500 setter: function(value) { user_data.mainTagger2.minutesDisplayDodgeTimeOnMap = value; },
4501 editor: "number"
4502 }
4503 },
4504 minutesWithoutAttacksDottedLine: {
4505 label: sangu_trans.mainTagger.minutesWithoutAttacksDottedLine,
4506 propUI: {
4507 getter: function() { return user_data.mainTagger2.minutesWithoutAttacksDottedLine; },
4508 setter: function(value) { user_data.mainTagger2.minutesWithoutAttacksDottedLine = value; },
4509 editor: "number|step=60"
4510 }
4511 },
4512 colorSupport: {
4513 label: sangu_trans.mainTagger.colorSupport,
4514 propUI: {
4515 getter: function() { return user_data.mainTagger2.colorSupport; },
4516 setter: function(value) { user_data.mainTagger2.colorSupport = value; },
4517 editor: "color"
4518 }
4519 },
4520 defaultDescription: {
4521 label: sangu_trans.mainTagger.defaultDescription,
4522 tooltip: sangu_trans.mainTagger.defaultDescriptionTooltip,
4523 propUI: {
4524 getter: function() { return user_data.mainTagger2.defaultDescription; },
4525 setter: function(value) { user_data.mainTagger2.defaultDescription = value; },
4526 editor: "text"
4527 }
4528 },
4529 keepReservedWords: {
4530 label: sangu_trans.mainTagger.keepReservedWords,
4531 tooltip: sangu_trans.mainTagger.keepReservedWordsTooltip,
4532 propUI: {
4533 getter: function() { return user_data.mainTagger2.keepReservedWords; },
4534 setter: function(value) { user_data.mainTagger2.keepReservedWords = value; },
4535 editor: "bool"
4536 }
4537 },
4538 otherButtonsTitle: {
4539 type: "subtitle",
4540 label: sangu_trans.mainTagger.otherButtons.title
4541 }
4542 };
4543
4544 for (var i = 0; i < user_data.mainTagger2.otherDescs.length; i++) {
4545 (function() {
4546 var otherDescription = user_data.mainTagger2.otherDescs[i];
4547
4548 properties['otherButton'+i] = {
4549 type: "subtitle",
4550 label: sangu_trans.mainTagger.otherButtons.title + ": " + otherDescription.name
4551 }
4552
4553 properties['otherButtonActive'+i] = {
4554 label: sangu_trans.global.resources.activate,
4555 propUI: {
4556 getter: function() { return otherDescription.active; },
4557 setter: function(value) { otherDescription.active = value; },
4558 editor: "bool"
4559 }
4560 }
4561
4562 properties['otherButtonName'+i] = {
4563 label: sangu_trans.mainTagger.otherButtons.button,
4564 propUI: {
4565 getter: function() { return otherDescription.name; },
4566 setter: function(value) { otherDescription.name = value; },
4567 editor: "text|width=10"
4568 }
4569 }
4570
4571 properties['otherButtonHitKey'+i] = {
4572 label: sangu_trans.mainTagger.otherButtons.hitKey,
4573 propUI: {
4574 getter: function() { return otherDescription.hitKey; },
4575 setter: function(value) { otherDescription.hitKey = value; },
4576 editor: "text|width=4"
4577 }
4578 }
4579
4580 properties['otherButtonDesc'+i] = {
4581 label: sangu_trans.mainTagger.otherButtons.renameTo,
4582 propUI: {
4583 getter: function() { return otherDescription.renameTo; },
4584 setter: function(value) { otherDescription.renameTo = value; },
4585 editor: "text|width=50"
4586 }
4587 }
4588 }());
4589 }
4590
4591
4592 user_data_configs.push({
4593 id: "mainTagger",
4594 title: sangu_trans.mainTagger.title,
4595 save: sangu_saver,
4596 properties: properties
4597 });
4598 }());
4599 }
4600
4601 if (showConfigs) {
4602 user_data_configs.push({
4603 id: "confirm",
4604 title: sangu_trans.confirm.title,
4605 save: sangu_saver,
4606 properties: {
4607 addExtraOkButton: {
4608 label: sangu_trans.confirm.addExtraOkButton,
4609 propUI: {
4610 getter: function() { return user_data.confirm.addExtraOkButton; },
4611 setter: function(value) { user_data.confirm.addExtraOkButton = value; },
4612 editor: "bool"
4613 }
4614 },
4615 replaceNightBonus: {
4616 label: sangu_trans.confirm.replaceNightBonus,
4617 show: world_config.nightbonus.active,
4618 propUI: {
4619 getter: function() { return user_data.confirm.replaceNightBonus; },
4620 setter: function(value) { user_data.confirm.replaceNightBonus = value; },
4621 editor: "bool"
4622 }
4623 },
4624 replaceTribeClaim: {
4625 label: sangu_trans.confirm.replaceTribeClaim,
4626 propUI: {
4627 getter: function() { return user_data.confirm.replaceTribeClaim; },
4628 setter: function(value) { user_data.confirm.replaceTribeClaim = value; },
4629 editor: "bool"
4630 }
4631 },
4632 addCatapultImages: {
4633 label: sangu_trans.confirm.addCatapultImages,
4634 propUI: {
4635 getter: function() { return user_data.confirm.addCatapultImages; },
4636 setter: function(value) { user_data.confirm.addCatapultImages = value; },
4637 editor: "bool"
4638 }
4639 }
4640 }
4641 });
4642 }
4643
4644 if (showConfigs) {
4645 user_data_configs.push({
4646 id: "profile",
4647 title: sangu_trans.profile.title,
4648 save: sangu_saver,
4649 properties: {
4650 show: {
4651 label: sangu_trans.global.resources.activate,
4652 propUI: {
4653 getter: function() { return user_data.profile.show; },
4654 setter: function(value) { user_data.profile.show = value; },
4655 editor: "bool"
4656 }
4657 },
4658 moveClaim: {
4659 label: sangu_trans.profile.moveClaim,
4660 propUI: {
4661 getter: function() { return user_data.profile.moveClaim; },
4662 setter: function(value) { user_data.profile.moveClaim = value; },
4663 editor: "bool"
4664 }
4665 },
4666 mapLink: {
4667 type: "subtitle",
4668 label: sangu_trans.profile.mapLink.title
4669 },
4670 mapLinkShow: {
4671 label: sangu_trans.global.resources.activate,
4672 propUI: {
4673 getter: function() { return user_data.profile.mapLink.show; },
4674 setter: function(value) { user_data.profile.mapLink.show = value; },
4675 editor: "bool"
4676 }
4677 },
4678 mapLinkFill: {
4679 label: sangu_trans.profile.mapLink.fill,
4680 propUI: {
4681 getter: function() { return user_data.profile.mapLink.fill; },
4682 setter: function(value) { user_data.profile.mapLink.fill = value; },
4683 editor: "color"
4684 }
4685 },
4686 mapLinkZoom: {
4687 label: sangu_trans.profile.mapLink.zoom,
4688 propUI: {
4689 getter: function() { return user_data.profile.mapLink.zoom; },
4690 setter: function(value) { user_data.profile.mapLink.zoom = value; },
4691 editor: "number|step=10"
4692 }
4693 },
4694 mapLinkGrid: {
4695 label: sangu_trans.profile.mapLink.grid,
4696 propUI: {
4697 getter: function() { return user_data.profile.mapLink.grid; },
4698 setter: function(value) { user_data.profile.mapLink.grid = value; },
4699 editor: "bool"
4700 }
4701 },
4702 mapLinkGridContinentNumbers: {
4703 label: sangu_trans.profile.mapLink.gridContinentNumbers,
4704 propUI: {
4705 getter: function() { return user_data.profile.mapLink.gridContinentNumbers; },
4706 setter: function(value) { user_data.profile.mapLink.gridContinentNumbers = value; },
4707 editor: "bool"
4708 }
4709 },
4710 mapLinkPlayerColor: {
4711 label: sangu_trans.profile.mapLink.playerColor,
4712 propUI: {
4713 getter: function() { return user_data.profile.mapLink.playerColor; },
4714 setter: function(value) { user_data.profile.mapLink.playerColor = value; },
4715 editor: "color"
4716 }
4717 },
4718 mapLinkTribeColor: {
4719 label: sangu_trans.profile.mapLink.tribeColor,
4720 propUI: {
4721 getter: function() { return user_data.profile.mapLink.tribeColor; },
4722 setter: function(value) { user_data.profile.mapLink.tribeColor = value; },
4723 editor: "color"
4724 }
4725 },
4726 mapLinkCentreX: {
4727 label: sangu_trans.profile.mapLink.centreX,
4728 propUI: {
4729 getter: function() { return user_data.profile.mapLink.centreX; },
4730 setter: function(value) { user_data.profile.mapLink.centreX = value; },
4731 editor: "number|step=10"
4732 }
4733 },
4734 mapLinkCentreY: {
4735 label: sangu_trans.profile.mapLink.centreY,
4736 propUI: {
4737 getter: function() { return user_data.profile.mapLink.centreY; },
4738 setter: function(value) { user_data.profile.mapLink.centreY = value; },
4739 editor: "number|step=10"
4740 }
4741 },
4742 mapLinkOwnColor: {
4743 label: sangu_trans.profile.mapLink.ownColor,
4744 propUI: {
4745 getter: function() { return user_data.profile.mapLink.ownColor; },
4746 setter: function(value) { user_data.profile.mapLink.ownColor = value; },
4747 editor: "color"
4748 }
4749 },
4750 mapLinkMarkedOnly: {
4751 label: sangu_trans.profile.mapLink.markedOnly,
4752 propUI: {
4753 getter: function() { return user_data.profile.mapLink.markedOnly; },
4754 setter: function(value) { user_data.profile.mapLink.markedOnly = value; },
4755 editor: "bool"
4756 }
4757 },
4758 mapLinkBigMarkers: {
4759 label: sangu_trans.profile.mapLink.bigMarkers,
4760 propUI: {
4761 getter: function() { return user_data.profile.mapLink.bigMarkers; },
4762 setter: function(value) { user_data.profile.mapLink.bigMarkers = value; },
4763 editor: "bool"
4764 }
4765 },
4766 mapLinkYourTribeColor: {
4767 label: sangu_trans.profile.mapLink.yourTribeColor,
4768 propUI: {
4769 getter: function() { return user_data.profile.mapLink.yourTribeColor; },
4770 setter: function(value) { user_data.profile.mapLink.yourTribeColor = value; },
4771 editor: "color"
4772 }
4773 },
4774 popup: {
4775 type: "subtitle",
4776 label: sangu_trans.profile.popup.title
4777 },
4778 popupShow: {
4779 label: sangu_trans.global.resources.activate,
4780 propUI: {
4781 getter: function() { return user_data.profile.popup.show; },
4782 setter: function(value) { user_data.profile.popup.show = value; },
4783 editor: "bool"
4784 }
4785 },
4786 popupTop: {
4787 label: sangu_trans.profile.popup.top,
4788 propUI: {
4789 getter: function() { return user_data.profile.popup.top; },
4790 setter: function(value) { user_data.profile.popup.top = value; },
4791 editor: "number|step=25"
4792 }
4793 },
4794 popupLeft: {
4795 label: sangu_trans.profile.popup.left,
4796 propUI: {
4797 getter: function() { return user_data.profile.popup.left; },
4798 setter: function(value) { user_data.profile.popup.left = value; },
4799 editor: "number|step=25"
4800 }
4801 },
4802 popupWidth: {
4803 label: sangu_trans.profile.popup.width,
4804 propUI: {
4805 getter: function() { return user_data.profile.popup.width; },
4806 setter: function(value) { user_data.profile.popup.width = value; },
4807 editor: "number|step=25"
4808 }
4809 },
4810 popupHeight: {
4811 label: sangu_trans.profile.popup.height,
4812 propUI: {
4813 getter: function() { return user_data.profile.popup.height; },
4814 setter: function(value) { user_data.profile.popup.height = value; },
4815 editor: "number|step=25"
4816 }
4817 }
4818 }
4819 });
4820 }
4821
4822 if (showConfigs) {
4823 user_data_configs.push({
4824 id: "placeLinks",
4825 title: sangu_trans.place.title,
4826 save: sangu_saver,
4827 properties: {
4828 scoutTitle: {
4829 type: "subtitle",
4830 label: sangu_trans.place.scoutTitle
4831 },
4832 scoutPlaceLinksName: {
4833 label: sangu_trans.place.linkText,
4834 propUI: {
4835 getter: function() { return user_data.place.attackLinks.scoutPlaceLinksName; },
4836 setter: function(value) { user_data.place.attackLinks.scoutPlaceLinksName = value; },
4837 editor: "text|width=23"
4838 }
4839 },
4840 scoutVillage: {
4841 label: sangu_trans.place.scoutVillage,
4842 propUI: {
4843 getter: function() { return user_data.place.attackLinks.scoutVillage; },
4844 setter: function(value) { user_data.place.attackLinks.scoutVillage = value; },
4845 editor: "number|step=10"
4846 }
4847 },
4848 scoutPlaceLinks: {
4849 label: sangu_trans.place.scoutPlaceLinks,
4850 propUI: {
4851 getter: function() { return user_data.place.attackLinks.scoutPlaceLinks; },
4852 setter: function(value) { user_data.place.attackLinks.scoutPlaceLinks = value; },
4853 editor: "array|addNew:number|step=10|delete"
4854 }
4855 },
4856
4857
4858
4859
4860
4861 fakePlaceLinkTitle: {
4862 type: "subtitle",
4863 label: sangu_trans.place.fakePlaceLinkTitle
4864 },
4865 fakePlaceLinkName: {
4866 label: sangu_trans.place.linkText,
4867 propUI: {
4868 getter: function() { return user_data.place.attackLinks.fakePlaceLinkName; },
4869 setter: function(value) { user_data.place.attackLinks.fakePlaceLinkName = value; },
4870 editor: "text|width=23"
4871 }
4872 },
4873 fakePlaceLink: {
4874 label: sangu_trans.global.resources.activate,
4875 propUI: {
4876 getter: function() { return user_data.place.attackLinks.fakePlaceLink; },
4877 setter: function(value) { user_data.place.attackLinks.fakePlaceLink = value; },
4878 editor: "bool"
4879 }
4880 },
4881 fakePlaceExcludeTroops: {
4882 label: sangu_trans.place.fakePlaceExcludeTroops,
4883 tooltip: sangu_trans.place.fakePlaceExcludeTroopsTooltip,
4884 propUI: {
4885 getter: function() { return user_data.place.attackLinks.fakePlaceExcludeTroops; },
4886 setter: function(value) { user_data.place.attackLinks.fakePlaceExcludeTroops = value; },
4887 editor: "array|addNew:text|delete|width=7"
4888 }
4889 },
4890
4891
4892
4893
4894
4895
4896 noblePlaceLinkTitle: {
4897 type: "subtitle",
4898 label: sangu_trans.place.noblePlaceLinkTitle
4899 },
4900 noblePlaceLinkDivideTitle: {
4901 type: "subtitle",
4902 label: sangu_trans.place.noblePlaceLinkDivideTitle
4903 },
4904 noblePlaceLinkDivideName: {
4905 label: sangu_trans.place.linkText,
4906 propUI: {
4907 getter: function() { return user_data.place.attackLinks.noblePlaceLinkDivideName; },
4908 setter: function(value) { user_data.place.attackLinks.noblePlaceLinkDivideName = value; },
4909 editor: "text|width=23"
4910 }
4911 },
4912 noblePlaceLink: {
4913 label: sangu_trans.global.resources.activate,
4914 propUI: {
4915 getter: function() { return user_data.place.attackLinks.noblePlaceLink; },
4916 setter: function(value) { user_data.place.attackLinks.noblePlaceLink = value; },
4917 editor: "bool"
4918 }
4919 },
4920 noblePlaceLinkDivideAddRam: {
4921 label: sangu_trans.place.noblePlaceLinkDivideAddRam,
4922 propUI: {
4923 getter: function() { return user_data.place.attackLinks.noblePlaceLinkDivideAddRam; },
4924 setter: function(value) { user_data.place.attackLinks.noblePlaceLinkDivideAddRam = value; },
4925 editor: "bool"
4926 }
4927 },
4928 noblePlaceLinkFirstTitle: {
4929 type: "subtitle",
4930 label: sangu_trans.place.noblePlaceLinkFirstTitle
4931 },
4932 noblePlaceLinkFirstName: {
4933 label: sangu_trans.place.linkText,
4934 tooltip: sangu_trans.place.noblePlaceLinkFirstNameTooltip,
4935 propUI: {
4936 getter: function() { return user_data.place.attackLinks.noblePlaceLinkFirstName; },
4937 setter: function(value) { user_data.place.attackLinks.noblePlaceLinkFirstName = value; },
4938 editor: "text|width=23"
4939 }
4940 },
4941 noblePlaceLinkSupportTitle: {
4942 type: "subtitle",
4943 label: sangu_trans.place.noblePlaceLinkSupportTitle
4944 },
4945 noblePlaceLinkSupportName: {
4946 label: sangu_trans.place.linkText,
4947 propUI: {
4948 getter: function() { return user_data.place.attackLinks.noblePlaceLinkSupportName; },
4949 setter: function(value) { user_data.place.attackLinks.noblePlaceLinkSupportName = value; },
4950 editor: "text|width=23"
4951 }
4952 },
4953 noblePlaceLinksForceShow: {
4954 label: sangu_trans.place.noblePlaceLinksForceShow,
4955 propUI: {
4956 getter: function() { return user_data.place.attackLinks.noblePlaceLinksForceShow; },
4957 setter: function(value) { user_data.place.attackLinks.noblePlaceLinksForceShow = value; },
4958 editor: "bool"
4959 }
4960 },
4961 nobleSupportOffTitle: {
4962 type: "subtitle",
4963 label: sangu_trans.place.nobleSupportOffTitle
4964 },
4965 nobleSupportOffUnit: {
4966 label: sangu_trans.place.nobleSupportUnit,
4967 propUI: {
4968 getter: function() { return user_data.place.attackLinks.nobleSupport[0].unit; },
4969 setter: function(value) { user_data.place.attackLinks.nobleSupport[0].unit = value; },
4970 editor: "unit"
4971 }
4972 },
4973 nobleSupportOffAmount: {
4974 label: sangu_trans.place.nobleSupportAmount,
4975 propUI: {
4976 getter: function() { return user_data.place.attackLinks.nobleSupport[0].amount; },
4977 setter: function(value) { user_data.place.attackLinks.nobleSupport[0].amount = value; },
4978 editor: "number|step=50"
4979 }
4980 },
4981 nobleSupportDefTitle: {
4982 type: "subtitle",
4983 label: sangu_trans.place.nobleSupportDefTitle
4984 },
4985 nobleSupportDefUnit: {
4986 label: sangu_trans.place.nobleSupportUnit,
4987 propUI: {
4988 getter: function() { return user_data.place.attackLinks.nobleSupport[1].unit; },
4989 setter: function(value) { user_data.place.attackLinks.nobleSupport[1].unit = value; },
4990 editor: "unit"
4991 }
4992 },
4993 nobleSupportDefAmount: {
4994 label: sangu_trans.place.nobleSupportAmount,
4995 propUI: {
4996 getter: function() { return user_data.place.attackLinks.nobleSupport[1].amount; },
4997 setter: function(value) { user_data.place.attackLinks.nobleSupport[1].amount = value; },
4998 editor: "number|step=50"
4999 }
5000 }
5001 }
5002 });
5003 }
5004
5005 if (showConfigs) {
5006 (function() {
5007 var i,
5008 properties = {};
5009
5010 for (i = 0; i < user_data.place.customPlaceLinks.length; i++) {
5011 (function() {
5012 var unitTypeIndex,
5013 customPlaceLink = user_data.place.customPlaceLinks[i],
5014 oneTimeTooltip = i == 0 ? sangu_trans.place.customPlaceOneTimeTooltip : undefined,
5015 oneTimeTooltipSendAlong = i == 0 ? sangu_trans.place.customPlaceSendAlongTooltip : undefined;
5016
5017 properties['customPlaceLink'+i+'Title'] = {
5018 type: "subtitle",
5019 label: sangu_trans.place.link.replace("{name}", customPlaceLink.name)
5020 };
5021
5022 properties['customPlaceLink'+i+'Name'] = {
5023 label: sangu_trans.place.linkText,
5024 propUI: {
5025 getter: function() { return customPlaceLink.name; },
5026 setter: function(value) { customPlaceLink.name = value; },
5027 editor: "text|width=23"
5028 }
5029 };
5030
5031 properties['customPlaceLink'+i+'Active'] = {
5032 label: sangu_trans.global.resources.activate,
5033 propUI: {
5034 getter: function() { return customPlaceLink.active; },
5035 setter: function(value) { customPlaceLink.active = value; },
5036 editor: "bool"
5037 }
5038 };
5039
5040 for (unitTypeIndex = 0; unitTypeIndex < world_data.units.length; unitTypeIndex++) {
5041 (function() {
5042 var unit = world_data.units[unitTypeIndex],
5043 reallyOneTimeTooltip = unitTypeIndex == 0 && oneTimeTooltip ? oneTimeTooltip : undefined;
5044
5045 properties['customPlaceLink'+i+unit] = {
5046 label: "<img src='graphic/unit/unit_"+unit+".png'/>",
5047 tooltip: reallyOneTimeTooltip,
5048 propUI: {
5049 getter: function() { return customPlaceLink[unit]; },
5050 setter: function(value) { customPlaceLink[unit] = value; },
5051 editor: "number|step=100"
5052 }
5053 };
5054 })();
5055 }
5056
5057 properties['customPlaceLink'+i+'SendAlong'] = {
5058 label: sangu_trans.place.customPlaceSendAlong,
5059 tooltip: oneTimeTooltipSendAlong,
5060 propUI: {
5061 getter: function() { return customPlaceLink.sendAlong; },
5062 setter: function(value) { customPlaceLink.sendAlong = value; },
5063 editor: "number|step=100"
5064 }
5065 };
5066 })();
5067 }
5068
5069 user_data_configs.push({
5070 id: "placeLinksCustom",
5071 title: sangu_trans.place.titleCustom,
5072 save: sangu_saver,
5073 properties: properties
5074 });
5075 }());
5076 }
5077
5078 if (showConfigs) {
5079 user_data_configs.push({
5080 id: "overviewsTroops",
5081 title: sangu_trans.overviews.command.title,
5082 save: sangu_saver,
5083 properties: {
5084 changeTroopsOverviewLink: {
5085 label: sangu_trans.overviews.command.changeTroopsOverviewLink,
5086 propUI: {
5087 getter: function() { return user_data.command.changeTroopsOverviewLink; },
5088 setter: function(value) { user_data.command.changeTroopsOverviewLink = value; },
5089 editor: "bool"
5090 }
5091 },
5092 defaultPopulationFilterAmount: {
5093 label: sangu_trans.overviews.troopsRestack.defaultPopulationFilterAmount,
5094 propUI: {
5095 getter: function() { return user_data.restack.defaultPopulationFilterAmount; },
5096 setter: function(value) { user_data.restack.defaultPopulationFilterAmount = value; },
5097 editor: "number|step=1000"
5098 }
5099 },
5100
5101 titleOwnTroopsPage: {
5102 type: "subtitle",
5103 label: sangu_trans.overviews.command.titleOwnTroopsPage
5104 },
5105 middleMouseClickDeletesRow: {
5106 label: sangu_trans.overviews.command.middleMouseClickDeletesRow,
5107 tooltip: sangu_trans.overviews.command.middleMouseClickDeletesRowTooltip,
5108 propUI: {
5109 getter: function() { return user_data.command.middleMouseClickDeletesRow2; },
5110 setter: function(value) { user_data.command.middleMouseClickDeletesRow2 = value; },
5111 editor: "bool"
5112 }
5113 },
5114 filterAutoSort: {
5115 label: sangu_trans.overviews.command.filterAutoSort,
5116 propUI: {
5117 getter: function() { return user_data.command.filterAutoSort; },
5118 setter: function(value) { user_data.command.filterAutoSort = value; },
5119 editor: "bool"
5120 }
5121 },
5122
5123
5124 titleDefensePage: {
5125 type: "subtitle",
5126 label: sangu_trans.overviews.command.titleDefensePage
5127 },
5128 fieldsDistanceFilterDefault: {
5129 label: sangu_trans.overviews.troopsRestack.fieldsDistanceFilterDefault,
5130 propUI: {
5131 getter: function() { return user_data.restack.fieldsDistanceFilterDefault; },
5132 setter: function(value) { user_data.restack.fieldsDistanceFilterDefault = value; },
5133 editor: "number"
5134 }
5135 },
5136 filterReverse: {
5137 label: sangu_trans.overviews.troopsRestack.filterReverse,
5138 tooltip: sangu_trans.overviews.troopsRestack.filterReverseTooltip,
5139 propUI: {
5140 getter: function() { return user_data.restack.filterReverse; },
5141 setter: function(value) { user_data.restack.filterReverse = value; },
5142 editor: "bool"
5143 }
5144 },
5145 filterMinPopulation: {
5146 label: sangu_trans.overviews.command.filterMinPopulation,
5147 propUI: {
5148 getter: function() { return user_data.command.filterMinPopulation; },
5149 setter: function(value) { user_data.command.filterMinPopulation = value; },
5150 editor: "number|step=1000"
5151 }
5152 },
5153 removeRowsWithoutSupport: {
5154 label: sangu_trans.overviews.troopsRestack.removeRowsWithoutSupport,
5155 propUI: {
5156 getter: function() { return user_data.restack.removeRowsWithoutSupport; },
5157 setter: function(value) { user_data.restack.removeRowsWithoutSupport = value; },
5158 editor: "bool"
5159 }
5160 },
5161 autohideWithoutSupportAfterFilter: {
5162 label: sangu_trans.overviews.troopsRestack.autohideWithoutSupportAfterFilter,
5163 tooltip: sangu_trans.overviews.troopsRestack.autohideWithoutSupportAfterFilterTooltip,
5164 propUI: {
5165 getter: function() { return user_data.restack.autohideWithoutSupportAfterFilter; },
5166 setter: function(value) { user_data.restack.autohideWithoutSupportAfterFilter = value; },
5167 editor: "bool"
5168 }
5169 },
5170 calculateDefTotalsAfterFilter: {
5171 label: sangu_trans.overviews.troopsRestack.calculateDefTotalsAfterFilter,
5172 tooltip: sangu_trans.overviews.troopsRestack.calculateDefTotalsAfterFilterTooltip,
5173 propUI: {
5174 getter: function() { return user_data.restack.calculateDefTotalsAfterFilter; },
5175 setter: function(value) { user_data.restack.calculateDefTotalsAfterFilter = value; },
5176 editor: "bool"
5177 }
5178 },
5179
5180 commandTitle: {
5181 type: "subtitle",
5182 label: sangu_trans.overviews.command.filterOnUnitTypeSeperator
5183 },
5184 filterMinDefaultType: {
5185 label: sangu_trans.overviews.command.filterMinDefaultType,
5186 propUI: {
5187 getter: function() { return user_data.command.filterMinDefaultType; },
5188 setter: function(value) { user_data.command.filterMinDefaultType = value; },
5189 editor: "unit"
5190 }
5191 },
5192 filterMinDefault: {
5193 label: sangu_trans.overviews.command.filterMinDefault,
5194 tooltip: sangu_trans.overviews.command.filterMinDefaultTooltip,
5195 propUI: {
5196 getter: function() { return user_data.command.filterMinDefault; },
5197 setter: function(value) { user_data.command.filterMinDefault = value; },
5198 editor: "number|step=100"
5199 }
5200 },
5201 filterMinSpear: {
5202 label: "<img src='graphic/unit/unit_spear.png' />",
5203 propUI: {
5204 getter: function() { return user_data.command.filterMin.spear; },
5205 setter: function(value) { user_data.command.filterMin.spear = value; },
5206 editor: "number|step=500"
5207 }
5208 },
5209 filterMinSword: {
5210 label: "<img src='graphic/unit/unit_sword.png' />",
5211 propUI: {
5212 getter: function() { return user_data.command.filterMin.sword; },
5213 setter: function(value) { user_data.command.filterMin.sword = value; },
5214 editor: "number|step=500"
5215 }
5216 },
5217 filterMinAxe: {
5218 label: "<img src='graphic/unit/unit_axe.png' />",
5219 propUI: {
5220 getter: function() { return user_data.command.filterMin.axe; },
5221 setter: function(value) { user_data.command.filterMin.axe = value; },
5222 editor: "number|step=500"
5223 }
5224 },
5225 filterMinArcher: {
5226 label: "<img src='graphic/unit/unit_archer.png' />",
5227 show: world_config.hasArchers,
5228 propUI: {
5229 getter: function() { return user_data.command.filterMin.archer; },
5230 setter: function(value) { user_data.command.filterMin.archer = value; },
5231 editor: "number|step=500"
5232 }
5233 },
5234 filterMinSpy: {
5235 label: "<img src='graphic/unit/unit_spy.png' />",
5236 propUI: {
5237 getter: function() { return user_data.command.filterMin.spy; },
5238 setter: function(value) { user_data.command.filterMin.spy = value; },
5239 editor: "number|step=100"
5240 }
5241 },
5242 filterMinLight: {
5243 label: "<img src='graphic/unit/unit_light.png' />",
5244 propUI: {
5245 getter: function() { return user_data.command.filterMin.light; },
5246 setter: function(value) { user_data.command.filterMin.light = value; },
5247 editor: "number|step=100"
5248 }
5249 },
5250 filterMinMarcher: {
5251 label: "<img src='graphic/unit/unit_marcher.png' />",
5252 show: world_config.hasArchers,
5253 propUI: {
5254 getter: function() { return user_data.command.filterMin.marcher; },
5255 setter: function(value) { user_data.command.filterMin.marcher = value; },
5256 editor: "number|step=100"
5257 }
5258 },
5259 filterMinHeavy: {
5260 label: "<img src='graphic/unit/unit_heavy.png' />",
5261 propUI: {
5262 getter: function() { return user_data.command.filterMin.heavy; },
5263 setter: function(value) { user_data.command.filterMin.heavy = value; },
5264 editor: "number|step=100"
5265 }
5266 },
5267 filterMinRam: {
5268 label: "<img src='graphic/unit/unit_ram.png' />",
5269 propUI: {
5270 getter: function() { return user_data.command.filterMin.ram; },
5271 setter: function(value) { user_data.command.filterMin.ram = value; },
5272 editor: "number|step=10"
5273 }
5274 },
5275 filterMinCatapult: {
5276 label: "<img src='graphic/unit/unit_catapult.png' />",
5277 propUI: {
5278 getter: function() { return user_data.command.filterMin.catapult; },
5279 setter: function(value) { user_data.command.filterMin.catapult = value; },
5280 editor: "number|step=10"
5281 }
5282 },
5283 filterMinSnob: {
5284 label: "<img src='graphic/unit/unit_snob.png' />",
5285 propUI: {
5286 getter: function() { return user_data.command.filterMin.snob; },
5287 setter: function(value) { user_data.command.filterMin.snob = value; },
5288 editor: "number"
5289 }
5290 },
5291 filterMinOther: {
5292 label: sangu_trans.overviews.command.filterMinOther,
5293 propUI: {
5294 getter: function() { return user_data.command.filterMinOther; },
5295 setter: function(value) { user_data.command.filterMinOther = value; },
5296 editor: "number|step=500"
5297 }
5298 },
5299 restackTitle: {
5300 type: "subtitle",
5301 label: sangu_trans.overviews.troopsRestack.title
5302 },
5303 troopsRestackTo: {
5304 label: sangu_trans.overviews.troopsRestack.to,
5305 propUI: {
5306 getter: function() { return user_data.restack.to; },
5307 setter: function(value) { user_data.restack.to = value; },
5308 editor: "number|step=1000"
5309 }
5310 },
5311 requiredDifference: {
5312 label: sangu_trans.overviews.troopsRestack.requiredDifference,
5313 propUI: {
5314 getter: function() { return user_data.restack.requiredDifference; },
5315 setter: function(value) { user_data.restack.requiredDifference = value; },
5316 editor: "number|step=500"
5317 }
5318 }
5319 }
5320 });
5321 }
5322
5323 if (showConfigs) {
5324 user_data_configs.push({
5325 id: "overviewsCommands",
5326 title: sangu_trans.overviews.commands.title,
5327 save: sangu_saver,
5328 properties: {
5329 sumRow: {
5330 label: sangu_trans.overviews.commands.sumRow,
5331 propUI: {
5332 getter: function() { return user_data.command.sumRow; },
5333 setter: function(value) { user_data.command.sumRow = value; },
5334 editor: "bool"
5335 }
5336 },
5337 filterFakeMaxPop: {
5338 label: sangu_trans.overviews.commands.filterFakeMaxPop,
5339 propUI: {
5340 getter: function() { return user_data.command.filterFakeMaxPop; },
5341 setter: function(value) { user_data.command.filterFakeMaxPop = value; },
5342 editor: "number|step=100"
5343 }
5344 },
5345 requiredTroopAmount: {
5346 label: sangu_trans.overviews.commands.requiredTroopAmount,
5347 propUI: {
5348 getter: function() { return user_data.command.bbCodeExport.requiredTroopAmount; },
5349 setter: function(value) { user_data.command.bbCodeExport.requiredTroopAmount = value; },
5350 editor: "number|step=100"
5351 }
5352 }
5353 }
5354 });
5355 }
5356
5357 if (showConfigs) {
5358 user_data_configs.push({
5359 id: "overviewsResources",
5360 title: sangu_trans.overviews.resources.title,
5361 save: sangu_saver,
5362 properties: {
5363 requiredResDefault: {
5364 label: sangu_trans.overviews.resources.requiredResDefault,
5365 propUI: {
5366 getter: function() { return user_data.resources.requiredResDefault; },
5367 setter: function(value) { user_data.resources.requiredResDefault = value; },
5368 editor: "number|step=10000"
5369 }
5370 },
5371 requiredMerchants: {
5372 label: sangu_trans.overviews.resources.requiredMerchants,
5373 propUI: {
5374 getter: function() { return user_data.resources.requiredMerchants; },
5375 setter: function(value) { user_data.resources.requiredMerchants = value; },
5376 editor: "number|step=10"
5377 }
5378 },
5379 filterMerchants: {
5380 label: sangu_trans.overviews.resources.filterMerchants,
5381 propUI: {
5382 getter: function() { return user_data.resources.filterMerchants; },
5383 setter: function(value) { user_data.resources.filterMerchants = value; },
5384 editor: "bool"
5385 }
5386 },
5387 highlightColor: {
5388 label: sangu_trans.overviews.resources.highlightColor,
5389 propUI: {
5390 getter: function() { return user_data.resources.highlightColor; },
5391 setter: function(value) { user_data.resources.highlightColor = value; },
5392 editor: "color"
5393 }
5394 },
5395 filterRows: {
5396 label: sangu_trans.overviews.resources.filterRows,
5397 propUI: {
5398 getter: function() { return user_data.resources.filterRows; },
5399 setter: function(value) { user_data.resources.filterRows = value; },
5400 editor: "bool"
5401 }
5402 },
5403 bbcodeMinimumDiff: {
5404 label: sangu_trans.overviews.resources.bbcodeMinimumDiff,
5405 propUI: {
5406 getter: function() { return user_data.resources.bbcodeMinimumDiff; },
5407 setter: function(value) { user_data.resources.bbcodeMinimumDiff = value; },
5408 editor: "number|step=2000"
5409 }
5410 }
5411 }
5412 });
5413 }
5414
5415 if (showConfigs) {
5416 // Buildingsoverview:
5417 (function() {
5418 var properties = {},
5419 i;
5420
5421 for (i = 0; i < world_data.buildings.length; i++) {
5422 (function() {
5423 var captured_index = i,
5424 building_name = world_data.buildings[captured_index],
5425 buildingPrettyfier = function(building) { return "<img src='graphic/buildings/"+building+".png'>"; };
5426
5427 properties[building_name+'_min'] = {
5428 label: sangu_trans.overviews.buildings.minLevel.replace("{building}", buildingPrettyfier(building_name)),
5429 propUI: {
5430 getter: function() { return user_data.buildings[building_name][0]; },
5431 setter: function(value) { user_data.buildings[building_name][0] = value; },
5432 editor: "number"
5433 }
5434 };
5435
5436 properties[building_name+'_max'] = {
5437 label: sangu_trans.overviews.buildings.maxLevel.replace("{building}", buildingPrettyfier(building_name)),
5438 propUI: {
5439 getter: function() { return user_data.buildings[building_name][1]; },
5440 setter: function(value) { user_data.buildings[building_name][1] = value; },
5441 editor: "number"
5442 }
5443 };
5444 })();
5445 }
5446
5447 user_data_configs.push({
5448 id: "overviewsBuildings",
5449 title: sangu_trans.overviews.buildings.title,
5450 save: sangu_saver,
5451 properties: properties
5452 });
5453 }());
5454 }
5455
5456 if (showConfigs) {
5457 // Incomingsoverview:
5458 (function() {
5459 var properties = {},
5460 i;
5461
5462 properties.attackIdTitle = {
5463 type: "subtitle",
5464 label: sangu_trans.overviews.incomings.attackIdTitle
5465 };
5466
5467 for (i = 0; i < user_data.incomings.attackIdDescriptions.length; i++) {
5468 (function() {
5469 var captured_index = i;
5470
5471 properties['incomings_attackIdDesc'+captured_index+'_title'] = {
5472 type: "subtitle",
5473 label: sangu_trans.overviews.incomings.seperatorTitle.replace("{minValue}", user_data.incomings.attackIdDescriptions[captured_index].minValue)
5474 };
5475
5476 properties['incomings_attackIdDesc'+captured_index+'_minValue'] = {
5477 label: sangu_trans.overviews.incomings.minValue,
5478 tooltip: captured_index == 0 ? sangu_trans.overviews.incomings.minValueTooltip : undefined,
5479 propUI: {
5480 getter: function() { return user_data.incomings.attackIdDescriptions[captured_index].minValue; },
5481 setter: function(value) { user_data.incomings.attackIdDescriptions[captured_index].minValue = value; },
5482 editor: "number"
5483 }
5484 };
5485
5486 properties['incomings_attackIdDesc'+captured_index+'_text'] = {
5487 label: sangu_trans.overviews.incomings.text,
5488 propUI: {
5489 getter: function() { return user_data.incomings.attackIdDescriptions[captured_index].text; },
5490 setter: function(value) { user_data.incomings.attackIdDescriptions[captured_index].text = value; },
5491 editor: "text"
5492 }
5493 };
5494 })();
5495 }
5496
5497 properties['incomings_attackIdDescMaxText'] = {
5498 label: sangu_trans.overviews.incomings.attackIdHigherDescription,
5499 propUI: {
5500 getter: function() { return user_data.incomings.attackIdHigherDescription; },
5501 setter: function(value) { user_data.incomings.attackIdHigherDescription = value; },
5502 editor: "text"
5503 }
5504 };
5505
5506 user_data_configs.push({
5507 id: "overviewsIncomings",
5508 title: sangu_trans.overviews.incomings.title,
5509 save: sangu_saver,
5510 properties: properties
5511 });
5512 }());
5513 }
5514
5515 if (showConfigs) {
5516 user_data_configs.push({
5517 id: "other",
5518 title: sangu_trans.other.title,
5519 save: sangu_saver,
5520 properties: {
5521 fancyImages: {
5522 label: sangu_trans.overviews.addFancyImagesToOverviewLinks,
5523 propUI: {
5524 getter: function() { return user_data.overviews.addFancyImagesToOverviewLinks; },
5525 setter: function(value) { user_data.overviews.addFancyImagesToOverviewLinks = value; },
5526 editor: "bool"
5527 }
5528 },
5529 proStyle: {
5530 tooltip: sangu_trans.other.proStyleTooltip,
5531 label: sangu_trans.other.proStyle,
5532 propUI: {
5533 getter: function() { return user_data.proStyle; },
5534 setter: function(value) { user_data.proStyle = value; },
5535 editor: "bool"
5536 }
5537 },
5538 calculateSnob: {
5539 label: sangu_trans.other.calculateSnob,
5540 show: !world_config.coins,
5541 propUI: {
5542 getter: function() { return user_data.other.calculateSnob; },
5543 setter: function(value) { user_data.other.calculateSnob = value; },
5544 editor: "bool"
5545 }
5546 },
5547 showPlayerProfileOnVillage: {
5548 label: sangu_trans.other.showPlayerProfileOnVillage,
5549 propUI: {
5550 getter: function() { return user_data.showPlayerProfileOnVillage; },
5551 setter: function(value) { user_data.showPlayerProfileOnVillage = value; },
5552 editor: "bool"
5553 }
5554 },
5555 overviewAjaxSeperateSupport: {
5556 label: sangu_trans.other.ajaxSeperateSupport,
5557 show: server_settings.ajaxAllowed,
5558 propUI: {
5559 getter: function() { return user_data.overview.ajaxSeperateSupport; },
5560 setter: function(value) { user_data.overview.ajaxSeperateSupport = value; },
5561 editor: "bool"
5562 }
5563 },
5564 canHideDiv: {
5565 label: sangu_trans.other.canHideDiv,
5566 propUI: {
5567 getter: function() { return user_data.overview.canHideDiv; },
5568 setter: function(value) { user_data.overview.canHideDiv = value; },
5569 editor: "bool"
5570 }
5571 },
5572 timeDisplayTitle: {
5573 type: "subtitle",
5574 label: sangu_trans.other.timeDisplayTitle
5575 },
5576 walkingTimeDisplay: {
5577 label: sangu_trans.other.walkingTimeDisplay,
5578 tooltip: sangu_trans.other.walkingTimeDisplayTooltip,
5579 propUI: {
5580 getter: function() { return user_data.walkingTimeDisplay; },
5581 setter: function(value) { user_data.walkingTimeDisplay = value; },
5582 editor: "text"
5583 }
5584 },
5585 displayDays: {
5586 label: sangu_trans.other.displayDays,
5587 tooltip: sangu_trans.other.displayDaysTooltip,
5588 propUI: {
5589 getter: function() { return user_data.displayDays; },
5590 setter: function(value) { user_data.displayDays = value; },
5591 editor: "bool"
5592 }
5593 },
5594 commandRenamerTitle: {
5595 type: "subtitle",
5596 label: sangu_trans.other.commandRenamer
5597 },
5598 commandRenamerActive: {
5599 label: sangu_trans.other.commandRenamerActive,
5600 propUI: {
5601 getter: function() { return user_data.attackAutoRename.active; },
5602 setter: function(value) { user_data.attackAutoRename.active = value; },
5603 editor: "bool"
5604 }
5605 },
5606 commandRenamerAddHaul: {
5607 label: sangu_trans.other.commandRenamerAddHaul,
5608 propUI: {
5609 getter: function() { return user_data.attackAutoRename.addHaul; },
5610 setter: function(value) { user_data.attackAutoRename.addHaul = value; },
5611 editor: "bool"
5612 }
5613 },
5614 farmLimitTitle: {
5615 type: "subtitle",
5616 label: sangu_trans.other.farmLimitTitle
5617 },
5618 farmLimitColors: {
5619 label: sangu_trans.other.farmLimitStackColors,
5620 propUI: {
5621 getter: function(propIndex) {
5622 return user_data.farmLimit.stackColors;
5623 },
5624 setter: function(value, propIndex) { user_data.farmLimit.stackColors = value; },
5625 editor: "array|addNew:color|delete"
5626 }
5627 },
5628 farmLimitAcceptableOverstack: {
5629 label: sangu_trans.other.farmLimitAcceptableOverstack,
5630 tooltip: sangu_trans.other.farmLimitAcceptableOverstackTooltip.replace("{farmlimit}", 30 * world_config.farmLimit),
5631 show: world_config.farmLimit,
5632 propUI: {
5633 getter: function() { return user_data.farmLimit.acceptableOverstack; },
5634 setter: function(value) { user_data.farmLimit.acceptableOverstack = value; },
5635 editor: "array|addNew:float|delete|step=0.01"
5636 }
5637 },
5638 farmLimitUnlimitedStack: {
5639 label: sangu_trans.other.farmLimitUnlimitedStack,
5640 show: !world_config.farmLimit,
5641 propUI: {
5642 getter: function() { return user_data.farmLimit.unlimitedStack; },
5643 setter: function(value) { user_data.farmLimit.unlimitedStack = value; },
5644 editor: "array|addNew:number|delete|step=1000"
5645 }
5646 }
5647 }
5648 });
5649 }
5650
5651
5652
5653
5654 if (showConfigs) {
5655 // Extra links on village info to troop overview
5656 (function() {
5657 var properties = {},
5658 i;
5659
5660 function addSetting(properties, index, offDef, propName, label, editor, tooltip) {
5661 properties['infoPage_extra_link'+index+'_'+offDef+propName] = {
5662 label: label,
5663 tooltip: tooltip,
5664 propUI: {
5665 getter: function() { return user_data.villageInfo4[index][offDef][propName]; },
5666 setter: function(value) { user_data.villageInfo4[index][offDef][propName] = value; },
5667 editor: editor
5668 }
5669 };
5670 }
5671
5672 // hehe
5673 function addSetting2(properties, index, offDef, propName, label, editor, tooltip) {
5674 properties['infoPage_extra_link'+index+'_'+offDef+propName] = {
5675 label: label,
5676 tooltip: tooltip,
5677 propUI: {
5678 getter: function() { return user_data.villageInfo4[index][offDef].filter[propName]; },
5679 setter: function(value) { user_data.villageInfo4[index][offDef].filter[propName] = value; },
5680 editor: editor
5681 }
5682 };
5683 }
5684
5685 function add2Links(captured_index, offDef) {
5686 addSetting(properties, captured_index, offDef+"_link", "name", sangu_trans.villageInfo.linkName, "text");
5687 addSetting(properties, captured_index, offDef+"_link", "icon", sangu_trans.villageInfo.icon, "text");
5688 addSetting(properties, captured_index, offDef+"_link", "sort", sangu_trans.villageInfo.sort, "bool");
5689 addSetting(properties, captured_index, offDef+"_link", "changeSpeed", sangu_trans.villageInfo.changeSpeed, "unit");
5690 addSetting(properties, captured_index, offDef+"_link", "group", sangu_trans.villageInfo.group, "number", sangu_trans.villageInfo.groupTitle);
5691
5692 properties['incomings_attackIdDesc'+captured_index+offDef+'_FilterTitle'] = {
5693 type: "subtitle",
5694 label: sangu_trans.villageInfo.filter.title
5695 };
5696
5697 addSetting2(properties, captured_index, offDef+"_link", "active", sangu_trans.villageInfo.filter.title, "bool");
5698 addSetting2(properties, captured_index, offDef+"_link", "unit", sangu_trans.villageInfo.filter.unit, "unit");
5699 addSetting2(properties, captured_index, offDef+"_link", "amount", sangu_trans.villageInfo.filter.amount, "number|step=100");
5700 }
5701
5702 for (i = 0; i < user_data.villageInfo4.length; i++) {
5703 (function() {
5704 var captured_index = i;
5705
5706 properties['incomings_attackIdDesc'+captured_index+'_title'] = {
5707 type: "subtitle",
5708 label: sangu_trans.villageInfo.title2 + " " + (captured_index + 1)
5709 };
5710
5711 properties['infoPage_extra_link'+captured_index+'_activate'] = {
5712 label: sangu_trans.global.resources.activate,
5713 propUI: {
5714 getter: function() { return user_data.villageInfo4[captured_index].active; },
5715 setter: function(value) { user_data.villageInfo4[captured_index].active = value; },
5716 editor: "bool"
5717 }
5718 };
5719
5720 properties['incomings_attackIdDesc'+captured_index+"off"+'_title'] = {
5721 type: "subtitle",
5722 label: sangu_trans.villageInfo.off_title
5723 };
5724 add2Links(captured_index, "off");
5725
5726 properties['incomings_attackIdDesc'+captured_index+"def"+'_title'] = {
5727 type: "subtitle",
5728 label: sangu_trans.villageInfo.def_title
5729 };
5730 add2Links(captured_index, "def");
5731
5732 })();
5733 }
5734
5735 user_data_configs.push({
5736 id: "villageInfoLinks",
5737 title: sangu_trans.villageInfo.title,
5738 save: sangu_saver,
5739 properties: properties
5740 });
5741 }());
5742 }
5743
5744 return user_data_configs;
5745 }());
5746 (function() {
5747 // contentPage is the place we will add the settings menu to
5748 var contentPage = $("table:first td:last", content_value).attr("width", "99%"),
5749 sanguTitle = "<h3 id='sanguConfigTitle'>" + trans.sp.sp.configuration.replace("{version}", sangu_version) + "</h3>";
5750
5751 function gimmeTheMoney() {
5752 function createButton(paypalCode, euroAmount, tooltip) {
5753 return '<div align="center">'
5754 + '<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">'
5755 + '<input type="hidden" name="cmd" value="_s-xclick">'
5756 + '<input type="hidden" name="hosted_button_id" value="' + paypalCode + '">'
5757 + '<input type="image" src="https://www.paypalobjects.com/nl_NL/BE/i/btn/btn_donate_SM.gif" border="0" name="submit" title="'+tooltip+'">'
5758 + '<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">'
5759 + '<br>' + trans.sp.sp.donate.buttonAmount.replace("{amount}", euroAmount)
5760 + '</form></div>';
5761 }
5762
5763 var html = "<h3>Contributors</h3>";
5764 html += "Hebben aan het Sangu Package meegewerkt: <br><b>";
5765 html += "De Goede Fee, Tjeerdo, cgrain, Hardcode93";
5766 html += "</b>";
5767
5768 html += "<h3>"+trans.sp.sp.donate.title+"</h3>";
5769 html += trans.sp.sp.donate.whyWouldI;
5770 html += "<br>" + trans.sp.sp.donate.books
5771 .replace("{abegin}", "<a target='_blank' href='http://www.amazon.com/wishlist/1RFQ21NSF4PAI/ref=cm_wl_prev_ret?_encoding=UTF8&reveal='>")
5772 .replace("{aend}", "</a>");
5773
5774 html += "<br><br>"
5775 + "<table width='100%'><tr>"
5776 + "<td>" + createButton("FA9MAMFAYKANL", 5, trans.sp.sp.donate.beer) + "</td>"
5777 + "<td>" + createButton("R9RX6XBCV6T4G", 10, trans.sp.sp.donate.food) + "</td>"
5778 + "<td>" + createButton("ELG8Y2GLSXAVA", 20, trans.sp.sp.donate.yaye) + "</td>"
5779 + "</tr>"
5780 + "</table>";
5781
5782 return html;
5783 }
5784
5785 // Reset sangu settings links
5786 var resetForm = "<a href='#' id='resetSettings'>» " + trans.sp.sp.settings.reset + "</a>";
5787 resetForm += "<br>";
5788 resetForm += "<a href='#' id='resetAllSettings'>» " + trans.sp.sp.settings.resetAll + "</a>";
5789
5790 // skeleton injection
5791 contentPage.html(sanguTitle + "<div id='sanguSettingsForm'>" + resetForm + gimmeTheMoney() + "</div>");
5792
5793 gimmeTheMoney();
5794 $("#sanguSettingsForm").append("<br><br>");
5795
5796 $("#resetSettings").click(function() {
5797 if (confirm(trans.sp.sp.settings.reset)) {
5798 pers.set('sangusettings', '');
5799 location.reload(false);
5800 }
5801 return false;
5802 });
5803
5804 $("#resetAllSettings").click(function() {
5805 if (confirm(trans.sp.sp.settings.resetAll)) {
5806 pers.clear();
5807 location.reload(false);
5808 }
5809 return false;
5810 });
5811
5812 (function() {
5813 var sanguSettingsForm,
5814 configIterator,
5815 settingFormTogglerHtml,
5816 settingsFormsOpenFromPersistence,
5817 adornButton = function(button) { $(button).css("background-color", user_data.colors.error); };
5818
5819 sanguSettingsForm = $("#sanguSettingsForm");
5820
5821 settingFormTogglerHtml = "<h3>" + trans.sp.sp.settings.configuration + "</h3>";
5822 settingFormTogglerHtml +=
5823 "<table class='vis' width='100%'><tr class='row_a'><th>"
5824 + trans.sp.sp.settings.configurationFormTogglerTooltip
5825 + "</th></tr><tr class='row_b'><td>";
5826 for (configIterator = 0; configIterator < user_data_configs.length; configIterator++) {
5827 settingFormTogglerHtml +=
5828 "<input type='button' value=\""
5829 + user_data_configs[configIterator].title
5830 + "\" id='"+user_data_configs[configIterator].id
5831 + "_button' class='editFormToggler' /> ";
5832 }
5833 settingFormTogglerHtml += "</td></tr></table><br>";
5834 sanguSettingsForm.append(settingFormTogglerHtml);
5835 $(".editFormToggler", sanguSettingsForm).click(function() {
5836 var openForms = "",
5837 linkedDiv = $("#" + this.id.replace("_button", ""));
5838
5839 if (linkedDiv.is(":visible")) {
5840 linkedDiv.hide();
5841 $(this).css("background-color", "");
5842 } else {
5843 linkedDiv.fadeIn();
5844 adornButton(this);
5845 }
5846
5847 $(".propertyEditFormContainer", sanguSettingsForm).each(function() {
5848 if ($(this).is(":visible")) {
5849 openForms += this.id + "|";
5850 }
5851 });
5852 pers.set("settingsFormsOpen", openForms);
5853 });
5854
5855 // build the property handler editting form
5856 for (configIterator = 0; configIterator < user_data_configs.length; configIterator++) {
5857 buildConfigForm(sanguSettingsForm, user_data_configs[configIterator]);
5858 }
5859
5860 settingsFormsOpenFromPersistence = pers.get("settingsFormsOpen");
5861 $(".propertyEditFormContainer", sanguSettingsForm).each(function() {
5862 if (settingsFormsOpenFromPersistence.indexOf(this.id+"|") > -1) {
5863 adornButton($("#" + this.id + "_button"));
5864 $(this).show();
5865 }
5866 });
5867
5868 $('input[id*="mainTagger_otherButtonHitKey"]').on('keydown', function(e){
5869 e.preventDefault();
5870 e.stopPropagation();
5871 var TagNumber = $(this).attr("id").match(/\d+/);
5872 $(this).val('');
5873 $(this).val(keyCodeMap[e.which].toUpperCase());
5874 user_data.mainTagger2.otherDescs[TagNumber]["hitKey"] = $(this).val();
5875 pers.set('sangusettings', JSON.stringify(user_data));
5876 trackEvent("ScriptUsage", "SettingEdit", "1");
5877 })
5878
5879 })();
5880
5881 // notable contributors
5882 (function() {
5883 var notableHtml = "<u>" + trans.sp.sp.donate.notable + "</u>";
5884 notableHtml += "<br><br><b>sakeb</b>: Nogmaals bedankt voor 'JavaScript: The Good Parts'! :)";
5885 notableHtml += "<br><b>Daniel Ivanov</b>";
5886 notableHtml += "<br><b>Pascal Gorel</b><br>";
5887
5888 $("#sanguSettingsForm").append(notableHtml);
5889 })();
5890 })();
5891 }
5892 break;
5893
5894 case "place":
5895 /**
5896 * {spVillage} The current village
5897 */
5898 var vilHome = getVillageFromCoords(game_data.village.coord);
5899 if ($("#attack_name").size() > 0) {
5900 // RALLYPOINT CONFIRM
5901 (function() {
5902 //console.time("confirm");
5903 try {
5904 // reorder the page
5905 if (user_data.proStyle) {
5906 $("table:first", content_value).css("width", 500);
5907
5908 // Merge nightbonus & tribe claim statements (for OK button placement)
5909 if (user_data.proStyle && (user_data.confirm.replaceTribeClaim || user_data.confirm.replaceNightBonus)) {
5910 var header = $("h2:first", content_value);
5911 var claim = $("h3.error:visible");
5912 if (claim.size() != 0) {
5913 claim.each(function() {
5914 var $this = $(this);
5915 $this.hide();
5916 header.addClass("error").text(header.text() + " - " + $this.text());
5917 });
5918 }
5919 }
5920 }
5921
5922 // extra attack button (always on the same place)
5923 if (user_data.confirm.addExtraOkButton) {
5924 $("h2:first", content_value).prepend("<input type=submit style='font-size: 10pt' id=focusPlaceHolder value='" + $("#troop_confirm_go").val() + "'><br>");
5925 $("#focusPlaceHolder").click(function () {
5926 $(this).attr("disabled", "disabled");
5927 $("#troop_confirm_go").click();
5928 });
5929 }
5930
5931 // Catapult building images
5932 if (user_data.confirm.addCatapultImages && $("#save_default_attack_building").length == 1) {
5933 var dropdown = $("select[name='building']");
5934 var buildingImages = "";
5935
5936 dropdown.find("option").each(function(index, value) {
5937 buildingImages += "<img class='catapultSwitcher' title='" + trans.sp.command.catapultImageTitle + "' building='" + $(value).val() +"' src='https://www.tribalwars.vodka/graphic/buildings/" + $(value).val() + ".png'> ";
5938 });
5939
5940 dropdown.parent().parent().before("<tr><td colspan=4>"+buildingImages+"</td></tr>");
5941 $("img.catapultSwitcher").click(function() {
5942 dropdown.val($(this).attr("building"));
5943 });
5944 }
5945
5946 var valueCells = $("table.vis:first td:odd", content_value);
5947 var targetVillage = valueCells.first().text();
5948
5949 // remember last attack
5950 // saved at the confirmation page so that we can't save
5951 // invalid coordinates
5952 var village = getVillageFromCoords(targetVillage);
5953 if (village.isValid) {
5954 pers.set("lastVil", village.coord);
5955 }
5956
5957 var isAttack = $("input[name='attack']").val() == "true";
5958 var isBarbarian = valueCells.eq(1).has("a").length === 0;
5959 var player = (isBarbarian ? '' : valueCells.eq(1).text());
5960
5961 var unitsSent = {};
5962 $.each(world_data.units, function (i, val) {
5963 unitsSent[val] = parseInt($("input[name='" + val + "']", content_value).val(), 10);
5964 });
5965
5966 // compare runtime with dodgetime
5967 var unitsCalc = calcTroops(unitsSent);
5968 var dodgeCookie = pers.getCookie("sanguDodge" + getQueryStringParam("village"));
5969 if (dodgeCookie) {
5970 dodgeCookie = dodgeCookie.split("~");
5971 var durationCell = $("table.vis:first td:contains('" + trans.tw.command.walkingTimeTitle + "')", content_value).next();
5972 var attackRunTime = getTimeFromTW(durationCell.text());
5973 var dodgeTime = getTimeFromTW(dodgeCookie[1]);
5974
5975 var runtimeIsOk = attackRunTime.totalSecs >= dodgeTime.totalSecs;
5976 var diffSecs = (attackRunTime.totalSecs - dodgeTime.totalSecs);
5977
5978 var dodgeCellText = "<table border=0 cellpadding=0 cellspacing=0 width='1%'><tr>";
5979 dodgeCellText += "<td width='25%' align=center>" + durationCell.text() + "</td>";
5980 dodgeCellText += "<td width='50%' align=center><b>" + (runtimeIsOk ? ">>>" : "<<<") + "</b></td>";
5981 dodgeCellText += "<td width='25%' align=center nowrap>" + dodgeCookie[1] + " ";
5982 if (diffSecs > 0) {
5983 dodgeCellText += trans.sp.command.dodgeMinuteReturn.replace("{minutes}", prettyDate(diffSecs * 2000, true)); // 2000 = Method expects milliseconds and distance is walked 2 times!
5984 }
5985 dodgeCellText += "</td>";
5986
5987 dodgeCellText += "</tr></table>";
5988 durationCell.html(dodgeCellText);
5989
5990 if (!runtimeIsOk) {
5991 durationCell.find("table").attr("title", trans.sp.command.dodgeNotFarEnough).css("background-color", user_data.colors.error).find("td").css("background-color", user_data.colors.error);
5992 }
5993
5994 if (dodgeCookie[0] != "unit_" + unitsCalc.getSlowest()) {
5995 $("h2:first", content_value).css("background-color", user_data.colors.error);
5996 }
5997 } else {
5998 // If a dodgecookie is in use, nightbonus etc isn't relevant
5999 unitsCalc.colorIfNotRightAttackType($("h2:first", content_value), isAttack);
6000 var arrivalTime = getDateFromTodayTomorrowTW($.trim($("#date_arrival").text()));
6001 if (user_data.proStyle && user_data.confirm.replaceNightBonus && isDateInNightBonus(arrivalTime)) {
6002 $("#date_arrival").css("background-color", user_data.colors.error).css("font-weight", "bold");
6003 }
6004 }
6005
6006 if (user_data.attackAutoRename.active) {
6007 // rename attack command
6008 // cookie reading code in place.js
6009 var villageCoord = $("input[name='x']", content_value).val() + '|' + $("input[name='y']", content_value).val();
6010 var sent = buildAttackString(villageCoord, unitsSent, player, !isAttack);
6011 document.title = game_data.village.coord + " -> " + sent;
6012
6013 var twInitialCommandName = (isAttack ? trans.tw.command.attackOn : trans.tw.command.supportFor) + targetVillage;
6014 pers.setSession("attRen_" + game_data.village.id + '_' + twInitialCommandName, sent);
6015 }
6016 } catch (e) { handleException(e, "place-confirm"); }
6017 //console.timeEnd("confirm");
6018 }());
6019 }
6020 // RALLYPOINT UNITS THERE
6021 else if (current_page.mode === 'units' && location.href.indexOf('try=back') == -1) {
6022 (function() {
6023 //console.time("units_back");
6024 try {
6025 var units_awayTable = $("#units_away").width("100%");
6026 if (units_awayTable.size() != 0) {
6027 // Troops in other villages
6028 $("tr:first", units_awayTable).append(
6029 "<th>" + trans.sp.place.distance + "</th>"
6030 + "<th>" + trans.sp.place.backOn + "</th>");
6031
6032 units_awayTable.find("tr:gt(0):even").each(function() {
6033 var row = $(this),
6034 villageCoord = getVillageFromCoords(row.find("td:eq(1)").text());
6035
6036 if (!villageCoord.isValid) {
6037 row.append("<th> </th><th> </th>");
6038 } else {
6039 var slowestUnit = null;
6040 var slowestUnitName = null;
6041 $.each(world_data.units, function (i, val) {
6042 var amount = $("td:eq(" + (i + 2) + "), th:eq(" + (i + 1) + ")", row).text();
6043 if (amount != '0') {
6044 if (slowestUnit == null || slowestUnit < world_data.unitsSpeed['unit_' + val]) {
6045 slowestUnitName = val;
6046 slowestUnit = world_data.unitsSpeed['unit_' + val];
6047 }
6048 }
6049 });
6050
6051 var fields = getDistance(vilHome.x, villageCoord.x, vilHome.y, villageCoord.y, slowestUnitName);
6052 var extraColumns = "<td align=right>" + parseInt(fields.fields, 10) + "</td>";
6053 extraColumns += "<td>" + twDateFormat(fields.arrivalTime) + "</td>";
6054
6055 row.append(extraColumns);
6056 }
6057 });
6058 }
6059
6060 // Calculate distance and walkingtime to the villages
6061 var unitsTable = $("form table:first");
6062 $("tr:first", unitsTable).append('<th width="50"><span class="icon header population" title="' + trans.sp.all.population + '"></span></th><th>' + trans.sp.place.distance + '</th><th>' + trans.sp.place.backOn + '</th>');
6063 unitsTable.find("tr:gt(0)").each(function () {
6064 var pop = 0;
6065 var row = $(this);
6066 var slowestUnit = null;
6067 var slowestUnitName = null;
6068
6069 $.each(world_data.units, function (i, val) {
6070 var amount = parseInt($("td:eq(" + (i + 1) + "), th:eq(" + (i + 1) + ")", row).text(), 10);
6071 if (amount !== 0) {
6072 pop += amount * world_data.unitsPositionSize[i];
6073
6074 if (slowestUnit == null || slowestUnit < world_data.unitsSpeed['unit_' + val]) {
6075 slowestUnitName = val;
6076 slowestUnit = world_data.unitsSpeed['unit_' + val];
6077 }
6078 }
6079 });
6080
6081 var villageCoord = getVillageFromCoords(row.find("td:first").text());
6082 var color = getStackColor(pop);
6083
6084 if (color !== "") {
6085 $(this).append("<td align=right style='background-color: " + color + "'>" + formatNumber(pop) + "</td><td colspan=2> </td>");
6086 } else {
6087 var extraColumns = '<td align=right>' + formatNumber(pop) + '</td>';
6088 if (!villageCoord.isValid) {
6089 extraColumns += "<td colspan=2 align=right> </td>";
6090 } else {
6091 //q(vilHome.x + ':' + slowestUnitName);
6092 var dist = getDistance(vilHome.x, villageCoord.x, vilHome.y, villageCoord.y, slowestUnitName),
6093 fields = parseInt(dist.fields, 10);
6094
6095 extraColumns += "<td align=right>" + fields + "</td><td>" + twDateFormat(dist.arrivalTime) + "</td>";
6096 $("td:first", this).append(" <b>" + trans.sp.all.fieldsSuffix.replace("{0}", fields) + "</b>");
6097 $(this).addClass("toSort").attr("fields", fields);
6098 }
6099 $(this).append(extraColumns);
6100 }
6101 });
6102
6103 var checkboxAmount = $("input[type='checkbox']", unitsTable);
6104 if (checkboxAmount.size() == 1) {
6105 // village has just been taken over? auto check checkbox
6106 checkboxAmount.attr("checked", true);
6107 }
6108
6109 // Sort on distance
6110 unitsTable.find("tr.toSort").sortElements(function (a, b) {
6111 return parseInt($(a).attr("fields"), 10) < parseInt($(b).attr("fields"), 10) ? 1 : -1;
6112 });
6113
6114 // are there incomings on the supporting villages?
6115 if (server_settings.ajaxAllowed) {
6116 unitsTable.find("tr.toSort").each(function() {
6117 var row = $(this);
6118 var villageUrl = $("a:first", this).attr("href");
6119 ajax(villageUrl, function (villageDetails) {
6120 var villageOwner = $("table.vis:first tr:eq(4) a", villageDetails);
6121 if (villageOwner.text() != game_data.player.name) {
6122 $("td:first a", row).after(" [" + villageOwner.outerHTML() + "]");
6123 } else {
6124 var incomingTable = $("table th:contains('" + trans.tw.overview.incomingTroops + "')", villageDetails);
6125 if (incomingTable.size() > 0) {
6126 incomingTable = incomingTable.parent().parent();
6127 var incomingRows = $("tr:has(img[src*='attack'])", incomingTable);
6128 if (incomingRows.size() > 0) {
6129 var firstAttack = incomingRows.eq(0);
6130 var timeLeft = $("td:eq(2)", firstAttack).text();
6131 var arrivalDate = $("td:eq(1)", firstAttack).text();
6132
6133 var lastAttack = incomingRows.last();
6134 var timeLeftLast = $("td:eq(2)", lastAttack).text();
6135 var arrivalDateLast = $("td:eq(1)", lastAttack).text();
6136
6137 var amount = incomingRows.size();
6138
6139 var attacksDesc;
6140 if (amount == 1) {
6141 attacksDesc = trans.sp.place.onlyAttack
6142 .replace("{timeLeftFirst}", timeLeft)
6143 .replace("{arrivalDateFirst}", arrivalDate);
6144 } else {
6145 attacksDesc = trans.sp.place.multipleAttack
6146 .replace("{timeLeftFirst}", timeLeft)
6147 .replace("{arrivalDateFirst}", arrivalDate)
6148 .replace("{timeLeftLast}", timeLeftLast)
6149 .replace("{arrivalDateLast}", arrivalDateLast)
6150 .replace("{amount}", amount);
6151 }
6152
6153 $("td:first input", row).after(" <img src='graphic/command/attack.png' title='" + attacksDesc + "'>");
6154 }
6155 }
6156 }
6157 });
6158 });
6159 }
6160 } catch (e) { handleException(e, "place-units_back"); }
6161 //console.timeEnd("units_back");
6162 }());
6163 }
6164 // RALLY POINT (DEFAULT)
6165 else {
6166 (function() {
6167 //console.time("place-place");
6168 try {
6169 // Auto rename attacks
6170 if (user_data.attackAutoRename.active) {
6171 // Less than ideal solution:
6172 // Does not work properly when sending many attacks (ie snobtrain)
6173 // In confirm.js the cookies are saved
6174
6175 var hasAttackRenamingCookieNeedle = pers.getWorldKey('attRen_' + game_data.village.id + '_');
6176 for (var i = 0; i < sessionStorage.length; i++) {
6177 var key = sessionStorage.key(i);
6178 if (key.indexOf(hasAttackRenamingCookieNeedle) == 0) {
6179 var twInitialCommandName = key.substr(hasAttackRenamingCookieNeedle.length);
6180 //q("found:" + hasAttackRenamingCookieNeedle + " -> " + twInitialCommandName);
6181
6182 // ' is an invalid village name character so we don't need to escape
6183 var commandLabel = $('.quickedit-label:contains("' + twInitialCommandName + '")');
6184 if (commandLabel.length > 0 && server_settings.ajaxAllowed) {
6185 var sanguCommandName = sessionStorage.getItem(key);
6186
6187 // Open the rename command form:
6188 commandLabel.parent().next().click();
6189
6190 // Fill in new command name and click rename button
6191 var commandWrapper = commandLabel.parent().parent().parent(),
6192 commandForm = commandWrapper.find(".quickedit-edit");
6193
6194 commandForm.find("input:first").val(sanguCommandName);
6195 commandForm.find("input:last").click();
6196
6197 pers.removeSessionItem(key);
6198
6199 if (commandLabel.closest("table").find("tr").length > 2) {
6200 commandLabel.closest("td").addClass("selected");
6201 }
6202 }
6203 }
6204 }
6205 }
6206
6207 $("#inputx,#inputy").focus(function() {
6208 $(this).select();
6209 });
6210
6211 // fill in coordinates? (links from troops overview page)
6212 if (server_settings.autoFillCoordinatesAllowed && window.location.search.indexOf("&sanguX=") != -1) {
6213 var match = window.location.search.match(/sanguX=(\d+)&sanguY=(\d+)/);
6214 if (typeof match[1] !== "undefined") {
6215 $("#inputx").val(match[1]);
6216 $("#inputy").val(match[2]);
6217 }
6218 }
6219
6220 // Spice up rally point:
6221 var speedCookie = spSpeedCookie();
6222
6223(function() {
6224 try {
6225
6226 // Show current selected speed + ability to change active speed
6227 $(".unit_link img", content_value).each(function() {
6228 $(this).attr("title", trans.sp.place.changeSpeedImageTooltips.replace("{originalTitle}", $(this).attr("title")));
6229 });
6230
6231 $("#command-data-form a img").click(function () {
6232 var unit = this.src;
6233 unit = unit.substr(unit.lastIndexOf('/') + 1);
6234 unit = unit.substr(0, unit.lastIndexOf('.'));
6235 speedCookie = spSpeedCookie(unit);
6236 $("#command-data-form a img").css("border", "0px").filter("img[src*='" + unit + "']").css("border", "3px red solid");
6237
6238 // lastvil
6239 var coord = getVillageFromCoords(pers.get("lastVil"));
6240 if (coord.isValid) {
6241 var dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, speedCookie);
6242 $("#lastVilTime")[0].innerHTML = dist.html;
6243 }
6244
6245 // targetVillage
6246 coord = getVillageFromCoords(spTargetVillageCookie());
6247 if (coord.isValid) {
6248 dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, speedCookie);
6249 $("#targetVilTime")[0].innerHTML = dist.html;
6250 }
6251
6252 }).filter("img[src*='" + speedCookie + "']").css("border", "3px red solid");
6253
6254 } catch (e) { handleException(e, "place-activespeed"); }
6255}());
6256(function() {
6257 try {
6258 // sangupackage last village
6259 var cookie = pers.get("lastVil"),
6260 coord = getVillageFromCoords(cookie),
6261 dist;
6262
6263 if (coord.isValid) {
6264 dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, speedCookie);
6265 var htmlStr = printCoord(coord, "» " + trans.sp.all.last + ": " + coord.x + "|" + coord.y);
6266 htmlStr += " <span id=lastVilTime>" + dist.html + "</span>";
6267 $("#command-data-form").append(htmlStr);
6268 }
6269
6270 // Add target village
6271 var targetVillage = getVillageFromCoords(spTargetVillageCookie());
6272 if (targetVillage.isValid) {
6273 dist = getDistance(targetVillage.x, vilHome.x, targetVillage.y, vilHome.y, speedCookie);
6274 $("#command-data-form").append("<br>" + printCoord(targetVillage, "» " + trans.sp.all.target + ": " + targetVillage.x + "|" + targetVillage.y) + " <span id=targetVilTime>" + dist.html + "</span>");
6275 }
6276 } catch (e) { handleException(e, "place-lastandtargetvillage"); }
6277}());
6278(function() {
6279 try {
6280 // Read troops available
6281 var units = [];
6282 units.total = 0;
6283 $("#command-data-form .unitsInput").each(function () {
6284 var amount = $(this).next().text().substr(1);
6285 units[this.name] = parseInt(amount.replace(")", ""), 10);
6286 units.total += units[this.name] * world_data.unitsSize['unit_'+this.name];
6287 });
6288
6289 // Add extra links next to "All troops"
6290 function createRallyPointScript(linksContainer, unitLoop, name, min, checkFunction, tag) {
6291 send = {};
6292 $.each(unitLoop, function (i, v) {
6293 if (units[v] >= min) {
6294 send[v] = checkFunction(units[v], v, tag);
6295 }
6296 });
6297 linksContainer.append(" <a href='#' onclick='" + fillRallyPoint(send) + "; return false'>" + name + "</a>");
6298 }
6299
6300 var villageType = calcTroops(units);
6301 var linksContainer = $('#selectAllUnits').parent().attr("colspan", 4);
6302
6303 // add fake attack
6304 var minFake = 0;
6305 if (world_config.hasMinFakeLimit) {
6306 minFake = getBuildingPoints();
6307 minFake *= world_config.minFake;
6308 if (units.ram > 0) {
6309 minFake -= world_data.unitsSize['unit_ram'];
6310 }
6311 }
6312
6313 if (user_data.place.attackLinks.fakePlaceLink && units['total'] >= minFake) {
6314 createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.fakePlaceLinkName, 0, function (amount, v, tag) {
6315 if ((v == 'ram' || v == 'catapult') && !tag.rammed && amount > 0) {
6316 tag.rammed = true;
6317 return 1;
6318 }
6319
6320 if (v == 'snob' || tag.toSend <= 0 || amount == 0) {
6321 return 0;
6322 }
6323
6324 if (user_data.place.attackLinks.fakePlaceExcludeTroops.indexOf(v) > -1) {
6325 return 0;
6326 }
6327
6328 var farmSize = world_data.unitsSize['unit_' + v];
6329 if (amount * farmSize > tag.toSend) {
6330 amount = Math.ceil(tag.toSend / farmSize);
6331 }
6332 tag.toSend -= amount * farmSize;
6333 if (v == 'sword' && amount > 0) {
6334 tag.toSend++;
6335 amount--;
6336 }
6337
6338 return amount;
6339 }, { toSend: minFake, rammed: false });
6340 }
6341
6342 if (units['total'] > 0)
6343 $.each(user_data.place.customPlaceLinks, function (i, v) {
6344 if (v.active && villageType.isMatch(v.type)) {
6345 // villageType: off, def, all
6346 if (v.required == undefined || units[v.required[0]] >= v.required[1]) {
6347 // requires certain amount of troops
6348 if (v.totalPop == undefined) {
6349 // work with absolute numbers
6350 createRallyPointScript(linksContainer, world_data.units, v.name, 0, function (amount, unitVal, tag) {
6351 //q(v + ' - SEND:' + tag[v] + '; amount=' + amount + ';');
6352 var send = tag[unitVal];
6353 if (send != undefined && amount > 0) {
6354 //q("send: " + send + " // amount: " + amount + " // unitVal: " + unitVal);
6355 if (send < 0) {
6356 send = amount + send;
6357 if (send < 0) {
6358 send = 1;
6359 }
6360 }
6361 if ((amount - send) * world_data.unitsSize['unit_' + unitVal] < tag.sendAlong) {
6362 send = amount;
6363 }
6364 if (send > 0 && !tag.ignoreNobles) {
6365 $.each(user_data.place.attackLinks.nobleSupport, function (i, val) {
6366 if (unitVal == val.unit && villageType.isMatch(val.villageType)) {
6367 send -= Math.ceil(units.snob * val.amount);
6368 }
6369 });
6370 }
6371 //if (unitVal == 'light') q(send);
6372
6373 if (send > amount) {
6374 return amount;
6375 }
6376 if (send > 0) {
6377 return send;
6378 }
6379 }
6380 return 0;
6381 }, v);
6382
6383 } else { // do automatic calculation which division of troops to select
6384 ////{ active: true, type: 'def', name: 'HelftZc', totalPop: 10000, divideOver: ['spear', 'heavy'] },
6385 // TODO this doesn't yet work, does it?
6386 // Probably not active...
6387 var totalPop = 0;
6388 $.each(v.divideOver, function (i, val) { totalPop += units[val] * world_data.unitsSize['unit_' + val]; });
6389
6390 createRallyPointScript(linksContainer, world_data.units, v.name, 0, function (amount, unitVal, tag) {
6391 if ($.inArray(unitVal, tag.divideOver) == -1) {
6392 return 0;
6393 }
6394 if (totalPop < tag.totalPop) {
6395 return amount;
6396 }
6397
6398 var currentUnitPercentage = (amount * world_data.unitsSize['unit_' + unitVal]) / totalPop;
6399 return Math.floor(amount * currentUnitPercentage);
6400 }, v);
6401 }
6402 }
6403 }
6404 });
6405
6406 if (units.spy >= user_data.place.attackLinks.scoutVillage && user_data.place.attackLinks.scoutPlaceLinks != null && user_data.place.attackLinks.scoutPlaceLinks.length > 0) {
6407 $.each(user_data.place.attackLinks.scoutPlaceLinks, function (i, v) {
6408 if (units.spy >= v) {
6409 createRallyPointScript(linksContainer, ["spy"], user_data.place.attackLinks.scoutPlaceLinksName.replace("{amount}", v), 0, function (amount, v, tag) {
6410 return tag;
6411 }, v);
6412 }
6413 });
6414 }
6415
6416 if (units.snob > 0 && user_data.place.attackLinks.noblePlaceLink) {
6417 if (user_data.place.attackLinks.noblePlaceLinkFirstName) {
6418 createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.noblePlaceLinkFirstName, 0, function (amount, v, tag) {
6419 if (v == 'snob') {
6420 return 1;
6421 }
6422 if (tag > 0) {
6423 var returned = null;
6424 $.each(user_data.place.attackLinks.nobleSupport, function (i, val) {
6425 if (v == val.unit && villageType.isMatch(val.villageType)) {
6426 returned = amount - Math.ceil((tag - 1) * val.amount);
6427 }
6428 });
6429 if (returned != null) {
6430 return returned;
6431 }
6432 }
6433 return amount;
6434 }, units.snob);
6435 }
6436
6437 if (user_data.place.attackLinks.noblePlaceLinkSupportName && (units.snob > 1 || user_data.place.attackLinks.noblePlaceLinksForceShow)) {
6438 createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.noblePlaceLinkSupportName, 0, function (amount, v, tag) {
6439 if (v == 'snob') {
6440 return 1;
6441 }
6442 var returned = 0;
6443 $.each(user_data.place.attackLinks.nobleSupport, function (i, val) {
6444 if (v == val.unit && villageType.isMatch(val.villageType)) {
6445 returned = Math.ceil(1 * val.amount);
6446 }
6447 });
6448 return returned;
6449 });
6450 }
6451
6452 if (units.snob > 0 && user_data.place.attackLinks.noblePlaceLinkDivideName) {
6453 createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.noblePlaceLinkDivideName, 0, function (amount, v, tag) {
6454 if (v == 'snob') {
6455 return 1;
6456 }
6457 if (v == 'catapult') {
6458 return 0;
6459 }
6460 if (v == 'ram' && !user_data.place.attackLinks.noblePlaceLinkDivideAddRam) {
6461 return 0;
6462 }
6463 return Math.floor(amount / units.snob);
6464 });
6465 }
6466 }
6467 } catch (e) { handleException(e, "place-extratrooplinks"); }
6468}());
6469
6470 } catch (e) { handleException(e, "place-place"); }
6471 //console.timeEnd("place-place");
6472 }());
6473 }
6474 break;
6475
6476 case "overview_villages":
6477 break;
6478 }
6479
6480 // USERPROFIEL++ // INFO_ ALLY/PLAYER
6481 if ((current_page.screen === 'info_ally' || current_page.screen === 'info_player' || current_page.screen === 'info_village')
6482 || (current_page.screen === "ally" && current_page.mode === "profile")) {
6483
6484 (function() {
6485 try {
6486 var tables = $('table.vis', content_value),
6487 villageInfoTable = tables.first(),
6488 commandsTable = villageInfoTable.next('table'),
6489 profile = user_data.profile,
6490 i;
6491
6492 if (game_data.features.Premium.active && location.href.indexOf('screen=info_village') > -1) {
6493 // extra links on the village overview page
6494 var createFilterLink = function(baseLink, settings) {
6495 var link = baseLink + "&group=" + settings.group + "&sort=" + settings.sort + "&changeSpeed=" + settings.changeSpeed;
6496
6497 if (settings.filter.active) {
6498 link += "&unit=" + settings.filter.unit + "&amount=" + settings.filter.amount;
6499 }
6500
6501 var fancyIcon = settings.icon ? "<img src='" + settings.icon + "'>" : "";
6502 return "<a href='" + link + "'>" + fancyIcon + settings.name + "</a>";
6503 };
6504
6505 for (i = 0; i < user_data.villageInfo4.length; i++) {
6506 var currentPairInfo = user_data.villageInfo4[i];
6507 if (currentPairInfo.active) {
6508 var id = villageInfoTable.find("td:eq(2)").text(),
6509 link = getUrlString(
6510 "&screen=overview_villages&type=own_home&mode=units&page=-1&targetvillage="
6511 + id.substr(id.lastIndexOf("=") + 1));
6512
6513 commandsTable.find("tbody:first").append(
6514 "<tr><td>" + createFilterLink(link, currentPairInfo.off_link) + "</td>"
6515 + "<td>" + createFilterLink(link, currentPairInfo.def_link) + "</td><tr>");
6516 }
6517 }
6518 }
6519
6520 if (user_data.profile.show && (location.href.indexOf('screen=info_village') == -1 || user_data.showPlayerProfileOnVillage)) {
6521 var screen;
6522 var mapProfile = user_data.profile.mapLink;
6523 var isVillage = false;
6524 if (current_page.screen !== 'info_ally' && current_page.screen !== "ally") {
6525 // player and village info page
6526 // Extra links and info in table at the left top
6527 screen = "player";
6528 if (user_data.proStyle) {
6529 $("td:first", content_value).closest('table').hasClass('modemenu')
6530 ? $(content_value).find('table:has("#villages_list") td:first').css("width", "40%").next().css("width", "60%")
6531 : $("td:first", content_value).css("width", "40%").next().css("width", "60%");
6532 }
6533
6534 if (current_page.screen === 'info_player') {
6535 // player info page
6536 id = commandsTable.find("a[href*='screen=mail']").attr("href");
6537
6538 if (id == undefined) {
6539 id = game_data.player.id;
6540 } else {
6541 id = id.substr(id.indexOf("&player=") + 8);
6542 //alert(id);
6543 if (id.indexOf("&") > -1) {
6544 id = id.substr(0, id.indexOf("&"));
6545 }
6546 }
6547 } else {
6548 // village info page
6549 isVillage = true;
6550 commandsTable = $("table.vis:first", content_value);
6551 id = commandsTable.find("tr:eq(3) a");
6552 //assert(id.size() == 1, "player id not found on info_village page");
6553 if (id.size() > 0) {
6554 id = id.attr("href").match(/id=(\d+)/)[1];
6555 assert(!!id, "player id href is not set");
6556 } else {
6557 id = 0;
6558 }
6559 }
6560
6561 // Direct link to TW Stats map
6562 if (id > 0 && profile.mapLink.show) {
6563 var link = "https://" + game_data.market + ".twstats.com/" + game_data.world + "/index.php?page=map";
6564 var tribeId = commandsTable.prev('table').find("td:eq(8) a");
6565 //assert(tribeId.size() == 1, "tribe id not found"); // Not everyone is in a tribe
6566 if (tribeId.size() == 1) {
6567 tribeId = tribeId.attr("href").match(/id=(\d+)/)[1];
6568 assert(!isNaN(tribeId), "tribe id is not a number");
6569 } else tribeId = 0;
6570
6571 if (mapProfile.tribeColor != null) {
6572 link += "&tribe_0_id=" + tribeId + "&tribe_0_colour=" + mapProfile.tribeColor.substr(1);
6573 }
6574 if (mapProfile.yourTribeColor != null && game_data.player.ally_id != tribeId && game_data.player.ally_id > 0) {
6575 link += "&tribe_1_id=" + game_data.player.ally_id + "&tribe_1_colour=" + mapProfile.yourTribeColor.substr(1);
6576 }
6577 link += "&player_0_id=" + id + "&player_0_colour=" + mapProfile.playerColor.substr(1);
6578 link += "&grid=" + (mapProfile.grid ? 1 : 0) + "&fill=" + mapProfile.fill.substr(1) + "&zoom=" + mapProfile.zoom + "¢rex=" + mapProfile.centreX + "¢rey=" + mapProfile.centreY;
6579 if (mapProfile.markedOnly) {
6580 link += "&nocache=1";
6581 }
6582 if (mapProfile.bigMarkers) {
6583 link += "&bm=1";
6584 }
6585 if (mapProfile.gridContinentNumbers) {
6586 link += "&kn=1";
6587 }
6588 if (mapProfile.ownColor != null && game_data.player.id != id) {
6589 link += "&player_1_id=" + game_data.player.id + "&player_1_colour=" + mapProfile.ownColor.substr(1);
6590 }
6591 commandsTable.find("tr:last").after("<tr><td colspan=2><a href='" + link + "' target='_blank'>» " + trans.sp.profile.twStatsMap + "</a> " + trans.sp.profile.externalPage + "</td></tr>");
6592 }
6593
6594 if (!isVillage) {
6595 // Amount of villages
6596 if (user_data.proStyle) {
6597 // always show villagename on one line
6598 var colWidth = $("table:eq(2) th", content_value);
6599 colWidth.first().css("width", "98%");
6600 colWidth.eq(1).css("width", "1%");
6601 colWidth.eq(2).css("width", "1%");
6602 }
6603
6604 var amountOfVillages = tables.eq(2).find("th:first").text();
6605 amountOfVillages = amountOfVillages.substr(amountOfVillages.indexOf("(") + 1);
6606 amountOfVillages = amountOfVillages.substr(0, amountOfVillages.length - 1);
6607 commandsTable.prev('table').find("tr:eq(2)").after("<tr><td>" + trans.sp.profile.villages + "</td><td>" + formatNumber(amountOfVillages) + "</td></tr>");
6608 }
6609 } else {
6610 screen = "tribe";
6611 if (current_page.screen === 'info_ally') {
6612 commandsTable = tables.eq(0);
6613 }
6614 id = location.href.match(/&id=(\d+)/)[1];
6615
6616 var link = "https://" + game_data.market + ".twstats.com/" + game_data.world + "/index.php?page=map";
6617 link += "&tribe_0_id=" + id + "&tribe_0_colour=" + mapProfile.tribeColor.substr(1);
6618 link += "¢rex=" + mapProfile.centreX + "¢rey=" + mapProfile.centreY;
6619 if (mapProfile.yourTribeColor != null && game_data.player.ally_id != id) {
6620 link += "&tribe_1_id=" + game_data.player.ally_id + "&tribe_1_colour=" + mapProfile.yourTribeColor.substr(1);
6621 }
6622 link += "&grid=" + (mapProfile.grid ? 1 : 0) + "&fill=" + mapProfile.fill.substr(1) + "&zoom=" + mapProfile.zoom
6623 if (mapProfile.markedOnly) {
6624 link += "&nocache=1";
6625 }
6626 if (mapProfile.bigMarkers) {
6627 link += "&bm=1";
6628 }
6629 if (mapProfile.gridContinentNumbers) {
6630 link += "&kn=1";
6631 }
6632 if (mapProfile.ownColor != null) {
6633 link += "&player_0_id=" + game_data.player.id + "&player_0_colour=" + mapProfile.ownColor.substr(1);
6634 }
6635 commandsTable.find("tr:last").before("<tr><td colspan=2><a href='" + link + "' target='_blank'>» " + trans.sp.profile.twStatsMap + "</a> " + trans.sp.profile.externalPage + "</td></tr>");
6636 }
6637
6638 // Build graphs
6639 if (id > 0) {
6640 var html = "";
6641
6642 // TWMap graphs
6643 var twMapGraphs;
6644 if (screen == "tribe") {
6645 twMapGraphs = [["tribe", trans.sp.profile.graphTWMap], ["p_tribe", trans.sp.profile.graphPoints], ["oda_tribe", trans.sp.profile.graphODA], ["odd_tribe", trans.sp.profile.graphODD]];
6646 } else {
6647 twMapGraphs = [["player", trans.sp.profile.graphTWMap], ["p_player", trans.sp.profile.graphPoints], ["oda_player", trans.sp.profile.graphODA], ["odd_player", trans.sp.profile.graphODD], ["ods_player", trans.sp.profile.graphODS]];
6648 }
6649 for (var i = 0; i < twMapGraphs.length; i++) {
6650 var graphDetails = screen == "tribe" ? profile.twMapTribeGraph[twMapGraphs[i][0]] : profile.twMapPlayerGraph[twMapGraphs[i][0]];
6651 if (graphDetails[0]) {
6652 html += createSpoiler(twMapGraphs[i][1], '<img src="http://' + game_data.world + '.tribalwarsmap.com/' + game_data.market + '/graph/' + twMapGraphs[i][0] + '/' + id + '" title="' + trans.sp.profile.graphTWMap + '">', graphDetails[1]);
6653 }
6654 }
6655
6656 // TWStats graphs
6657 var graphs = [["points", trans.sp.profile.graphPoints], ["villages", trans.sp.profile.graphVillages], ["od", trans.sp.profile.graphOD], ["oda", trans.sp.profile.graphODA], ["odd", trans.sp.profile.graphODD], ["rank", trans.sp.profile.graphRank]];
6658 if (screen == "tribe") {
6659 graphs.push(["members", trans.sp.profile.graphMembers]);
6660 }
6661 var toShow = screen == "tribe" ? profile.tribeGraph : profile.playerGraph;
6662 for (var i = 0; i < graphs.length; i++) {
6663 if (toShow[i][1]) {
6664 var graphType = toShow[i][1] == 'big' ? 'ss' : '';
6665 html += createSpoiler(graphs[i][1], '<img src="https://' + game_data.market + '.twstats.com/image.php?type=' + screen + graphType + 'graph&id=' + id + '&s=' + game_data.world + '&graph=' + graphs[i][0] + '">', toShow[i][2] != undefined);
6666 }
6667 }
6668
6669 // Show graphs
6670 if (html.length > 0) {
6671 var pictureTable;
6672 if (screen == 'player' || (isVillage && user_data.showPlayerProfileOnVillage)) {
6673 pictureTable = $(content_value).find('table:has("th:first:contains(Profiel)")'); // TODO: untranslated resource Profiel
6674 if (isVillage || pictureTable.html() == null) {
6675 // With no info nor personal text
6676 pictureTable = $("<table class='vis' width='100%'><tr><th colspan='2'>" + trans.tw.profile.title + "</th></tr></table>");
6677 $("td:first", content_value).closest('table').hasClass('modemenu') ? $(content_value).find('table:has("#villages_list") td:first').next().prepend(pictureTable) : $("td:first", content_value).next().prepend(pictureTable);
6678 } else if (pictureTable.find("th").text() != trans.tw.profile.title) {
6679 // TODO: There is a ; after the IF, is that the intention???
6680 if (pictureTable.find("th:first").text() == trans.tw.profile.awardsWon);
6681 pictureTable = pictureTable.parent();
6682
6683 // If there is only the node "Personal info"
6684 var temp = $("<table class='vis' width='100%'><tr><th colspan='2'>" + trans.tw.profile.title + "</th></tr></table>");
6685 pictureTable.prepend(temp);
6686 pictureTable = temp;
6687 }
6688
6689 if (pictureTable.find("td[colspan=2]").size() > 0) {
6690 pictureTable.find("tr:last").before("<tr><td colspan=2>" + html + "</td></tr>");
6691 } else {
6692 pictureTable.find("tr:last").after("<tr><td colspan=2>" + html + "</td></tr>");
6693 }
6694 } else {
6695 commandsTable.after("<table class=vis width='100%'><tr><th>" + trans.tw.profile.title + "</th></tr><tr><td>" + html + "</td></tr></table>");
6696 }
6697 }
6698 }
6699
6700 // Conquers (intern)
6701 if (id > 0 && profile.popup.show) {
6702 var twLink = 'https://' + game_data.market + '.twstats.com/' + game_data.world + '/index.php?page=' + screen + '&mode=conquers&id=' + id + '&pn=1&type=1&enemy=-1&enemyt=-1&min=&max=';
6703 var conquers = "<tr><td colspan=2><a href=\"\" id='conquers'>» " + trans.sp.profile.conquers + "</a> " + trans.sp.profile.internalPage + "</td></tr>";
6704 if (screen == 'tribe') {
6705 commandsTable.find("tr:last").before(conquers);
6706 } else {
6707 commandsTable.find("tr:last").after(conquers);
6708 }
6709 var popupWidth = profile.popup.width;
6710 var popupHeight = profile.popup.height;
6711 commandsTable.after('<div class="messagepop pop" id="popup" style="display: none"><iframe src=' + twLink + ' width=' + popupWidth + ' height=' + popupHeight + '></div>');
6712 $("#popup").css({ "left": profile.popup.left, "top": profile.popup.top, "background-color": "#FFFFFF", "border": "1px solid #999999", "position": "absolute", "width": popupWidth, "height": popupHeight, "z-index": 50, "padding": "25px 25px 20px" });
6713
6714 $(function () {
6715 $("#conquers").on('click', function (event) {
6716 if ($(this).hasClass('selected')) {
6717 $("#conquers").removeClass("selected");
6718 } else {
6719 $(this).addClass("selected");
6720 }
6721 $("#popup").toggle();
6722 return false;
6723 });
6724
6725 $("#popup").on('click', function () {
6726 $("#popup").hide();
6727 $("#conquers").removeClass("selected");
6728 return false;
6729 });
6730 });
6731 }
6732 }
6733
6734 if (current_page.screen === 'info_village' && user_data.proStyle && profile.moveClaim) {
6735 // move claim to a position that does not interfere with more important links (2-click behavior)
6736 if ($("td:eq(8)", commandsTable).text() == trans.tw.profile.claimedBy) {
6737 commandsTable.append($("tr:eq(5),tr:eq(6)", commandsTable));
6738 }
6739 }
6740 } catch (e) { handleException(e, "info_villageplayertribe"); }
6741 }());
6742 }
6743 if (current_page.screen === 'info_village') {
6744 //Written by hardcode
6745 (function() {
6746 var show = true;
6747 var head = $(".vis:contains('Aankomend')", content_value).find("tr:first");
6748 var text = $("th:contains('Aankomst:')", content_value).html('Aankomend: <img src="https://www.tribalwars.vodka/graphic/minus.png" style=" float: right;">');
6749
6750 head.on("click", function () {
6751 if(show === true) {
6752 $(".no_ignored_command").hide();
6753 text.html('Verborgen: <img src="https://www.tribalwars.vodka/graphic/plus.png" style=" float: right;">');
6754 show = false;
6755 }else{
6756 $(".no_ignored_command").show();
6757 text.html('Aankomend: <img src="https://www.tribalwars.vodka/graphic/minus.png" style=" float: right;">');
6758 show = true;
6759 }
6760 });
6761 }());
6762 }
6763
6764 // ALL OVERVIEW PAGES
6765 if (current_page.screen === 'overview_villages') {
6766 var overviewTable;
6767 //tableHandler.overviewTable
6768
6769 var tableHandler;
6770 (function (tableHandler) {
6771 function init(id, options) {
6772 tableHandler.overviewTableName = id;
6773 tableHandler.overviewTable = $("#" + id);
6774 tableHandler.settings = {
6775 hasBottomTotalRow: false
6776
6777 };
6778 tableHandler.settings = $.extend({}, tableHandler.settings, options || {});
6779
6780 // do stuff on page load
6781 ajaxLoadNextPageSetup();
6782 }
6783 tableHandler.init = init;
6784
6785 function getReplacedVillageRows(page) {
6786 var overviewTable = typeof page === 'undefined' ? tableHandler.overviewTable : $("#"+tableHandler.overviewTableName, page);
6787 if (typeof tableHandler.settings.rowReplacer === "function") {
6788 var newTable = "";
6789 var villageRows = selectVillageRows(overviewTable);
6790 villageRows.each(function () {
6791 var row = $(this);
6792 newTable += tableHandler.settings.rowReplacer(row);
6793 });
6794 return newTable;
6795 } else {
6796 return selectVillageRows(overviewTable);
6797 }
6798 }
6799 tableHandler.getReplacedVillageRows = getReplacedVillageRows;
6800
6801 function selectVillageRows(page) {
6802 //q(tableHandler.overviewTableName);
6803 //q("grrrr:"+page.find("tr").not(":first").length);
6804 var villageRows = page.find("tr").not(":first");
6805 if (tableHandler.settings.hasBottomTotalRow) {
6806 villageRows = villageRows.not(":last");
6807 }
6808 //q(villageRows);
6809 return villageRows;
6810 }
6811
6812 function ajaxLoadNextPageSetup() {
6813 if (server_settings.ajaxAllowed) {
6814 var nextPageLink = $("#paged_view_content a.paged-nav-item").first();
6815 if (nextPageLink.length !== 0) {
6816 // find all pages we can still add to the current table
6817 var currentPageLabel = nextPageLink.parent().find("strong");
6818 var nextPageLinks = [];
6819 currentPageLabel = currentPageLabel.next();
6820 while (currentPageLabel.text().match(/\d/)) {
6821 nextPageLinks.push(currentPageLabel);
6822 currentPageLabel = currentPageLabel.next();
6823 }
6824
6825 if (nextPageLinks.length > 0) {
6826 nextPageLink.parent().append(" <a href=# id=loadNextPage>"+trans.sp.overviews.loadNextPage+"</a>");
6827
6828 $("#loadNextPage").click(function() {
6829 // Get next page or remove link
6830 var nextPageUrl = nextPageLinks[0];
6831 if (nextPageLinks.length == 1) {
6832 $(this).replaceWith("<strong>"+trans.sp.overviews.loadNextPage+"</strong>");
6833 }
6834 nextPageLinks.shift();
6835
6836 // Fetch and insert next page
6837 ajax(nextPageUrl.attr("href"), function (page) {
6838 var nextPageRows = getReplacedVillageRows($(page));
6839 if (tableHandler.settings.hasBottomTotalRow) {
6840 tableHandler.overviewTable.find("tr:last").before(nextPageRows);
6841 } else {
6842 tableHandler.overviewTable.append(nextPageRows);
6843 }
6844
6845 nextPageUrl.replaceWith("<strong>"+nextPageUrl.text()+"</strong>");
6846 });
6847 });
6848 }
6849 }
6850 }
6851 }
6852 })(tableHandler || (tableHandler = {}));
6853
6854 // PRODUCTION OVERVIEW
6855 if (location.href.indexOf('mode=prod') > -1) {
6856 (function() {
6857 //console.time("overview-prod");
6858 try {
6859 overviewTable = $("#production_table");
6860 tableHandler.init("production_table");
6861
6862 // Filter full storage rooms
6863 var resTable = $("#production_table");
6864 var menu = "<table class='vis' width='100%'>";
6865 menu += "<tr><th width='99%'>";
6866 menu += " <input type=checkbox id=resFilter " + (user_data.resources.filterRows ? "checked" : "") + "> " + trans.sp.prodOverview.filter + " ";
6867 menu += " <input type=button id=resStorageFull value='" + trans.sp.prodOverview.filterFullGS + "' title=''> ";
6868 menu += "<select id=resAmountType><option value=1>" + trans.sp.all.more + "</option>";
6869 menu += "<option value=-1>" + trans.sp.all.less + "</option></select>";
6870 menu += "<input type=text id=resAmount size=6 value=" + user_data.resources.requiredResDefault + ">";
6871 menu += " <input type=button class=resFilter value='" + trans.tw.all.wood + "' resIndex=0><input type=button class=resFilter value='" + trans.tw.all.stone + "' resIndex=1><input type=button class=resFilter value='" + trans.tw.all.iron + "' resIndex=2><input type=button class=resFilter value='" + trans.sp.all.all + "' resIndex=-1>";
6872 menu += " " + trans.sp.all.withText + " <input type=checkbox id=resMerchant " + (user_data.resources.filterMerchants ? "checked" : "") + " title='" + trans.sp.prodOverview.merchantTooltip + "'>";
6873 menu += "<input type=text id=resMerchantAmount size=2 value=" + user_data.resources.requiredMerchants + " title='" + trans.sp.prodOverview.merchantAmountTooltip + "'> " + trans.sp.all.merchants + " ";
6874
6875 menu += "</th><th width='1%' nowrap>";
6876 menu += "<input type=button id=resBBCode value='" + trans.sp.prodOverview.bbCodes + "'> "
6877 + "<input type=checkbox id=resBBCodeImages> " + trans.sp.prodOverview.bbCodesInfo + " ";
6878 menu += "</th></tr></table>";
6879 resTable.before(menu);
6880
6881 $("#resFilter").change(function () {
6882 var isCheck = $(this).is(":checked");
6883 $("#resFilter").attr("title", isCheck ? trans.sp.prodOverview.filterTooltip : trans.sp.prodOverview.filterTooltipReverse);
6884 $("#resStorageFull").attr("title", isCheck ? trans.sp.prodOverview.filterFullGSTooltip : trans.sp.prodOverview.filterFullGSTooltipReverse);
6885 $(".resFilter").each(function (index, value) {
6886 if (index == 3) {
6887 $(value).attr("title", isCheck ? trans.sp.prodOverview.filterAllTooltip : trans.sp.prodOverview.filterAllTooltipReverse);
6888 } else {
6889 $(value).attr("title", isCheck ? trans.sp.prodOverview.filter1Tooltip.replace("{0}", $(value).attr("value")) : trans.sp.prodOverview.filter1TooltipReverse.replace("{0}", $(value).attr("value")));
6890 }
6891 });
6892 });
6893
6894 $("#resFilter").change();
6895
6896 $("#resStorageFull").click(function () {
6897 trackClickEvent("FilterFullRes");
6898 filterRes('full', $("#resFilter").is(":checked"));
6899 });
6900
6901 $("#resBBCode").click(function () {
6902 trackClickEvent("BBCodeOutput");
6903 var bbs = filterRes("bbcode", false),
6904 reverse = $("#resAmountType").val() == "-1",
6905 bbCodesTitle = reverse ? trans.sp.prodOverview.tooLittleText : trans.sp.prodOverview.tooMuchText;
6906
6907 bbCodesTitle = bbCodesTitle
6908 .replace("{diff}", parseInt(user_data.resources.bbcodeMinimumDiff / 1000, 10))
6909 .replace("{min}", parseInt(parseInt($("#resAmount").val(), 10) / 1000, 10));
6910
6911 if ($("#textsArea").size() == 0) {
6912 $(this).parent().parent().parent().append("<tr><td colspan=2 id=textsArea></td></tr>");
6913 } else {
6914 $("#textsArea").html("");
6915 }
6916
6917 $("#textsArea").append("<b>" + bbCodesTitle + "</b>" + trans.sp.prodOverview.bbCodeExtraInfo + "<br><textarea id=bbcodeArea cols=50 rows=10 wrap=off>");
6918 $("#bbcodeArea").val(bbs);
6919
6920 $("#textsArea").append("<br><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>");
6921 $("#closeTextsArea").click(function() {
6922 $("#textsArea").parent().remove();
6923 });
6924 });
6925
6926 function filterRes(resourceIndex, hideRows) {
6927 var resCode = [trans.tw.all.wood, trans.tw.all.stone, trans.tw.all.iron];
6928 var bbcodes = '';
6929 var goners = $();
6930 var stayers = $();
6931 var filterMerchants = $("#resMerchant").is(":checked");
6932 var filterMerchantsAmount = parseInt($("#resMerchantAmount").val(), 10);
6933 var minAmount = parseInt($("#resAmount").val(), 10);
6934 var reverse = $("#resAmountType").val() == "-1";
6935 var bbCodeImages = $("#resBBCodeImages").is(":checked");
6936 var minDif = user_data.resources.bbcodeMinimumDiff;
6937 var bbCodesTitle;
6938
6939 if (reverse) {
6940 bbcodes = trans.sp.prodOverview.tooLittle + "\n";
6941 bbCodesTitle = trans.sp.prodOverview.tooLittleText;
6942 } else {
6943 bbcodes = trans.sp.prodOverview.tooMuch + "\n";
6944 bbCodesTitle = trans.sp.prodOverview.tooMuchText;
6945 }
6946 bbCodesTitle = bbCodesTitle.replace("{min}", minDif).replace("{diff}", minAmount);
6947
6948 function doResource(resCell, resArray, resIndex, reverse, minAmount) {
6949 var resAmount = parseInt(resArray[resIndex], 10);
6950 if ((!reverse && resAmount > minAmount) || (reverse && resAmount < minAmount)) {
6951 $("span[title]:eq(" + resIndex + ")", resCell).css("font-weight", "bold")
6952 return false;
6953 }
6954 return true;
6955 }
6956
6957 var hasNotes = $("th:first", resTable).text().indexOf(trans.tw.overview.village) == -1;
6958 resTable.find("tr:gt(0)").each(function () {
6959 var isOk = true;
6960 var resCell;
6961 if (hasNotes) {
6962 resCell = $(this).find("td:eq(3)");
6963 } else {
6964 resCell = $(this).find("td:eq(2)");
6965 }
6966 var resources = $.trim(resCell.text()).replace(/\./gi, "").split(" ");
6967
6968 if (resourceIndex == 'bbcode') {
6969 // All resources
6970 var villageBBCode = '';
6971 for (var i = 0; i < 3; i++) {
6972 if ((!reverse && resources[i] - minDif > minAmount) || (reverse && parseInt(resources[i], 10) + parseInt(minDif, 10) < minAmount)) {
6973 if (bbCodeImages) {
6974 villageBBCode += "[img]https://www.tribalwars.nl/graphic/" + world_data.resources[i] + ".png[/img] ";
6975 } else {
6976 villageBBCode += resCode[i] + " ";
6977 }
6978 villageBBCode += parseInt(Math.abs(resources[i] - minAmount) / 1000, 10) + "k ";
6979 }
6980 }
6981 if (villageBBCode.length > 0) {
6982 var villageCell = $("td:eq(" + (hasNotes ? "1" : "0") + ") span:eq(1)", this);
6983 bbcodes += "[village]" + getVillageFromCoords(villageCell.text()).coord + "[/village] " + villageBBCode + "\n";
6984 }
6985 } else if (resourceIndex == 'full') {
6986 // full storage rooms
6987 if ($(".warn", this).size() > 0) {
6988 resCell.css("background-color", user_data.resources.highlightColor);
6989 isOk = false;
6990 }
6991
6992 } else {
6993 // One specific resource
6994 $("span[title]", resCell).css("font-weight", "normal");
6995
6996 if (resourceIndex == "-1") {
6997 isOk = isOk && !(!doResource(resCell, resources, 0, reverse, minAmount)
6998 | !doResource(resCell, resources, 1, reverse, minAmount)
6999 | !doResource(resCell, resources, 2, reverse, minAmount));
7000 } else {
7001 isOk = isOk && doResource(resCell, resources, resourceIndex, reverse, minAmount);
7002 }
7003
7004 if (!isOk) {
7005 resCell.css("background-color", user_data.resources.highlightColor);
7006 } else {
7007 resCell.css("background-color", "");
7008 }
7009
7010 if (filterMerchants) {
7011 resCell = $(this).find("td:eq(4)");
7012 if (hasNotes) {
7013 resCell = resCell.next();
7014 }
7015 var merchants = resCell.text();
7016 merchants = merchants.substr(0, merchants.indexOf("/"));
7017 if (merchants < filterMerchantsAmount) {
7018 resCell.css("background-color", user_data.colors.error);
7019 } else {
7020 resCell.css("background-color", "");
7021 }
7022 }
7023 }
7024
7025 if (hideRows && isOk) {
7026 goners = goners.add($(this));
7027
7028 // Village rename script will not rename villages if the hidden rename inputfield is on a hidden row
7029 // --> People were using our script to filter the village list and then use a mass village renamer which also renamed the hidden village rows
7030 $("input:first", $(this)).val("");
7031
7032 }
7033 else if (!$(this).is(":visible")) {
7034 stayers = stayers.add($(this));
7035 }
7036 });
7037 if (hideRows) {
7038 goners.remove();
7039 var amountOfVillagesCell = $("tr:first th", resTable).eq(hasNotes ? 1 : 0);
7040 amountOfVillagesCell.text(amountOfVillagesCell.text().replace(/\d+/, $("tr", resTable).size() - 1));
7041 } else {
7042 stayers.show();
7043 goners.hide();
7044 }
7045
7046 return bbcodes;
7047 }
7048
7049 $(".resFilter").click(function () {
7050 trackClickEvent("FilterResource");
7051 filterRes($(this).attr("resIndex"), $("#resFilter").is(":checked"));
7052 });
7053 } catch (e) { handleException(e, "overview-prod"); }
7054 //console.timeEnd("overview-prod");
7055 }());
7056 }
7057 // TROOPS OVERVIEW
7058 else if (location.href.indexOf('mode=units') > -1
7059 && (location.href.indexOf('type=own_home') > -1 || location.href.indexOf('type=there') > -1)) {
7060 (function() {
7061 //console.time("overview-thereownhome");
7062 try {
7063 var villageCounter = 0;
7064 var rowSize = world_data.units.length + 1;
7065 if (world_config.hasMilitia) {
7066 rowSize++;
7067 }
7068
7069 var overviewMenuRowFilter = "tr:gt(0)",
7070 /**
7071 * Page speed can be overruled by the querystring
7072 */
7073 currentPageSpeed = spSpeedCookie(),
7074 /**
7075 * {village} object from target cookie (or by url querystring set)
7076 */
7077 target;
7078
7079 /**
7080 * Do initial filter? (based on querystring)
7081 */
7082 var doFilter = false,
7083 unitIndex = world_data.units.indexOf(user_data.command.filterMinDefaultType),
7084 unitAmount = user_data.command.filterMinDefault,
7085 sort = false,
7086 changeSpeed = false,
7087 i;
7088 var search = window.location.search.substring(1).split("&");
7089 for (i = 0; i < search.length; i++) {
7090 var item = search[i].split("=");
7091 switch (item[0]) {
7092 case 'unit':
7093 doFilter = true;
7094 unitIndex = world_data.units.indexOf(item[1]);
7095 break;
7096 case 'amount':
7097 doFilter = true;
7098 unitAmount = parseInt(item[1], 10);
7099 break;
7100 case 'changeSpeed':
7101 changeSpeed = item[1];
7102 if (changeSpeed != false) {
7103 //spSpeedCookie(changeSpeed);
7104 currentPageSpeed = changeSpeed;
7105 }
7106 break;
7107
7108 case 'targetvillage':
7109 var newTargetVillage = getVillageFromCoords(item[1]);
7110 spTargetVillageCookie(newTargetVillage.coord);
7111 break;
7112
7113 case 'sort':
7114 sort = item[1] == "true";
7115 break;
7116 }
7117 }
7118
7119 // Sangu package menu is also built in reinitialize_table
7120 /**
7121 * Creates a select box with all unit types in this world
7122 * @param {string} id the DOM ID
7123 * @param {string} select the currently selected unit
7124 */
7125 function makeUnitBox(id, select) {
7126 var box = "<select id=" + id + ">";
7127 $.each(world_data.units, function (i, v) {
7128 box += "<option value=" + i + (v == select ? " selected" : "") + ">" + trans.tw.units.names[v] + "</option>";
7129 });
7130 box += "</select>";
7131 return box;
7132 }
7133
7134 var menu = "<table width='100%' class='vis'>";
7135 menu += "<tr>";
7136 menu += "<th nowrap width='1%'>";
7137 menu += "<input type=text size=5 id=filterAxeValue value='" + user_data.command.filterMinDefault + "'>";
7138 menu += makeUnitBox("filterAxeType", user_data.command.filterMinDefaultType);
7139 menu += "<input type=button id=filterAxe value='" + trans.sp.troopOverview.filterTroops + "'";
7140 menu += " title='" + trans.sp.troopOverview.filterTroopsTooltip + "'> ";
7141
7142 menu += "</th><th nowrap width='1%'>";
7143
7144 menu += "<select id=filterPopValueType><option value=1>" + trans.sp.all.more + "</option>";
7145 menu += "<option value=-1>" + trans.sp.all.less + "</option></select>";
7146 menu += "<input type=text size=5 id=filterPopValue value='" + user_data.command.filterMinPopulation + "'>";
7147 menu += "<input type=button id=filterPop value='" + trans.sp.troopOverview.filterPopulation + "' title='" + trans.sp.troopOverview.filterPopulationTooltip + "'> ";
7148
7149 menu += "</th><th nowrap width='1%'>";
7150 menu += "<input type=text size=5 id=filterWalkingTimeValue>";
7151 menu += "<input type=button id=filterWalkingTime value='" + trans.sp.troopOverview.filterWalkingTime + "' title='" + trans.sp.troopOverview.filterWalkingTimeTooltip + "'> ";
7152
7153 menu += "</th><th width='95%'>";
7154
7155 menu += "<input type=button id=snobFilter value='" + trans.sp.troopOverview.filterNoble + "' title='" + trans.sp.troopOverview.filterNobleTooltip + "'> ";
7156 menu += "<input type=button id=attackFilter value='" + trans.sp.troopOverview.filterUnderAttack + "' title='" + trans.sp.troopOverview.filterUnderAttackTooltip + "'> ";
7157
7158 menu += "</th><th width='1%'>";
7159
7160 menu += "<input type=button id=calculateStack value='" + trans.sp.troopOverview.calcStack + "' title='" + trans.sp.troopOverview.calcStackTooltip + "'>";
7161 menu += "</th>";
7162
7163 menu += "</tr></table>";
7164
7165 // second row
7166 menu += "<table><tr><th width='1%' nowrap>";
7167 menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": ";
7168
7169 menu += "</th><th width='1%' nowrap>";
7170 menu += "<input type=text size=12 id=defFilterTextValue value=''>";
7171 menu += "<input type=button id=defFilterText value='" + trans.sp.commands.freeTextFilter + "'>";
7172
7173 menu += "</th><th width='97%' nowrap>";
7174 menu += "<input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>";
7175
7176 menu += "</th>";
7177
7178 if (location.href.indexOf('type=there') > -1) {
7179 menu += "<th width='1%'><input type=button id=defRestack value='" + trans.sp.troopOverview.restack + "'></th>";
7180 }
7181 menu += "<th nowrap width='1%' style='padding-right: 8px; padding-top: 3px;'>";
7182
7183 menu += "<input type=checkbox id=sortIt title='" + trans.sp.troopOverview.sortTooltip + "'"
7184 + (user_data.command.filterAutoSort ? " checked" : "") + "> "
7185 + trans.sp.troopOverview.sort;
7186
7187 menu += "</th></tr>";
7188 menu += "</table>";
7189
7190 // Sangu filter menu
7191 var sanguMenu = menu;
7192
7193 // Overview table menu
7194 menu = "<tr id=units_table_header>";
7195 menu += "<th>" + trans.sp.troopOverview.village + "</th>";
7196 menu += "<th>" + trans.sp.troopOverview.nightBonus + "</th>";
7197 $.each(world_data.units, function (i, v) {
7198 menu += "<th><img src='/graphic/unit/unit_" + v + ".png' title=\"" + trans.sp.troopOverview.selectUnitSpeed.replace("{0}", trans.tw.units.names[v]) + "\" alt='' id=" + v + " /></th>";
7199 });
7200 if (world_config.hasMilitia) {
7201 menu += "<th><img src='/graphic/unit/unit_militia.png' title='" + trans.tw.units.militia + "' alt='' id=militia /></th>";
7202 }
7203 menu += "<th>" + trans.sp.troopOverview.commandTitle + "</th>";
7204
7205
7206 target = getVillageFromCoords(spTargetVillageCookie());
7207 menu += "<th nowrap>" + trans.sp.all.targetEx
7208 + " <input type=text id=targetVillage name=targetVillage size=8 value='"
7209 + (target.isValid ? target.coord : "") + "'>"
7210 + "<input type=button class='btn' id=targetVillageButton value='"
7211 + trans.sp.troopOverview.setTargetVillageButton + "'></th>";
7212 menu += "</tr>";
7213
7214
7215
7216
7217
7218
7219 // function to replace the village rows
7220 tableHandler.init("units_table", {
7221 rowReplacer: function (row) {
7222 //q($(row).html());
7223 var mod = "row_a";
7224 var newRow = "";
7225 var finalRow = "";
7226 var addThisRow = true;
7227 var cells = $("td:gt(0)", row);
7228 var units = {};
7229 var villageCell = $("td:first", row);
7230 var villageId = $("span.quickedit-vn", villageCell).attr("data-id");
7231
7232 cells.each(function (index, element) {
7233 if (doFilter && index - 1 == unitIndex && parseInt(this.innerHTML, 10) < unitAmount) {
7234 //q("index:" + index + ' == '+ unitIndex + " : " + row.html() + ' * 1 < ' + unitAmount);
7235 addThisRow = false;
7236 return false;
7237 }
7238 else if (index == rowSize) {
7239 //q(index + "==" + rowSize);
7240 newRow += "<td>";
7241 newRow += "<img src='/graphic/dots/red.png' title='" + trans.sp.troopOverview.removeVillage + "' style='margin-bottom: 2px' /> ";
7242 //newRow += "<img src='https://www.tribalwars.vodka/graphic/delete_small.png' style='margin-bottom: 3px; position: relative' title='" + trans.sp.troopOverview.removeVillage + "' /> ";
7243 newRow += "<a href='" + $("a", element).attr('href').replace("mode=units", "") + "&sanguX=0&sanguY=0' class='attackLinks'>";
7244 newRow += "<img src='/graphic/command/attack.png' title='" + trans.sp.troopOverview.toThePlace + "' style='margin-bottom: 1px' />";
7245 // Works only with leftclick onclick='this.src=\"/graphic/command/return.png\";'
7246 newRow += "</a>";
7247 newRow += "</td>";
7248 } else {
7249 //q("units:" + world_data.units[index - 1]);
7250 var cellDisplay = this.innerHTML;
7251 if (cellDisplay === "0") {
7252 cellDisplay = " ";
7253 }
7254 else if (cellDisplay.indexOf('="has_tooltip"') > -1) {
7255 cellDisplay = cellDisplay.replace('="has_tooltip"', '="has_tooltip" title="'+trans.sp.troopOverview.cheapNobles+'"');
7256 }
7257
7258 newRow += "<td>" + cellDisplay + "</td>";
7259 if (index > 0) {
7260 units[world_data.units[index - 1]] = parseInt(element.innerHTML, 10);
7261 }
7262 // innerHTML can contain a + sign for the nobles: "+" indicates nobles can be rebuild cheaply
7263 // The snobs are not important here
7264 }
7265 });
7266
7267 if (addThisRow) {
7268 var villageType = calcTroops(units);
7269 if (doFilter) {
7270 mod = villageCounter % 2 == 0 ? "row_a" : "row_b";
7271 } else {
7272 mod = !villageType.isDef ? "row_a" : "row_b";
7273 }
7274
7275 var coord = getVillageFromCoords(villageCell.text());
7276
7277 //finalRow += "<tbody>";
7278 finalRow += "<tr arrival='0' data-coord-x='" + coord.x + "' data-coord-y='" + coord.y + "' "
7279 + " class='row_marker " + mod + (game_data.village.id == villageId ? " selected" : "") + "'>";
7280 finalRow += "<td>" + villageCell.html() + "</td>";
7281 finalRow += newRow;
7282 finalRow += "<td></td></tr>";
7283 //finalRow += "</tbody>";
7284
7285 villageCounter++;
7286
7287 return finalRow;
7288 }
7289 return "";
7290 }
7291 });
7292
7293 var newTable = tableHandler.getReplacedVillageRows();
7294 $("#units_table")
7295 .html("<table width='100%' class='vis' id='units_table' target='false'>" + menu + newTable + "</table>")
7296 .before(sanguMenu);
7297
7298
7299 // Tooltips
7300 $("#defReverseFilter").change( function () {
7301 var isChecked = $(this).is(":checked");
7302 var defTrans = trans.sp.troopOverview;
7303
7304 $("#defFilterContinent").attr("title", isChecked ? defTrans.continentFilterTooltip : defTrans.continentFilterTooltipReverse);
7305 $("#defFilterText").attr("title", defTrans.freeTextFilterTooltip.replace("{filterType}", isChecked ? defTrans.freeTextFilterTooltipFilterTypeWith : defTrans.freeTextFilterTooltipFilterTypeWithout));
7306 });
7307 $("#defReverseFilter").change();
7308
7309
7310 // Initial focus on target inputbox
7311 $('#targetVillage').click(function () {
7312 $(this).focus().select();
7313 });
7314
7315
7316
7317 // "Attacks per page" -> change to # villages in the list
7318 var pageSize = $("input[name='page_size']");
7319 var villageAmountCell = $("#units_table tr:first th:first");
7320 //assert(villageAmountCell.length === 1, "village cell Dorp (xxx) niet gevonden");
7321 villageAmountCell.text(villageAmountCell.text() + " (0)");
7322 function setVillageCount(amount) {
7323 pageSize.val(amount);
7324 villageAmountCell.text(villageAmountCell.text().replace(/\d+/, amount));
7325 }
7326
7327 pageSize.parent().prev().text(trans.sp.overviews.totalVillages);
7328 setVillageCount(villageCounter);
7329
7330 // Recalculate arrival times as the target village changes
7331 $("#targetVillageButton").click(function () {
7332 trackClickEvent("TargetVillageSet");
7333 var targetMatch = getVillageFromCoords($('#targetVillage').val(), true);
7334 $("#units_table").attr("target", targetMatch.isValid);
7335 if (!targetMatch.isValid) {
7336 spTargetVillageCookie("");
7337 alert(trans.sp.troopOverview.setTargetVillageButtonAlert);
7338 $("#targetVillage").focus();
7339
7340 } else {
7341 $(".attackLinks", tableHandler.overviewTable).each(function() {
7342 // add target coordinates to attack image href which are read in place
7343 var hrefWithVillageCoords = $(this).attr("href");
7344 hrefWithVillageCoords = hrefWithVillageCoords.replace(/sanguX=(\d+)&sanguY=(\d+)/, "sanguX="+targetMatch.x+"&sanguY="+targetMatch.y);
7345 $(this).attr("href", hrefWithVillageCoords);
7346 });
7347
7348 spTargetVillageCookie(targetMatch.coord);
7349 $("#units_table").find(overviewMenuRowFilter).each(function () {
7350 var unitRow = $(this),
7351 dist = getDistance(targetMatch.x, unitRow.attr("data-coord-x"), targetMatch.y, unitRow.attr("data-coord-y"), currentPageSpeed);
7352
7353 $("td:last", unitRow).html(dist.html);
7354 $(this).attr("arrival", dist.travelTime);
7355 if (dist.isNightBonus) {
7356 $("td:eq(1)", unitRow).css("background-color", user_data.colors.error);
7357 } else {
7358 $("td:eq(1)", unitRow).css("background-color", '');
7359 }
7360 });
7361
7362 if ($("#sortIt").is(":checked")) {
7363 $("#units_table").find(overviewMenuRowFilter).sortElements(function (a, b) {
7364 return parseInt($(a).attr("arrival"), 10) > parseInt($(b).attr("arrival"), 10) ? 1 : -1;
7365 });
7366 }
7367 }
7368 });
7369
7370 // sort can be set with the querystring
7371 if (sort) {
7372 $("#targetVillageButton").click();
7373 }
7374
7375 // delete a table row
7376 $("#units_table").mouseup(function (e) {
7377 if (e.target.nodeName === 'IMG') {
7378 if (e.target.title == trans.sp.troopOverview.removeVillage) {
7379 setVillageCount(parseInt(pageSize.val(), 10) - 1);
7380 $(e.target).parent().parent().remove();
7381 }
7382 }
7383 });
7384
7385 // remove row or add border to command cell when middle mouse click (open in new tab)
7386 $(tableHandler.overviewTable).on("mousedown",".attackLinks", function(e) {
7387 if (e.which == 2) {
7388 var cell = $(e.target).parent().parent();
7389 if (user_data.command.middleMouseClickDeletesRow2) {
7390 cell.parent().remove();
7391 } else {
7392 cell.css("border", (parseInt(cell.css("border-width").substr(0, 1), 10) + 1) + "px red solid");
7393 }
7394 }
7395 });
7396
7397 // Change active speed by clicking on a unit icon
7398 // ATTN: border style duplicated in trans.troopOverview.help
7399 $('#' + currentPageSpeed).parent().css("border", "2px green dotted");
7400 $('#' + spSpeedCookie()).parent().css("border", "3px red solid");
7401 $("#units_table_header").click(function (e) {
7402 if (e.target.nodeName === 'IMG' && e.target.id !== "militia") {
7403 currentPageSpeed = e.target.id;
7404 $("img", this).parent().css("border", "0px");
7405 $('#' + currentPageSpeed).parent().css("border", "2px green dotted");
7406 $('#' + spSpeedCookie()).parent().css("border", "3px red solid");
7407 $("#targetVillageButton").click();
7408 }
7409 });
7410
7411 $("#units_table_header").dblclick(function (e) {
7412 if (e.target.nodeName === 'IMG' && e.target.id !== "militia") {
7413 currentPageSpeed = e.target.id;
7414 spSpeedCookie(e.target.id);
7415 $("img", this).parent().css("border", "0px");
7416 $('#' + currentPageSpeed).parent().css("border", "2px green dotted");
7417 $('#' + spSpeedCookie()).parent().css("border", "3px red solid");
7418 $("#targetVillageButton").click();
7419 }
7420 });
7421 function filterVillageRows(filterStrategy, options) {
7422 // return true to hidethe row; false keep row visible (without reverse filter checkbox)
7423 options = options || {
7424 allowFilter: true
7425 };
7426 var reverseFilter = options.allowFilter && $("#defReverseFilter").is(":checked"),
7427 goners = $(),
7428 villageCounter = 0;
7429
7430 $("#units_table").find(overviewMenuRowFilter).each(function () {
7431 var self = $(this);
7432 if (!reverseFilter != !filterStrategy(self)) {
7433 goners = goners.add(self);
7434 $("input:eq(1)", self).val("");
7435 } else {
7436 villageCounter++;
7437 }
7438 });
7439 goners.remove();
7440
7441 // Show totals
7442 setVillageCount(villageCounter);
7443 }
7444
7445 // CONTINENT FILTER
7446 $("#defFilterContinent").click(function () {
7447 trackClickEvent("FilterContinent");
7448 var continent = parseInt($("#defFilterContinentText").val(), 10);
7449 if (!isNaN(continent)) {
7450 filterVillageRows(function (row) {
7451 var village = getVillageFromCoords(row.find("td:first").text());
7452 if (!village.isValid ) {
7453 return true;
7454 }
7455 return village.continent() != continent;
7456 });
7457 }
7458 });
7459
7460 // TEXT FILTER
7461 $("#defFilterText").click(function () {
7462 trackClickEvent("FilterText");
7463 var compareTo = $("#defFilterTextValue").val().toLowerCase();
7464 if (compareTo.length > 0) {
7465 filterVillageRows(function (row) {
7466 return row.text().toLowerCase().indexOf(compareTo) == -1;
7467 });
7468 }
7469 });
7470
7471 // WALKINGTIME FILTER
7472 $("#filterWalkingTime").click(function () {
7473 var minWalkingTime = parseInt($("#filterWalkingTimeValue").val(), 10) * 60;
7474
7475 if (!isNaN(minWalkingTime)) {
7476 trackClickEvent("WalkingTime");
7477 filterVillageRows(
7478 function (row) {
7479 return parseInt(row.attr("arrival"), 10) < minWalkingTime;
7480 },
7481 {
7482 allowFilter: false
7483 }
7484 );
7485 } else {
7486 alert(trans.sp.troopOverview.filterWalkingTimeTooltip);
7487 }
7488 });
7489
7490
7491
7492
7493
7494
7495 // Filter rows with less than x axemen (or another unit)
7496 $("#filterAxe").click(function () {
7497 trackClickEvent("FilterUnitAmount");
7498 var villageCounter = 0;
7499 var goners = $();
7500 var minAxeValue = parseInt($("#filterAxeValue").val(), 10);
7501 var unit = parseInt($('#filterAxeType').val(), 10);
7502 $("#units_table").find(overviewMenuRowFilter).each(function () {
7503 var val = $("td:eq(" + (unit + 2) + ")", this).html();
7504 if (val == ' ' || parseInt(val, 10) < minAxeValue) {
7505 goners = goners.add($(this));
7506 $("input:first", $(this)).val("");
7507 }
7508 else
7509 villageCounter++;
7510 });
7511 goners.remove();
7512 setVillageCount(villageCounter);
7513 });
7514 // change by default selected unit the filter will be active for
7515 $("#filterAxeType").change(function () {
7516 var unit = world_data.units[$(this).val()];
7517 if (typeof user_data.command.filterMin[unit] !== 'undefined') {
7518 $("#filterAxeValue").val(user_data.command.filterMin[unit]);
7519 } else {
7520 $("#filterAxeValue").val(user_data.command.filterMinOther);
7521 }
7522 });
7523
7524
7525
7526 // Filter rows without snobs/nobles
7527 $("#snobFilter").click(function () {
7528 trackClickEvent("FilterSnob");
7529 var villageCounter = 0;
7530 var goners = $();
7531 $("#units_table").find(overviewMenuRowFilter).each(function () {
7532 if ($.trim($("td:eq(" + (world_data.unitsPositionSize.length + 1) + ")", this).text()) === '') {
7533 goners = goners.add($(this));
7534 $("input:first", $(this)).val("");
7535 } else
7536 villageCounter++;
7537 });
7538 goners.remove();
7539 setVillageCount(villageCounter);
7540 });
7541
7542 // hide rows not under attack
7543 $("#attackFilter").click(function () {
7544 trackClickEvent("FilterUnderAttack");
7545 var villageCounter = 0;
7546 var goners = $();
7547 $("#units_table").find(overviewMenuRowFilter).each(function () {
7548 //q("'" + $(this).html() + "'");
7549 //q("---------------------------------------------------");
7550 if ($('td:first:not(:has(img[title=\'' + trans.tw.command.attack + '\']))', this).size() != 0) {
7551 goners = goners.add($(this));
7552 $("input:first", $(this)).val("");
7553 } else {
7554 villageCounter++;
7555 }
7556 });
7557 goners.remove();
7558 setVillageCount(villageCounter);
7559 });
7560
7561 // filter rows with less then x population
7562 $("#filterPop").click(function () {
7563 trackClickEvent("FilterFarm");
7564 $("#calculateStack").click();
7565 var villageCounter = 0;
7566 var goners = $();
7567 var min = parseInt($("#filterPopValue").val(), 10);
7568 var reverseFilter = $("#filterPopValueType").val() == "-1";
7569 $("#units_table").find(overviewMenuRowFilter).each(function () {
7570 var line = $(this);
7571 $("td:eq(1)", this).each(function () {
7572 var amount = parseInt($(this).text().replace('.', ''), 10);
7573 if ((!reverseFilter && amount < min) || (reverseFilter && amount > min)) {
7574 goners = goners.add(line);
7575 $("input:first", line).val("");
7576 }
7577 else villageCounter++;
7578 });
7579 });
7580 goners.remove();
7581 setVillageCount(villageCounter);
7582 });
7583 // One time help display
7584 (function() {
7585 if ($("#targetVillageButton").length === 0) {
7586 // group without villages
7587 return;
7588 }
7589
7590 var position = $("#targetVillageButton").position(),
7591 options = {
7592 left: position.left - 300,
7593 top: position.top + 35
7594 },
7595 content = {
7596 title: trans.sp.troopOverview.helpTitle,
7597 body: trans.sp.troopOverview.help.replace("{unitIcon}", "<img src='graphic/unit/unit_ram.png'>, <img src='graphic/unit/unit_spear.png'>, ...")
7598 };
7599
7600 createFixedTooltip("troopOverviewTooltip", content, options);
7601 }());
7602
7603 // Calculate stack
7604 $("#calculateStack").click(function () {
7605 trackClickEvent("CalculateStack");
7606 if (!this.disabled) {
7607 this.disabled = true;
7608 $("#units_table").find(overviewMenuRowFilter).each(function () {
7609 var total = 0;
7610 $("td:gt(1)", this).each(function (i) {
7611 if (!($.trim(this.innerHTML) == '' || this.innerHTML == ' ' || i >= world_data.unitsPositionSize.length)) {
7612 total += this.innerHTML * world_data.unitsPositionSize[i];
7613 }
7614 });
7615 $("td:eq(1)", this).text(formatNumber(total)).css("background-color", getStackColor(total));
7616 });
7617 }
7618 });
7619 // Calculate Restack BB codes
7620 if (location.href.indexOf('type=there') > -1) {
7621 $("#defRestack").click(function () {
7622 trackClickEvent("BBCodeOutput");
7623 $("#calculateStack").click();
7624
7625 var request = "";
7626 $("#units_table").find(overviewMenuRowFilter).each(function () {
7627 var total = parseInt($("td:eq(1)", $(this)).text().replace(/\./, ''), 10);
7628 if (user_data.restack.to - total > user_data.restack.requiredDifference) {
7629 var villageDesc = $(this).find("td:first span[data-text]").text(),
7630 villageCoord = getVillageFromCoords(villageDesc);
7631
7632 request += "[village]" + villageCoord.coord + "[/village] (" + parseInt((user_data.restack.to - total) / 1000, 10) + "k)\n";
7633 }
7634 });
7635
7636 if ($("#textsArea").size() == 0) {
7637 $(this).parent().parent().parent().append("<tr><td id=textsArea colspan=5></td></tr>");
7638 } else {
7639 $("#textsArea").html("");
7640 }
7641
7642 var title = trans.sp.troopOverview.restackTitle
7643 .replace("{to}", parseInt(user_data.restack.to / 1000, 10))
7644 .replace("{requiredDiff}", parseInt(user_data.restack.requiredDifference / 1000, 10));
7645 $("#textsArea").append(title + "<br><textarea cols=35 rows=10 id=defRestackArea>" + request + "</textarea>");
7646
7647 $("#textsArea").append("<br><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>");
7648 $("#closeTextsArea").click(function() {
7649 $("#textsArea").parent().remove();
7650 });
7651 });
7652 }
7653
7654 } catch (e) { handleException(e, "overview-thereownhome"); }
7655 //console.timeEnd("overview-thereownhome");
7656 }());
7657 }
7658 // BUILDINGS OVERVIEW
7659 else if (location.href.indexOf('mode=buildings') > -1) {
7660 (function() {
7661 //console.time("overview-buildings");
7662 try {
7663 // Highlight everything not conform
7664 overviewTable = $("#buildings_table");
7665 tableHandler.init("buildings_table");
7666
7667 var menu = "<table class='vis' width='100%'>";
7668 menu += "<tr><th>";
7669 menu += "<input type=checkbox id=buildingOpti> " + trans.sp.buildOverview.optimistic + " ";
7670 menu += "<input type=button id=buildingHighlight value='" + trans.sp.buildOverview.mark + "'>";
7671 menu += "<input type=button id=buildingFilter value='" + trans.sp.buildOverview.filter + "'>";
7672 menu += "</th></tr></table>";
7673 overviewTable.before(menu);
7674
7675 function filterBuildings(cellAction, hideRows) {
7676 var buildings = [];
7677 overviewTable.find("tr:first img").each(function (i, v) {
7678 buildings[i] = this.src.substr(this.src.lastIndexOf('/') + 1);
7679 buildings[i] = buildings[i].substr(0, buildings[i].indexOf('.'));
7680 });
7681
7682 var goners = $();
7683 var opti = $("#buildingOpti").is(":checked");
7684 overviewTable.find("tr:gt(0)").each(function () {
7685 var isOk = true;
7686 $(this).find("td:gt(3)").each(function (i, v) {
7687 var range = user_data.buildings[buildings[i]];
7688 if (range != undefined) {
7689 var text = parseInt($(this).text(), 10);
7690 if (text < range[0]) {
7691 $(this).css("background-color", user_data.colors.error);
7692 isOk = false;
7693 } else if (text > range[1] && !opti) {
7694 $(this).css("background-color", user_data.colors.good);
7695 isOk = false;
7696 } else
7697 $(this).css("background-color", "");
7698 }
7699 });
7700 if (hideRows && isOk) {
7701 goners = goners.add($(this));
7702 $("input:first", $(this)).val("");
7703 }
7704 });
7705 goners.remove();
7706 }
7707
7708 $("#buildingHighlight").click(function () {
7709 trackClickEvent("TableHighlight");
7710 filterBuildings(function (cell, isOk) {
7711 cell.css("background-color", isOk ? "" : user_data.colors.neutral);
7712 }, false);
7713 });
7714
7715 $("#buildingFilter").click(function () {
7716 trackClickEvent("TableRemove");
7717 filterBuildings(function (cell, isOk) {
7718 cell.css("background-color", isOk ? "" : user_data.colors.neutral);
7719 }, true);
7720 });
7721 } catch (e) { handleException(e, "overview-buildings"); }
7722 //console.timeEnd("overview-buildings");
7723 }());
7724 }
7725 // TECHS OVERVIEW // SMEDERIJ OVERVIEW // SMITHY OVERVIEW
7726 else if (location.href.indexOf('mode=tech') > -1) {
7727 (function() {
7728 //console.time("overview-techs");
7729 try {
7730 overviewTable = $("#techs_table");
7731 tableHandler.init("techs_table");
7732
7733 // Highlight everything not conform usersettings
7734 if (world_config.smithyLevels) {
7735 var menu = "<table class='vis' width='100%'>";
7736 menu += "<tr><th>";
7737 menu += "<select id='groupType'>";
7738 $.each(user_data.smithy, function (i, v) {
7739 menu += "<option value=" + i + ">" + v[0] + "</option>";
7740 });
7741 menu += "</select>";
7742 menu += "<input type=checkbox id=buildingOpti> " + trans.sp.smithOverview.optimistic + " ";
7743 menu += "<input type=button id=smithyHighlight value='" + trans.sp.smithOverview.mark + "'>";
7744 menu += "<input type=button id=smithyFilter value='" + trans.sp.smithOverview.filter + "'>";
7745 menu += "</th></tr></table>";
7746 $("#techs_table").before(menu);
7747
7748 function filterTechs(cellAction, hideRows) {
7749 var goners = $();
7750 var opti = $("#buildingOpti").is(":checked");
7751 var def = user_data.smithy[$("#groupType").val()][1];
7752 $("#techs_table").find("tr:gt(0)").each(function () {
7753 var isOk = true;
7754 $(this).find("td:gt(2)").each(function (i, v) {
7755 var range = def[world_data.units[i]];
7756 if (i < world_data.units.length && range != undefined) {
7757 var text = parseInt($(this).text(), 10);
7758 if (text == '') {
7759 text = 0;
7760 }
7761 if (text < range[0]) {
7762 $(this).css("background-color", user_data.colors.error);
7763 isOk = false;
7764 }
7765 else if (text > range[1] && !opti) {
7766 $(this).css("background-color", user_data.colors.good);
7767 isOk = false;
7768 } else {
7769 $(this).css("background-color", "");
7770 }
7771 }
7772 });
7773 if (hideRows && isOk) {
7774 goners = goners.add($(this));
7775 $("input:first", $(this)).val("");
7776 }
7777 });
7778 goners.remove();
7779 }
7780
7781 $("#smithyHighlight").click(function () {
7782 trackClickEvent("TableHighlight");
7783 filterTechs(function (cell, isOk) {
7784 cell.css("background-color", isOk ? "" : user_data.colors.neutral);
7785 }, false);
7786 });
7787
7788 $("#smithyFilter").click(function () {
7789 trackClickEvent("TableRemove");
7790 filterTechs(function (cell, isOk) {
7791 cell.css("background-color", isOk ? "" : user_data.colors.neutral);
7792 }, true);
7793 });
7794 }
7795 } catch (e) { handleException(e, "overview-techs"); }
7796 //console.timeEnd("overview-techs");
7797 }());
7798 }
7799 // GROUPS OVERVIEW
7800 else if (location.href.indexOf('mode=groups') > -1) {
7801 (function() {
7802 //console.time("overview-groups");
7803 try {
7804 overviewTable = $("#group_assign_table");
7805 tableHandler.init("group_assign_table", {
7806 hasBottomTotalRow: true
7807 });
7808
7809 // TODO: edit groups: make div floatable and remember position
7810 var menu = "";
7811 menu += "<table class=vis width='100%'><tr><th>";
7812
7813 menu += trans.sp.defOverview.village + " <input type=text size=5 id=defFilterDistVillage value=''>";
7814 menu += "<select id=defFilterDistType>";
7815 menu += "<option value=1 selected>" + trans.sp.all.closer + "</option><option value=-1>" + trans.sp.all.further + "</option></select>";
7816 menu += " F <input type=text size=3 id=defFilterDistFields value=" + user_data.restack.fieldsDistanceFilterDefault + ">";
7817 menu += "<input type=button id=defFilterDist value='" + trans.sp.defOverview.distFilter + "' title='" + trans.sp.defOverview.distFilterTooltip + "'>";
7818
7819 menu += " | ";
7820 menu += "<input type=button id=attackFilter value='" + trans.sp.defOverview.filterUnderAttack + "'>";
7821
7822 menu += "<br>";
7823
7824 menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": ";
7825
7826 menu += " <input type=text size=12 id=defFilterTextValue value=''>";
7827 menu += "<input type=button id=defFilterText value='" + trans.sp.groups.villageFilter + "'>";
7828
7829 menu += " <input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>";
7830
7831 menu += " <input type=textbox size=3 id=defFilterAmountText maxlength=2><input type=button id=defFilterAmount value='" + trans.sp.groups.amountFilter + "'>";
7832 menu += " <input type=textbox size=4 id=defFilterPointsText maxlength=5><input type=button id=defFilterPoints value='" + trans.sp.groups.pointsFilter + "'>";
7833 menu += " <input type=textbox size=5 id=defFilterFarmText maxlength=6><input type=button id=defFilterFarm value='" + trans.tw.all.farm + "'>";
7834
7835 menu += " <input type=text size=12 id=defFilterGroupValue value=''>";
7836 menu += "<input type=button id=defFilterGroup value='" + trans.sp.groups.groupNameFilter + "'>";
7837 menu += "</th></tr></table>";
7838
7839 var selectAllRow = $("#group_assign_table tr:last");
7840 $("#group_assign_table").before(menu).after("<table class=vis width='100%'><tr><th><input type=checkbox id=selectAllVisible> " + selectAllRow.text() + "</th></tr></table>");
7841 selectAllRow.remove();
7842
7843 // Select all checkbox behavior
7844 $("#selectAllVisible").change(function () {
7845 var isChecked = $(this).is(":checked");
7846 $("#group_assign_table input:checked").prop("checked", false);
7847 if (isChecked) {
7848 $("#group_assign_table input[type='checkbox']").not(":hidden").prop("checked", true);
7849 }
7850
7851 //$("#group_assign_table input:hidden").prop("checked", false);
7852 //$("#group_assign_table input:visible").prop("checked", isChecked);
7853 });
7854
7855 // Change tooltips when clicking the reverse filter checkbox
7856 $("#defReverseFilter").change(function () {
7857 var isChecked = $(this).is(":checked");
7858 var defTrans = trans.sp.groups;
7859 $("#defFilterText").attr("title", isChecked ? defTrans.villageFilterTitle : defTrans.villageFilterTitleRev);
7860 $("#defFilterContinent").attr("title", isChecked ? trans.sp.commands.continentFilterTooltip : trans.sp.commands.continentFilterTooltipReverse);
7861
7862 $("#defFilterAmount").attr("title", isChecked ? defTrans.amountFilterTitle : defTrans.amountFilterTitleRev);
7863 $("#defFilterPoints").attr("title", isChecked ? defTrans.pointsFilterTitle : defTrans.pointsFilterTitleRev);
7864 $("#defFilterFarm").attr("title", isChecked ? defTrans.farmFilterTitle : defTrans.farmFilterTitleRev);
7865
7866 $("#defFilterGroup").attr("title", isChecked ? defTrans.groupNameFilterTitle : defTrans.groupNameFilterTitleRev);
7867 });
7868 $("#defReverseFilter").change();
7869
7870 /**
7871 * Perform a filter on the groups table rows
7872 * @param {function} filterStrategy jQuery object with the row is the first parameter
7873 * @param {boolean} reverseFilter
7874 * @param {function} [keepRowStrategy]
7875 * @param {*} [tag] passed as second param to filterStrategy and keepRowStrategy
7876 */
7877
7878 function filterGroupRows(filterStrategy, reverseFilter, keepRowStrategy, tag) {
7879 if (typeof reverseFilter === "undefined") {
7880 reverseFilter = !$("#defReverseFilter").is(":checked");
7881 }
7882
7883 var goners = $();
7884 var totalVisible = 0;
7885 $("#group_assign_table tr:gt(0)").each(function () {
7886 var row = $(this);
7887 if (row.is(":visible")) {
7888 if (!reverseFilter != !filterStrategy(row, tag)) {
7889 goners = goners.add(row);
7890 //$("input:eq(1)", row).val("");
7891 } else {
7892 totalVisible++;
7893 if (keepRowStrategy != null) {
7894 keepRowStrategy(row, tag);
7895 }
7896 }
7897 }
7898 });
7899 goners.remove();
7900 var firstHeaderCell = $("#group_assign_table th:first");
7901 var firstHeaderCellHtml = firstHeaderCell.html();
7902 firstHeaderCell.html(firstHeaderCellHtml.substr(0, firstHeaderCellHtml.lastIndexOf(" ")) + " (" + totalVisible + ")");
7903 }
7904
7905 // Filter on distance to given village
7906 $("#defFilterDist").click(function () {
7907 var targetVillage = getVillageFromCoords($("#defFilterDistVillage").val(), true);
7908 if (!targetVillage.isValid) {
7909 alert(trans.sp.defOverview.distanceToVillageNoneEntered);
7910 return;
7911 }
7912
7913 trackClickEvent("FilterDistance");
7914 var reverseFilter = !($("#defFilterDistType").val() != "-1");
7915 var maxDistance = parseInt($("#defFilterDistFields").val(), 10);
7916
7917 var isAlreadyVisible = $("#filterContext").size() == 1;
7918 var distanceHeader =
7919 trans.sp.defOverview.distanceToVillage.replace(
7920 "{0}",
7921 "<a href='"
7922 + getUrlString("&screen=map&x=" + targetVillage.x + "&y=" + targetVillage.y + "'>")
7923 + targetVillage.coord + "</a>");
7924
7925 if (isAlreadyVisible) {
7926 $("#filterContext").html(distanceHeader);
7927 } else {
7928 $("#group_assign_table").find("th:first").after("<th><span id=filterContext>" + distanceHeader + "</span> <img src='graphic/oben.png' class=sortDistance direction=up> <img src='graphic/unten.png' class=sortDistance direction=down></th>");
7929 $(".sortDistance").click(function () {
7930 if ($(this).attr("direction") == "up") {
7931 $("#group_assign_table").find("tr:gt(0)").filter(":visible").sortElements(function (a, b) {
7932 return parseInt($(a).attr("fieldAmount"), 10) > parseInt($(b).attr("fieldAmount"), 10) ? 1 : -1;
7933 });
7934 } else {
7935 $("#group_assign_table").find("tr:gt(0)").filter(":visible").sortElements(function (a, b) {
7936 return parseInt($(a).attr("fieldAmount"), 10) < parseInt($(b).attr("fieldAmount"), 10) ? 1 : -1;
7937 });
7938 }
7939 });
7940 }
7941
7942 filterGroupRows(
7943 function (row, tag) {
7944 var compareVillage = getVillageFromCoords(row.find("td:first").text());
7945 tag.distance = getDistance(targetVillage.x, compareVillage.x, targetVillage.y, compareVillage.y, 'ram').fields;
7946 return tag.distance > maxDistance;
7947
7948 }, reverseFilter,
7949 function (mainRow, tag) {
7950 mainRow.attr("fieldAmount", tag.distance);
7951 if (!isAlreadyVisible) {
7952 mainRow.find("td:first").after("<td><b>" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + "</b></td>");
7953 } else {
7954 mainRow.find("td:eq(1)").html("<b>" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + "</b>");
7955 }
7956 }, { distance: 0 });
7957 });
7958
7959 // Filter on incoming attacks
7960 $("#attackFilter").click(function () {
7961 trackClickEvent("FilterUnderAttack");
7962 filterGroupRows(function (row) {
7963 return $('td:first:not(:has(img[title=\'' + trans.tw.command.attack + '\']))', row).size() == 0;
7964 });
7965 });
7966
7967 // filter on village name
7968 $("#defFilterText").click(function () {
7969 trackClickEvent("FilterText");
7970 var compareTo = $("#defFilterTextValue").val().toLowerCase();
7971 if (compareTo.length > 0) {
7972 filterGroupRows(function (row) {
7973 return row.find("td:first").text().toLowerCase().indexOf(compareTo) != -1;
7974 });
7975 }
7976 });
7977
7978 // filter on group names
7979 $("#defFilterGroup").click(function () {
7980 trackClickEvent("FilterGroupName");
7981 var compareTo = $("#defFilterGroupValue").val().toLowerCase();
7982 if (compareTo.length > 0) {
7983 filterGroupRows(function (row) {
7984 return row.find("td:eq(4)").text().toLowerCase().indexOf(compareTo) != -1;
7985 });
7986 }
7987 });
7988
7989 $("#defFilterContinent").click(function () {
7990 trackClickEvent("FilterContinent");
7991 var compareTo = parseInt($("#defFilterContinentText").val(), 10);
7992 if (compareTo >= 0) {
7993 compareTo = compareTo.toString();
7994 filterGroupRows(function (row) {
7995 var villageContinent = $.trim(row.find("td:first").text()),
7996 continentStart = villageContinent.lastIndexOf(trans.tw.all.continentPrefix);
7997
7998 return villageContinent.substr(continentStart + 1) === compareTo;
7999 });
8000 }
8001 });
8002
8003 // filter on # groups
8004 $("#defFilterAmount").click(function (){
8005 trackClickEvent("FilterGroupCount");
8006 var compareTo = parseInt($("#defFilterAmountText").val(), 10);
8007 if (compareTo >= 0) {
8008 if (!$("#defReverseFilter").is(":checked")) {
8009 filterGroupRows(
8010 function (row) {
8011 return parseInt(row.find("td:eq(1)").text(), 10) > compareTo;
8012 },
8013 false);
8014 } else {
8015 filterGroupRows(
8016 function (row) {
8017 return parseInt(row.find("td:eq(1)").text(), 10) < compareTo;
8018 },
8019 false);
8020 }
8021 }
8022 });
8023
8024 $("#defFilterPoints").click(function () {
8025 trackClickEvent("FilterPoints");
8026 var compareTo = parseInt($("#defFilterPointsText").val(), 10);
8027 if (compareTo >= 0) {
8028 filterGroupRows(function (row) {
8029 return parseInt(row.find("td:eq(2)").text().replace(".", ""), 10) < compareTo;
8030 });
8031 }
8032 });
8033
8034 $("#defFilterFarm").click(function () {
8035 trackClickEvent("FilterFarm");
8036 var compareTo = parseInt($("#defFilterFarmText").val(), 10);
8037 if (compareTo >= 0) {
8038 filterGroupRows(function (row) {
8039 var farmValue = row.find("td:eq(3)").text();
8040 farmValue = parseInt(farmValue.substr(0, farmValue.indexOf("/")), 10);
8041 return farmValue < compareTo;
8042 });
8043 }
8044 });
8045 } catch (e) { handleException(e, "overview-groups"); }
8046 //console.timeEnd("overview-groups");
8047 }());
8048 }
8049 // SUPPORT OVERVIEW
8050 else if (location.href.indexOf('type=support_detail') > -1
8051 || location.href.indexOf('type=away_detail') > -1) {
8052
8053 (function() {
8054 //console.time("overview-supportdetail");
8055 try {
8056 overviewTable = $("#units_table");
8057 tableHandler.init("units_table", {
8058 hasBottomTotalRow: true
8059 });
8060
8061 /**
8062 * true: we're on the support_detail page. false: away_detail page
8063 * @type {boolean}
8064 */
8065 var isSupport = location.href.indexOf('type=support_detail') > -1;
8066
8067 /**
8068 * Sets the correct rowcount in the first header cell
8069 */
8070 function setTotalCount() {
8071 $("th:first", overviewTable).text(
8072 trans.sp.defOverview.totalVillages.replace(
8073 "{0}",
8074 $("tr.units_away", overviewTable).size()));
8075 }
8076
8077
8078 var menu = "<table class='vis' width='100%'>";
8079 menu += "<tr><th width='1%' nowrap>";
8080 menu += "<input type=button id=defTotals value='" + trans.sp.defOverview.stackButton + "' title='" + trans.sp.defOverview.stackTooltip + "'>";
8081 menu += "<input type=button id=defHideEmpty value='" + trans.sp.defOverview.filterNoSupport + "' title='" + trans.sp.defOverview.filterNoSupportTooltip + "'> ";
8082
8083 menu += "</th><th width='96%' nowrap>";
8084 menu += "<input type=button id=attackFilter value='" + trans.sp.defOverview.filterUnderAttack + "'>";
8085 if (!isSupport) {
8086 menu += " <input type=button id=defFilterBarbarian value='" + trans.sp.defOverview.barbarianFilter + "' title='" + trans.sp.defOverview.barbarianFilterTooltip + "'>";
8087 } else {
8088 menu += "</th><th width='1%' nowrap>";
8089 menu += "<input type=text size=8 id=defFilterTotalPopValue value='" + user_data.restack.defaultPopulationFilterAmount + "'>";
8090 menu += "<select id=defFilterTotalPopComparer>";
8091 menu += "<option value=-1>" + trans.sp.all.less + "</option><option value=1 selected>" + trans.sp.all.more + "</option></select>";
8092 menu += "<input type=button id=defFilterTotalPop value='" + trans.sp.defOverview.stackFilter + "' title='" + trans.sp.defOverview.stackFilterTooltip + "'>";
8093
8094 menu += "</th><th width='1%' nowrap>";
8095 menu += trans.sp.defOverview.village + " <input type=text size=5 id=defFilterDistVillage value=''>";
8096 menu += "<select id=defFilterDistType>";
8097 menu += "<option value=1 selected>" + trans.sp.all.closer + "</option><option value=-1>" + trans.sp.all.further + "</option></select>";
8098 // TODO: untranslated F(ields)
8099 menu += " F <input type=text size=3 id=defFilterDistanceValue value=" + user_data.restack.fieldsDistanceFilterDefault + ">";
8100 menu += "<input type=button id=defFilterDist value='" + trans.sp.defOverview.distFilter + "' title='" + trans.sp.defOverview.distFilterTooltip + "'>";
8101
8102 menu += "</th><th width='1%' nowrap>";
8103 menu += " <input type=text size=8 id=defRestackTo value=" + user_data.restack.to + "> <input type=button id=defRestack value='" + trans.sp.defOverview.stackBBCodes + "' title='" + trans.sp.defOverview.stackBBCodesTooltip + "'>";
8104 //menu += "</th></tr></table>";
8105 }
8106
8107 menu += "</th></tr></table>";
8108 menu += "<table class='vis' width='100%'><tr><th width='1%' nowrap>";
8109 menu += isSupport ? trans.sp.defOverview.extraFiltersSupport : trans.sp.defOverview.extraFiltersDefense;
8110
8111 menu += "</th><th width='1%' nowrap>";
8112 menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.defOverview.extraFiltersReverse + "'" + (user_data.restack.filterReverse ? " checked" : "") + "> " + trans.sp.defOverview.extraFiltersInfo;
8113
8114 menu += "</th><th width='1%' nowrap>";
8115 menu += "<input type=text size=3 id=defFilterDistanceValue value=" + user_data.restack.fieldsDistanceFilterDefault + "> <input type=button id=defFilterDistance value='" + trans.sp.defOverview.distFilter2 + "'>";
8116
8117 menu += "</th><th width='1%' nowrap>";
8118 menu += " <span style='background-color: #ecd19a; border: 1px solid black' id='unitFilterBox'>";
8119 menu += " <img src='graphic/unit/unit_snob.png' id=filtersnob> <img src='graphic/unit/unit_spy.png' id=filterspy>";
8120 menu += " <img src='graphic/buildings/barracks.png' id=filterAttack> <img src='graphic/unit/def.png' id=filterDefense> <img id=filterSupport src='graphic/command/support.png'> ";
8121 menu += "</span> ";
8122
8123 menu += "</th><th width='96%' nowrap>";
8124 menu += "<input type=text size=12 id=defFilterTextValue value=''>";
8125 menu += "<input type=button id=defFilterText value='" + trans.sp.defOverview.freeTextFilter + "'>";
8126 menu += "</th></tr></table>";
8127
8128 overviewTable.before(menu);
8129
8130 $("#defReverseFilter").change(function () {
8131 var isChecked = $(this).is(":checked");
8132 var defTrans = trans.sp.defOverview;
8133 $("#unitFilterBox").find("img:eq(0)").attr("title", isChecked ? defTrans.nobleFilter : defTrans.nobleFilterRev);
8134 $("#unitFilterBox").find("img:eq(1)").attr("title", isChecked ? defTrans.spyFilter : defTrans.spyFilterRev);
8135 $("#unitFilterBox").find("img:eq(2)").attr("title", isChecked ? defTrans.attackFilter : defTrans.attackFilterRev);
8136 $("#unitFilterBox").find("img:eq(3)").attr("title", isChecked ? defTrans.supportFilter : defTrans.supportFilterRev);
8137
8138 $("#unitFilterBox").find("img:eq(4)").attr("title", (isSupport ? defTrans.otherPlayerFilterFrom : defTrans.otherPlayerFilterTo).replace("{action}", isChecked ? defTrans.otherPlayerFilterShow : defTrans.otherPlayerFilterHide));
8139 $("#defFilterText").attr("title", defTrans.freeTextFilterTooltip.replace("{villageType}", isSupport ? defTrans.filterTooltipVillageTypeSupporting : defTrans.filterTooltipVillageTypeSupported).replace("{filterType}", isChecked ? defTrans.freeTextFilterTooltipFilterTypeWith : defTrans.freeTextFilterTooltipFilterTypeWithout));
8140 $("#defFilterDistance").attr("title", defTrans.distanceFilterTooltip.replace("{villageType}", isSupport ? defTrans.filterTooltipVillageTypeSupporting : defTrans.filterTooltipVillageTypeSupported).replace("{filterType}", !isChecked ? defTrans.distanceFilterTooltipFilterTypeCloser : defTrans.distanceFilterTooltipFilterTypeFurther));
8141 });
8142 $("#defReverseFilter").change();
8143 // This file contains the filters on the FIRST row of the menu
8144
8145 // UNDER ATTACK FILTER
8146 $("#attackFilter").click(function () {
8147 trackClickEvent("FilterAttack");
8148 var reverseFilter = true; // never reverse this filter!
8149
8150 var filterStrategy =
8151 function (row) {
8152 return $('td:first:not(:has(img[title=\'' + trans.tw.command.attack + '\']))', row).size() == 0;
8153 };
8154
8155 var lastRow = $("tr:last", overviewTable).get(0);
8156 var goners = $();
8157 $("tr.units_away", overviewTable).each(function () {
8158 var self = $(this);
8159 if (!reverseFilter != !filterStrategy(self)) {
8160 goners = goners.add(self);
8161
8162 var nextRow = self.next();
8163 while (!nextRow.hasClass("units_away") && nextRow.get(0) !== lastRow) {
8164 goners = goners.add(nextRow);
8165 nextRow = nextRow.next();
8166 }
8167 }
8168 });
8169 goners.remove();
8170 setTotalCount();
8171
8172 // this is already done in the code above :)
8173 //$("#defHideEmpty").click();
8174
8175 if (user_data.restack.calculateDefTotalsAfterFilter
8176 && !$("#defTotals").is(":disabled")) {
8177
8178 $("#defTotals").click();
8179 }
8180 });
8181
8182
8183
8184 /**
8185 * Performs a filter on the OWN villages (ie not the villages supporting the OWN villages)
8186 * The 'row' parameter are the rows with class grandTotal. These are the rows that get added after (below) all
8187 * supporting os rows when the total def is being calculated.
8188 * @param {function} filterStrategy return a boolean to filter all rows for the OWN away. first parameter is the (jQuery) row with the OWN village
8189 * @param {boolean} reverseFilter reverse the above strategy
8190 * @param {function} [survivorRowStrategy] execute on all rows that are not being removed (gets passed the row and optional tag)
8191 * @param {*} [tag] this value is passed onto filterStrategy and survivorRowStrategy as the second parameter (row is the first param)
8192 */
8193 function filterMainRows(filterStrategy, reverseFilter, survivorRowStrategy, tag) {
8194 if (!$("#defTotals").is(":disabled")) {
8195 $("#defTotals").click();
8196 }
8197
8198 /*var goners = $();
8199 $("tr.grandTotal", overviewTable).each(function () {
8200 var self = $(this),
8201 prev;
8202 if (!reverseFilter != !filterStrategy(self, tag)) {
8203 goners = goners.add(self).add(self.next());
8204
8205 prev = self.prev();
8206 while (!prev.hasClass("units_away")) {
8207 goners = goners.add(prev);
8208 prev = prev.prev();
8209 }
8210
8211 goners = goners.add(prev);
8212 } else if (survivorRowStrategy != null) {
8213 prev = self.prev();
8214 while (!prev.hasClass("units_away")) {
8215 prev = prev.prev();
8216 }
8217 survivorRowStrategy(prev, tag);
8218 }
8219 });
8220 goners.remove();
8221 setTotalCount();*/
8222
8223 var lastRow = $("tr:last", overviewTable).get(0);
8224 var goners = $();
8225 $("tr.units_away", overviewTable).each(function () {
8226 var self = $(this);
8227 if (!reverseFilter != !filterStrategy(self, tag)) {
8228 goners = goners.add(self);
8229
8230 var nextRow = self.next();
8231 while (!nextRow.hasClass("units_away") && nextRow.get(0) !== lastRow) {
8232 goners = goners.add(nextRow);
8233 nextRow = nextRow.next();
8234 }
8235 }
8236 else if (survivorRowStrategy != null) {
8237 /*prev = self.prev();
8238 while (!prev.hasClass("units_away")) {
8239 prev = prev.prev();
8240 }*/
8241 survivorRowStrategy(self, tag);
8242 }
8243 });
8244 goners.remove();
8245 setTotalCount();
8246 }
8247
8248
8249
8250 // filter the OWN villages on less/more population (requires total calculation)
8251 $("#defFilterTotalPop").click(function () {
8252 trackClickEvent("FilterFarm");
8253 var reverseFilter = $("#defFilterTotalPopComparer").val() != "-1";
8254 var compareTo = parseInt($("#defFilterTotalPopValue").val(), 10);
8255
8256 filterMainRows(
8257 //q(row.attr("village") + "is:" + row.attr("population"));
8258 function (row) { return (parseInt(row.attr("population"), 10) > compareTo); },
8259 reverseFilter);
8260 });
8261
8262 // filter the OWN villages on less/more distance to given coordinates (requires total calculation)
8263 $("#defFilterDist").click(function () {
8264 var targetVillage = getVillageFromCoords($("#defFilterDistVillage").val(), true);
8265 if (!targetVillage.isValid) {
8266 alert(trans.sp.defOverview.distanceToVillageNoneEntered);
8267 return;
8268 }
8269
8270 trackClickEvent("FilterDistanceToX");
8271 var reverseFilter = !($("#defFilterDistType").val() != "-1");
8272 var maxDistance = parseInt($("#defFilterDistanceValue").val(), 10);
8273
8274 // Change text of th cell to 'distance to ' + given village
8275 overviewTable.find("th:eq(1)").html(
8276 trans.sp.defOverview.distanceToVillage.replace(
8277 "{0}",
8278 "<a href='"
8279 + getUrlString("&screen=map&x=" + targetVillage.x + "&y=" + targetVillage.y + "'>")
8280 + targetVillage.coord + "</a>"));
8281
8282 filterMainRows(
8283 function (row, tag) {
8284 var compareVillage = getVillageFromCoords(row.attr("village"));
8285 tag.distance = getDistance(targetVillage.x, compareVillage.x, targetVillage.y, compareVillage.y, 'ram').fields;
8286 return tag.distance > maxDistance;
8287 },
8288 reverseFilter,
8289 function (mainRow, tag) {
8290 // Adds the distance between OWN village and the user given coordinates
8291 mainRow.find("td:eq(1)").html("<b>" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + "</b>");
8292 },
8293 { distance: 0 });
8294 });
8295 // Calculate villages that don't have x population defense
8296 // and create BBcodes textarea for it
8297 $("#defRestack").click(function () {
8298 trackClickEvent("BBCodeOutput");
8299 if (!$("#defTotals").attr("disabled")) {
8300 $("#defTotals").click();
8301 }
8302
8303 var restackTo = parseInt($("#defRestackTo").val(), 10);
8304 var counter = 0;
8305
8306 var request = "";
8307 $("tr.grandTotal", overviewTable).each(function () {
8308 var self = $(this);
8309 var total = parseInt(self.attr('population'), 10);
8310 if (restackTo - total > user_data.restack.requiredDifference) {
8311 var villageCoords = self.attr("village");
8312 counter++;
8313 request += counter + "[village]" + villageCoords + "[/village] (" + parseInt((restackTo - total) / 1000, 10) + trans.sp.defOverview.thousandSuffix + ")\n";
8314 }
8315 });
8316
8317 if ($("#textsArea").size() == 0) {
8318 $(this).parent().parent().parent().parent().after(
8319 "<table class='vis' width='100%'><tr>"
8320 + "<td id=textsArea width='50%' valign='top'></td>"
8321 + "<td id='extraTextsArea' width='50%' valign='top'>"
8322 + trans.sp.defOverview.freeText
8323 + "<br><textarea cols=50 rows=9></textarea></td>"
8324 + "</tr></table>");
8325
8326 $("#textsArea").parent().after("<tr><td colspan='2'><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea></td></tr>");
8327 } else {
8328 $("#textsArea").html("");
8329 }
8330
8331 var title = trans.sp.troopOverview.restackTitle
8332 .replace("{to}", parseInt(restackTo / 1000, 10))
8333 .replace("{requiredDiff}", parseInt(user_data.restack.requiredDifference / 1000, 10));
8334
8335 $("#textsArea").append(title + "<br><textarea cols=50 rows=10 id=restackArea>" + request + "</textarea>");
8336
8337 $("#closeTextsArea").click(function() {
8338 $("#textsArea").parent().parent().remove();
8339 });
8340 });
8341 // Check all villages checkbox replacement
8342 $("input.selectAll").replaceWith("<input type=checkbox id=selectAllVisible>");
8343 $("#selectAllVisible").change(function () {
8344 var isChecked = $(this).is(":checked");
8345
8346 $("input.village_checkbox:hidden", overviewTable).prop("checked", false);
8347 $("input.village_checkbox:visible", overviewTable).prop("checked", isChecked);
8348 });
8349
8350
8351 // Hide all OWN rows/villages that don't have any support rows anymore
8352 $("#defHideEmpty").click(function () {
8353 trackClickEvent("FilterEmpty");
8354 var goners = $();
8355 if ($("#defTotals").is(":disabled")) {
8356 $("tr.units_away", overviewTable).each(function () {
8357 var mainRow = $(this),
8358 nextRow = mainRow.next();
8359
8360 if (nextRow.hasClass("grandTotal")) {
8361 goners = goners.add(mainRow).add(nextRow.next()).add(nextRow);
8362 }
8363 else if (nextRow.hasClass("units_away")) {
8364 goners = goners.add(mainRow);
8365 }
8366 });
8367 } else {
8368 $("tr.units_away", overviewTable).each(function () {
8369 var mainRow = $(this),
8370 nextRow = mainRow.next();
8371
8372 if (nextRow.hasClass("units_away")) {
8373 goners = goners.add(mainRow);
8374 }
8375 });
8376 }
8377
8378 goners.remove();
8379 setTotalCount();
8380 });
8381
8382
8383 // Calculate the amount of def in each village
8384 // Give sensible background row colors
8385 // Add attributes to the grandTotal class rows 'village' (coords) and 'population'
8386 // Add attribute 'distance' the distance between OWN and supporting villages, in fields
8387 $("#defTotals").click(function () {
8388 trackClickEvent("FilterTotalDef");
8389 $(this).attr("disabled", true);
8390 var rowColor = 0;
8391 var goners = $();
8392 overviewTable.find("tr.units_away").each(function () {
8393 var self = $(this);
8394 var firstCell = self.find("td:first");
8395 var villageCoord = getVillageFromCoords(firstCell.text().replace(firstCell.find(".quickedit-label").attr("data-text"), ""));
8396
8397 // ensure row color swapping for each own village
8398 rowColor++;
8399 if (rowColor % 2 == 1) {
8400 self.removeClass("row_a").addClass("row_b");
8401 } else {
8402 self.removeClass("row_b").addClass("row_a");
8403 }
8404
8405 // village attribute both to .units_away and .grandTotal rows ;)
8406 self.attr("village", villageCoord.coord);
8407
8408 var nextRow = self.next();
8409 if (nextRow.hasClass("units_away")) {
8410 if (user_data.restack.removeRowsWithoutSupport) {
8411 goners = goners.add(self);
8412 }
8413 } else {
8414 // calculate total support
8415 var grandTotal = 0;
8416 var totals = [];
8417 while (nextRow.hasClass("row_a") || nextRow.hasClass("row_b")) {
8418 // supporting rows loop
8419 var total = 0;
8420 $("td:gt(0)", nextRow).each(function (i) {
8421 // total support per supporting village
8422 var cellSelf = $(this);
8423 var cellContent = $.trim(cellSelf.text());
8424 if (!(cellContent == '0' || i >= world_data.unitsPositionSize.length)) {
8425 total += cellContent * world_data.unitsPositionSize[i];
8426 if (totals[i] == undefined) {
8427 totals[i] = parseInt(cellContent, 10);
8428 } else {
8429 totals[i] += parseInt(cellContent, 10);
8430 }
8431 }
8432 });
8433 grandTotal += total;
8434 $("td:eq(" + (world_data.unitsPositionSize.length + 1) + ")", nextRow).text(formatNumber(total));
8435
8436 // print distance between own village
8437 var supportedCell = $("td:first", nextRow);
8438 var supportedVillage = getVillageFromCoords(supportedCell.text());
8439 var distance = parseInt(getDistance(supportedVillage.x, villageCoord.x, supportedVillage.y, villageCoord.y, 'ram').fields, 10);
8440 //supportedCell.html(supportedCell.html() + ' <b>' + trans.sp.all.fieldsSuffix.replace("{0}", distance) + '</b>');
8441 supportedCell.append(' <b>' + trans.sp.all.fieldsSuffix.replace("{0}", distance) + '</b>');
8442 nextRow.attr("distance", distance);
8443
8444 if (rowColor % 2 == 1) {
8445 nextRow.removeClass("row_a").addClass("row_b");
8446 } else {
8447 nextRow.removeClass("row_b").addClass("row_a");
8448 }
8449
8450 nextRow = nextRow.next();
8451 }
8452
8453 // row colors for the support villages
8454 if (rowColor % 2 == 1) {
8455 nextRow.removeClass("row_a").addClass("row_b");
8456 } else {
8457 nextRow.removeClass("row_b").addClass("row_a");
8458 }
8459
8460 var troopCells = "";
8461 for (var i = 0; i < world_data.unitsPositionSize.length; i++) {
8462 if (typeof totals[i] !== 'undefined') {
8463 troopCells += "<td>" + formatNumber(totals[i]) + "</td>";
8464 } else {
8465 troopCells += "<td><span class=hidden>0</span></td>";
8466 }
8467 }
8468
8469 self.attr("population", grandTotal);
8470 var color = getStackColor(grandTotal);
8471 color = "<td style='background-color: " + color + "; border:1px solid black'>" + formatNumber(grandTotal) + "</td>";
8472
8473 nextRow.before("<tr class='grandTotal " + (rowColor % 2 == 1 ? "row_b" : "row_a") + "' village='" + villageCoord.coord + "' population='" + grandTotal + "'><td> </td><td>" + (isSupport ? trans.sp.defOverview.totalFromOtherVillages : trans.sp.defOverview.totalInOtherVillages) + "</td>" + troopCells + color + "</tr><tr height=10></tr>");
8474 }
8475 });
8476
8477 goners.remove();
8478 });
8479 // This file contains the filters on the SECOND row of the menu
8480
8481 /**
8482 * Loops over all supporting rows and removes the rows that fail the filterStrategy predicate. Where the
8483 * filterMainRows function loops over the OWN villages, this one loops over all the others.
8484 * @param {Function} filterStrategy gets each jQuery row that represents a supporting village passed as parameter
8485 * @param {string=after} [calcDefTotalsTime] is "before" or "after". before if it uses row attributes set by #defTotals
8486 */
8487 function filterTable(filterStrategy, calcDefTotalsTime) {
8488 if (typeof calcDefTotalsTime === 'undefined') {
8489 calcDefTotalsTime = "after";
8490 }
8491 if (calcDefTotalsTime === "before" && !$("#defTotals").is(":disabled")) {
8492 $("#defTotals").click();
8493 }
8494 var totalDefCalced = $("#defTotals").is(":disabled");
8495
8496 var reverseFilter = $("#defReverseFilter").is(":checked");
8497 var goners = $();
8498 $("tr", overviewTable).slice(1).each(function () {
8499 var self = $(this);
8500 if ((totalDefCalced && self.attr("distance"))
8501 || (!totalDefCalced && (self.hasClass("row_a") || self.hasClass("row_b")))) {
8502
8503 if (!reverseFilter != !filterStrategy(self)) {
8504 goners = goners.add(self);
8505 }
8506 }
8507 });
8508 goners.remove();
8509 setTotalCount();
8510 if (user_data.restack.autohideWithoutSupportAfterFilter) {
8511 $("#defHideEmpty").click();
8512 }
8513
8514 if (user_data.restack.calculateDefTotalsAfterFilter
8515 && calcDefTotalsTime === "after"
8516 && !$("#defTotals").is(":disabled")) {
8517
8518 $("#defTotals").click();
8519 }
8520 }
8521
8522
8523
8524
8525
8526 // NOBLES and SCOUTS
8527 $("#filtersnob, #filterspy").click( function () {
8528 trackClickEvent("FilterSnobOrSpy");
8529 var position = $.inArray($(this).attr("id").substr(6), world_data.units) + 1;
8530 filterTable(function (row) {
8531 return row.find("td").eq(position).text() != "0";
8532 });
8533 });
8534
8535 // OTHER PLAYERS SUPPORT
8536 $("#filterSupport").click( function () {
8537 trackClickEvent("FilterSupport");
8538 filterTable(function (row) {
8539 return row.find("td:first a").length != 2;
8540 });
8541 });
8542
8543 // DEFENSIVE & OFFENSIVE UNITS
8544 $("#filterAttack, #filterDefense").click( function () {
8545 trackClickEvent("FilterOffOrDef");
8546 var unitArray = $(this).attr('id') == "filterDefense" ? world_data.units_def : world_data.units_off;
8547 filterTable(function (row) {
8548 var hideRow = false;
8549 $("td:gt(0)", row).each(function (i) {
8550 if (world_data.units[i] != undefined
8551 && world_data.units[i] != "heavy"
8552 && parseInt($(this).text(), 10) > 0
8553 && $.inArray(world_data.units[i], unitArray) > -1) {
8554
8555 hideRow = true;
8556 return false;
8557 }
8558 });
8559
8560 return hideRow;
8561 });
8562 });
8563
8564 /// BARBARIAN VILLAGES filter
8565 $("#defFilterBarbarian").click( function () {
8566 trackClickEvent("FilterBarbarian");
8567 filterTable(function (row) {
8568 var text = row.find("td:first").text();
8569 return text.match(/\(---\)\s+\(F\d+\)$/); // Unlocalized F(ields) string
8570 });
8571 });
8572
8573 // TEXT FILTER
8574 $("#defFilterText").click( function () {
8575 trackClickEvent("FilterText");
8576 var compareTo = $("#defFilterTextValue").val().toLowerCase();
8577 if (compareTo.length > 0)
8578 filterTable(function (row) {
8579 return row.text().toLowerCase().indexOf(compareTo) == -1;
8580 });
8581 });
8582
8583 // DISTANCE between OWN and supporting village
8584 $("#defFilterDistance").click(function () {
8585 trackClickEvent("FilterDistance");
8586 var maxDistance = $("#defFilterDistanceValue").val();
8587 filterTable(
8588 function (row) {
8589 var distance = $(row).attr("distance");
8590 return (distance != '' && parseInt(distance, 10) < maxDistance);
8591 },
8592 "before");
8593 });
8594
8595 } catch (e) { handleException(e, "overview-supportdetail"); }
8596 //console.timeEnd("overview-supportdetail");
8597 }());
8598 }
8599 // COMMANDS OVERVIEW
8600 else if (location.href.indexOf('mode=commands') > -1) {
8601 (function() {
8602 //console.time("overview-commands");
8603 try {
8604 overviewTable = $("#commands_table");
8605 tableHandler.init("commands_table", {
8606 hasBottomTotalRow: true
8607 });
8608
8609 var commandListType = getQueryStringParam("type");
8610
8611 var menu = "";
8612 menu += "<table class=vis width='100%'>";
8613 menu += "<tr>";
8614 if (location.href.indexOf('type=all') > -1 || location.href.indexOf('&type=') == -1) {
8615 menu += "<th width='1%'>";
8616 menu += "<input type=button id=filterReturning value='" + trans.sp.commands.filterReturn + "' title=\"" + trans.sp.commands.filterReturnTooltip + "\">";
8617 menu += "</th>";
8618 }
8619
8620 menu += "<th width='1%' nowrap>";
8621 menu += "<input type=checkbox id=sortSum " + (user_data.command.sumRow ? "checked" : "") + "> " + trans.sp.commands.totalRows + " ";
8622 var isSupport = location.href.indexOf('type=support') > -1;
8623 menu += "<input type=button id=sortIt value='" + trans.sp.commands.group + "'>";
8624
8625 menu += "</th><th width='98%'>";
8626
8627 menu += "<input type=button id=BBCodeOutput value='" + trans.sp.commands.bbCodeExport + "' title='" + trans.sp.commands.bbCodeExportTooltip + "'>";
8628
8629 if (commandListType !== "attack" && commandListType !== "return") {
8630 menu += " ";
8631 menu += "<input type=text id=supportPlayerName size=> ";
8632 menu += "<input type=button id=supportPlayerExport value='" + trans.sp.commands.supportPlayerExport + "' title='" + trans.sp.commands.supportPlayerExportTooltip + "'>";
8633 }
8634
8635 menu += "</th></tr></table>";
8636
8637 // second row
8638 menu += "<table><tr><th width='1%' nowrap>";
8639 menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": ";
8640
8641 menu += "</th><th width='1%' nowrap>";
8642 menu += "<span style='background-color: #ecd19a; border: 1px solid black' id='unitFilterBox'>";
8643 menu += " <img src='graphic/unit/unit_snob.png' id=filtersnob> <img src='graphic/unit/unit_spy.png' id=filterspy> <img src='graphic/face.png' id=filterFake> ";
8644 menu += " </span>";
8645
8646 menu += "</th><th width='1%' nowrap>";
8647 menu += "<input type=text size=12 id=defFilterTextValue value=''>";
8648 menu += "<input type=button id=defFilterText value='" + trans.sp.commands.freeTextFilter + "'>";
8649
8650 menu += "</th><th width='97%' nowrap>";
8651 menu += "<input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>";
8652
8653 menu += "</th></tr>";
8654 menu += "</table>";
8655 $("#commands_table").before(menu);
8656
8657 $("#select_all").replaceWith("<input type='checkbox' id='selectAll'>");
8658 var selectAllCheckboxes = function() {
8659 var isChecked = $("#selectAll").is(":checked");
8660 $("#commands_table tr:visible").find(":checkbox").prop("checked", isChecked);
8661 };
8662 $("#selectAll").change(selectAllCheckboxes);
8663
8664 var offsetToUnits = 3;
8665
8666 $("#defReverseFilter").change( function () {
8667 var isChecked = $(this).is(":checked");
8668 var defTrans = trans.sp.commands;
8669 $("#unitFilterBox").find("img:eq(0)").attr("title", !isChecked ? defTrans.nobleFilter : defTrans.nobleFilterRev);
8670 $("#unitFilterBox").find("img:eq(1)").attr("title", isChecked ? defTrans.spyFilter : defTrans.spyFilterRev);
8671 $("#unitFilterBox").find("img:eq(2)").attr("title", !isChecked ? defTrans.fakeFilter : defTrans.fakeFilterRev);
8672
8673 $("#defFilterContinent").attr("title", isChecked ? defTrans.continentFilterTooltip : defTrans.continentFilterTooltipReverse);
8674
8675 $("#defFilterText").attr("title", defTrans.freeTextFilterTooltip.replace("{filterType}", isChecked ? defTrans.freeTextFilterTooltipFilterTypeWith : defTrans.freeTextFilterTooltipFilterTypeWithout));
8676 });
8677
8678 $("#defReverseFilter").change();
8679 var hasGrouped = false;
8680
8681 // generate bb code or JSON (for player os) export
8682 $("#BBCodeOutput,#supportPlayerExport").click(function () {
8683 trackClickEvent($(this).attr("id"));
8684 var villages = [];
8685 var request = {};
8686 var filter = hasGrouped ? "tr.command" : "tr:gt(0)";
8687 $("#commands_table " + filter).filter(":visible").each(function () {
8688 var row = $(this);
8689 var cells = $("td", row);
8690 var firstCell = cells.first();
8691 var commandType = firstCell.find("img:first").attr("src");
8692
8693 if (typeof commandType !== 'undefined'
8694 && commandType.indexOf("command/cancel.png") == -1
8695 && commandType.indexOf("command/other_back.png") == -1
8696 && commandType.indexOf("command/back.png") == -1
8697 && commandType.indexOf("command/return.png") == -1) {
8698
8699 // We get the village coords from the description of the command
8700 // Meaning if the user changes the name to "blabla" that we can't parse it
8701 var village = getVillageFromCoords($.trim(firstCell.text()));
8702 //assert(village.isValid, $.trim(firstCell.text()) + " could not be converted to village");
8703 if (village.isValid) {
8704 if (request[village.coord] == undefined) {
8705 request[village.coord] = { village: village.coord, attacks: [], hasSupport: false };
8706 villages.push(village.coord);
8707 }
8708
8709 var unitsSent = {};
8710 $.each(world_data.units,
8711 function (i, val) {
8712 unitsSent[val] = parseInt(cells.eq(offsetToUnits + i).text(), 10);
8713 });
8714
8715 var isSupport = false;
8716 if (commandListType == "support") {
8717 isSupport = true;
8718 }
8719 else if (commandListType == "attack") {
8720 isSupport = false;
8721 } else {
8722 isSupport = cells.first().has("img[src*='command/support.png']").size() == 1;
8723 }
8724
8725 request[village.coord].hasSupport = isSupport;
8726 request[village.coord].attacks.push({
8727 isSupport: isSupport,
8728 units: unitsSent,
8729 unitsString: buildAttackString(null, unitsSent, null, isSupport, user_data.command.bbCodeExport.requiredTroopAmount),
8730 commandName: isSupport ? $.trim(firstCell.text()) : "",
8731 commandId: isSupport ? firstCell.find(":checkbox").attr("value") : null,
8732 arrivalDate: getDateFromTodayTomorrowTW(cells.eq(2).text())
8733 });
8734 }
8735 }
8736 });
8737
8738 var exportWidgets = [];
8739 if ($(this).attr("id") === "BBCodeOutput") {
8740 var requestsPer500 = [""];
8741 var requestComposed = "";
8742 for (var i = 0; i < villages.length; i++) {
8743 var currentVillage = request[villages[i]];
8744 var currentText = "";
8745 currentText += "[spoiler][code]";
8746 var attackCount = 0;
8747 var supportCount = 0;
8748 var lastAttack = null;
8749 var largestAttack = 0;
8750 var totalPop = 0;
8751 for (var attackId = 0; attackId < currentVillage.attacks.length; attackId++) {
8752 var currentAttack = currentVillage.attacks[attackId];
8753 if (currentAttack.isSupport) {
8754 supportCount++;
8755 $.each(world_data.units, function (i, val) {
8756 totalPop += currentAttack.units[val] * world_data.unitsPositionSize[i];
8757 });
8758 } else {
8759 attackCount++;
8760 if (lastAttack == null || lastAttack < currentAttack.arrivalDate) {
8761 lastAttack = currentAttack.arrivalDate;
8762 }
8763 }
8764 if (largestAttack < currentAttack.unitsString.length) {
8765 largestAttack = currentAttack.unitsString.length;
8766 }
8767 }
8768
8769 for (var attackId = 0; attackId < currentVillage.attacks.length; attackId++) {
8770 var currentAttack = currentVillage.attacks[attackId];
8771 currentText += currentAttack.unitsString;
8772 var extraTabs = (largestAttack - currentAttack.unitsString.length) / 1;
8773 if (Math.ceil(extraTabs) == extraTabs) {
8774 extraTabs = Math.ceil(extraTabs);
8775 }
8776 for (var tabs = 0; tabs < extraTabs + 1; tabs++) {
8777 currentText += " ";
8778 }
8779
8780 currentText += "\t" + twDateFormat(currentAttack.arrivalDate, true) + "\n";
8781 }
8782 currentText += "[/code][/spoiler]\n";
8783
8784 var headerTemplate;
8785 if (!currentVillage.hasSupport && attackCount !== 0) {
8786 headerTemplate = trans.sp.commands.exportAttackHeader;
8787 }
8788 else if (currentVillage.hasSupport && attackCount === 0) {
8789 headerTemplate = trans.sp.commands.exportDefenseHeader;
8790 } else {
8791 headerTemplate = trans.sp.commands.exportCompleteHeader;
8792 }
8793
8794 requestComposed +=
8795 headerTemplate
8796 .replace("{#}", attackCount)
8797 .replace("{support#}", supportCount)
8798 .replace("{totalStack}", formatNumber(totalPop))
8799 .replace("{lastAttack}", lastAttack !== null ? twDateFormat(lastAttack, true) : "")
8800 .replace("{village}", "[village]" + villages[i] + "[/village]")
8801 + "\n " + currentText;
8802
8803 // splits per 500 [ characters (limit in TW)
8804 var amountBracket = requestsPer500[requestsPer500.length - 1].match(/\[/g);
8805 if (amountBracket != null && (requestComposed.match(/\[/g).length + amountBracket.length > server_settings.allowedSquareBrackets)) {
8806 requestsPer500.push("");
8807 }
8808 requestsPer500[requestsPer500.length - 1] += requestComposed;
8809 requestComposed = "";
8810 }
8811
8812 for (i = 0; i < requestsPer500.length; i++) {
8813 exportWidgets.push("<textarea cols=80 rows=10 class=restackArea>" + requestsPer500[i] + "</textarea>");
8814 }
8815
8816 } else {
8817 // JSON export for player support
8818 var exportAttacks = [],
8819 playerName = $.trim($("#supportPlayerName").val()),
8820 filter = playerName.length === 0
8821 ? function(attackString) { return true; }
8822 : function(attackString) { return attackString.indexOf(playerName) !== -1 };
8823
8824 for (var i = 0; i < villages.length; i++) {
8825 var currentVillage = request[villages[i]];
8826
8827 if (currentVillage.hasSupport) {
8828 for (var attackId = 0; attackId < currentVillage.attacks.length; attackId++) {
8829 var currentAttack = currentVillage.attacks[attackId];
8830 if (currentAttack.isSupport && filter(currentAttack.commandName)) {
8831 exportAttacks.push({
8832 commandName: currentAttack.commandName,
8833 commandId: currentAttack.commandId
8834 });
8835 /*q(villages[i]);
8836 q(currentVillage)
8837 q(currentAttack);
8838 q("---------------------");*/
8839 }
8840 }
8841 }
8842 }
8843
8844 if (exportAttacks.length > 0) {
8845 exportWidgets.push("<textarea style='width: 96%' rows=10 class=restackArea>" + JSON.stringify(exportAttacks, null, 4) + "</textarea>");
8846 } else {
8847 alert(trans.sp.commands.exportNone);
8848 }
8849 }
8850
8851 if (exportWidgets.length > 0) {
8852 if ($("#textsArea").size() == 0) {
8853 $(this).parent().parent().parent().append("<tr><td id=textsArea colspan=3></td></tr>");
8854 } else {
8855 $("#textsArea").html("");
8856 }
8857 for (var i = 0; i < exportWidgets.length; i++) {
8858 $("#textsArea").append(exportWidgets[i]);
8859 }
8860 $("#textsArea").append("<br><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>");
8861 $("#closeTextsArea").click(function() {
8862 $("#textsArea").parent().remove();
8863 });
8864 }
8865 });
8866
8867 function filterCommandRows(filterStrategy) {
8868 // return true to hidethe row; false keep row visible (without reverse filter checkbox)
8869 var reverseFilter = $("#defReverseFilter").is(":checked");
8870 var goners = $();
8871 var filter = hasGrouped ? "tr.command" : "tr:gt(0)";
8872 $("#commands_table " + filter).filter(":visible").each(function () {
8873 if ($("th", this).size() != 0) {
8874 // don't do anything anymore when on the total row
8875 return;
8876 }
8877 if (!reverseFilter != !filterStrategy($(this))) {
8878 goners = goners.add($(this));
8879 $("input:eq(1)", this).val("");
8880 }
8881 });
8882 goners.remove();
8883
8884 // Show totals
8885 var amountOfCommandos = $("#commands_table " + filter).size();
8886 if (hasGrouped) {
8887 $("#commands_table tr.sumLine").hide();
8888 } else {
8889 amountOfCommandos--;
8890 }
8891
8892 $("#commands_table th:first").text(trans.sp.commands.tableTotal.replace("{0}", amountOfCommandos));
8893 $("#amountOfAttacks").text(amountOfCommandos);
8894 if ($("#amountOfAttacks").size() == 1) {
8895 $("#amountOfTargets").val("???");
8896 }
8897
8898 $("#commands_table tr").not(":visible").find(":checkbox").prop("checked", false);
8899 }
8900
8901 // Filter sent back, returning and cancelled commands
8902 $("#filterReturning").click(function () {
8903 $(this).attr("disabled", "disabled");
8904 trackClickEvent("FilterReturning");
8905 filterCommandRows( function (row) {
8906 var firstCellImage = $("td:first img:first", row).attr("src");
8907 return firstCellImage.indexOf("command/other_back.png") != -1
8908 || firstCellImage.indexOf("command/back.png") != -1
8909 || firstCellImage.indexOf("command/return.png") != -1
8910 || firstCellImage.indexOf("command/cancel.png") != -1;
8911 });
8912 });
8913
8914 $("#defFilterText").click(function () {
8915 trackClickEvent("FilterText");
8916 var compareTo = $("#defFilterTextValue").val().toLowerCase();
8917 if (compareTo.length > 0) {
8918 filterCommandRows(function (row) {
8919 return row.text().toLowerCase().indexOf(compareTo) == -1;
8920 });
8921 }
8922 });
8923
8924 $("#filterspy").click(function () {
8925 trackClickEvent("FilterSpy");
8926 var position = $.inArray($(this).attr("id").substr(6), world_data.units);
8927 filterCommandRows(function (row) {
8928 if (row.find("td").eq(position + offsetToUnits).text() == "0") {
8929 return false;
8930 }
8931 var totalScout = row.find("td").eq(position + offsetToUnits).text();
8932
8933 var cell = row.find("td:eq(" + (offsetToUnits - 1) + ")");
8934 for (var i = 0; i < world_data.units.length; i++) {
8935 cell = cell.next();
8936 if (totalScout < cell.text()) {
8937 return false;
8938 }
8939 }
8940 return true;
8941 });
8942 });
8943
8944 $("#filtersnob").click(function () {
8945 trackClickEvent("FilterSnob");
8946 var position = $.inArray($(this).attr("id").substr(6), world_data.units) + offsetToUnits;
8947 filterCommandRows(function (row) {
8948 return row.find("td").eq(position).text() == "0";
8949 });
8950 });
8951
8952 $("#filterFake").click(function () {
8953 trackClickEvent("FilterFake");
8954 var maxPop = user_data.command.filterFakeMaxPop;
8955 filterCommandRows(function (row) {
8956 var total = 0;
8957 var cell = row.find("td:eq(" + (offsetToUnits - 1) + ")");
8958 for (var i = 0; i < world_data.units.length; i++) {
8959 cell = cell.next();
8960 total += parseInt(cell.text(), 10);
8961
8962 // An attack with a noble is (almost) never a fake:
8963 if (i == world_data.units.length - 1 && cell.text() != "0") {
8964 return false;
8965 }
8966
8967 if (total > maxPop) {
8968 return false;
8969 }
8970 }
8971 return true;
8972 });
8973 });
8974
8975 $("#defFilterContinent").click(function () {
8976 trackClickEvent("FilterContinent");
8977 var continent = parseInt($("#defFilterContinentText").val(), 10);
8978 if (!isNaN(continent)) {
8979 filterCommandRows(function (row) {
8980 var village = getVillageFromCoords(row.find("td:first").text());
8981 var village2 = getVillageFromCoords(row.find("td:eq(1)").text());
8982 if (!village.isValid || !village2.isValid) {
8983 return true;
8984 }
8985 return village.continent() != continent && village2.continent() != continent;
8986 });
8987 }
8988 });
8989
8990 // Sort/group incoming attacks
8991 $("#sortIt").click(function () {
8992 trackClickEvent("Sort");
8993 hasGrouped = true;
8994 var newTable = "";
8995 var targets = [];
8996 var amountOfCommandos = 0;
8997 var sum = $('#sortSum').is(':checked');
8998 $("#filterReturning").attr("disabled", true);
8999
9000 $("#commands_table").find("tr:gt(0)").filter(":visible").each(function () {
9001 var target = $.trim($(".quickedit-label", this).text());
9002 var village = getVillageFromCoords(target);
9003 if (village.isValid) {
9004 amountOfCommandos++;
9005 if (targets[village.coord] == undefined) {
9006 targets.push(village.coord);
9007 targets[village.coord] = new Array();
9008 }
9009 targets[village.coord].push($(this));
9010 }
9011 });
9012
9013 var mod = 0;
9014 if (isSupport) {
9015 $.each(targets, function (i, v) {
9016 mod++;
9017 var amount = 0;
9018 var totalDef = new Array();
9019 totalDef['pop'] = 0;
9020 $.each(world_data.units, function (index, value) { totalDef[value] = 0; });
9021
9022 $.each(targets[v], function (index, value) {
9023 var villageId = $("td:eq(1) a:first", value).attr("href").match(/id=(\d+)/)[1];
9024 newTable += "<tr class='command nowrap row_" + (mod % 2 == 0 ? 'b' : 'a') + (villageId == game_data.village.id ? " selected" : "") + "'>" + value.html() + "</tr>";
9025 amount++;
9026
9027 var unitAmounts = $("td:gt(2)", value);
9028 $.each(world_data.units, function (iUnit, vUnit) {
9029 var amount = parseInt(unitAmounts.eq(iUnit).html(), 10);
9030 if (amount == 1) {
9031 totalDef[vUnit] = amount;
9032 } else {
9033 totalDef[vUnit] += amount;
9034 }
9035 totalDef['pop'] += amount * world_data.unitsSize['unit_' + vUnit];
9036 });
9037 });
9038
9039 if (sum) {
9040 newTable += "<tr class='sumLine'><td align=right colspan=3><b>" + trans.sp.commands.totalRowsText.replace("{0}", amount).replace("{1}", formatNumber(totalDef['pop'])) + " </b></td>";
9041 $.each(world_data.units, function (iUnit, vUnit) {
9042 newTable += "<td>" + (totalDef[vUnit] == 0 ? " " : formatNumber(totalDef[vUnit])) + "</td>";
9043 });
9044 newTable += "</tr>";
9045 }
9046 });
9047 } else {
9048 // attacks (meaning: no support commands)
9049 $.each(targets, function (i, v) {
9050 mod++;
9051 var amount = 0;
9052 var lastArrival = '';
9053 $.each(targets[v], function (index, value) {
9054 var villageId = $("td:eq(1) a:first", value).attr("href").match(/id=(\d+)/)[1];
9055
9056 var currentArrival = $(value).find("td:eq(2)").text();
9057 if (lastArrival == currentArrival) {
9058 // Don't show when it's on the same second
9059 // Only practical on full second worlds really
9060 newTable += "<tr class='command nowrap row_" + (mod % 2 == 0 ? 'b' : 'a') + (villageId == game_data.village.id ? " selected" : "") + "'>";
9061 $(this).find("td").each(function (i) {
9062 if (i == 2) {
9063 newTable += "<td> </td>";
9064 }
9065 else if ($(this).text() == 0) {
9066 newTable += "<td class=hidden>0</td>";
9067 } else {
9068 newTable += "<td>" + $(this).html() + "</td>";
9069 }
9070 });
9071 newTable += "</tr>";
9072 }
9073 else {
9074 newTable += "<tr class='command nowrap row_" + (mod % 2 == 0 ? 'b' : 'a') + (villageId == game_data.village.id ? " selected" : "") + "'>" + value.html() + "</tr>";
9075 }
9076 lastArrival = currentArrival;
9077 amount++;
9078 });
9079
9080 if (sum) {
9081 newTable += "<tr class='sumLine'><td align=right colspan=" + (3 + world_data.units.length) + ">" + amount + " </td></tr>";
9082 }
9083 });
9084 }
9085
9086 var menu = $("#commands_table tr").first().html(),
9087 totalRow = $("#commands_table tr:last");
9088 $("#commands_table").html("<table id='commands_table' class='vis'>" + menu + newTable + totalRow.outerHTML() + "</table>");
9089 $("#selectAll").change(selectAllCheckboxes);
9090
9091 // total number of attacks
9092 if ($("#amountOfAttacks").size() == 0) {
9093 var totalDesc = (isSupport ? trans.sp.commands.totalSupport : trans.sp.commands.totalAttack);
9094 var totalVillagesDesc = isSupport ? trans.sp.commands.totalVillagesSupport : trans.sp.commands.totalVillagesAttack;
9095 var pageSize = $("input[name='page_size']");
9096 if (pageSize.size() == 0) {
9097 pageSize = $("input[type='submit']:last");
9098 pageSize.after("<table class=vis><tr class='row_a'><th>" + totalVillagesDesc + "</th><td><input type=text size=5 value=" + targets.length + " id=amountOfTargets></td></tr><tr class='row_a'><th>" + totalDesc + ":</th><td id='amountOfAttacks'>" + amountOfCommandos + "</td></tr></table>");
9099 } else {
9100 pageSize[0].id = "amountOfTargets";
9101 pageSize.parent().prev().text(totalVillagesDesc);
9102 pageSize = pageSize.val(targets.length).parent().parent().parent();
9103 pageSize.append('<tr><th colspan=2>' + totalDesc + ':</th><td id="amountOfAttacks">' + amountOfCommandos + '</td></tr>');
9104 }
9105 } else {
9106 $("#amountOfTargets").val(targets.length);
9107 $("#amountOfAttacks").text(amountOfCommandos);
9108 }
9109 });
9110 } catch (e) { handleException(e, "overview-commands"); }
9111 //console.timeEnd("overview-commands");
9112 }());
9113 }
9114 // INCOMINGS OVERVIEW
9115 else if (location.href.indexOf('mode=incomings') > -1) {
9116 (function() {
9117 //console.time("overview-incomings");
9118 try {
9119 overviewTable = $("#incomings_table");
9120 tableHandler.init("incomings_table", {
9121 hasBottomTotalRow: getQueryStringParam("subtype") !== "supports"
9122 });
9123
9124 var table = {
9125 /**
9126 * Quick sort adds extra rows with the .total class
9127 */
9128 hasTotalRows: false,
9129 /**
9130 * Some buttons add extra columns
9131 */
9132 newColumns: {
9133 before: 0,
9134 after: 0
9135 },
9136 getColspan: function() {
9137 return 7 + this.newColumns.before + this.newColumns.after;
9138 },
9139 /**
9140 * Remove the total rows so that other filters can operate again
9141 */
9142 fixTable: function() {
9143 if (this.hasTotalRows === true) {
9144 overviewTable.find("tr.total").remove();
9145 this.hasTotalRows = false;
9146 }
9147 },
9148 getVillageRows: function() {
9149 var rows = overviewTable.find("tr:gt(0)");
9150 if (tableHandler.settings.hasBottomTotalRow) {
9151 rows = rows.not("tr:last");
9152 }
9153 return rows;
9154 },
9155 /**
9156 * Set the table total rows count correctly
9157 * @param {number} rowCount
9158 * @param {number} [villagesTargeted]
9159 */
9160 setTotals: function(rowCount, villagesTargeted) {
9161 var amountOfCommandsHeaderCell = $("tr:first", overviewTable).find("th:first"),
9162 amountOfRows = $("#amountOfRows");
9163
9164 assert(amountOfCommandsHeaderCell.length === 1, "couldn't find the command headercell");
9165 amountOfCommandsHeaderCell.html(amountOfCommandsHeaderCell.html().replace(/\(\d+\)/, "(" + rowCount + ")"));
9166
9167 if (typeof villagesTargeted !== "undefined") {
9168 if (amountOfRows.size() === 0) {
9169 var pageSize = $("input[name='page_size']");
9170 pageSize.parent().prev().text(trans.sp.commands.totalVillagesAttack);
9171 pageSize = pageSize.attr("id", "villagesTargeted").parent().parent().parent();
9172 pageSize.append('<tr><th colspan=2>' + trans.sp.incomings.amount + '</th><td id="amountOfRows">' + rowCount + '</td></tr>');
9173 } else {
9174 $("#amountOfRows").text(villagesTargeted);
9175 $("#villagesTargeted").val(villagesTargeted);
9176 }
9177 }
9178 }
9179 };
9180
9181 var columnsToFilterCount = 5;
9182
9183 // build sangu menu
9184 var menu = "";
9185 menu += "<table width='100%' class='vis' id='sangu_menu'>";
9186 menu += "<tr><th width='1%'>";
9187 menu += "<input type=button id=sortIt value='" + trans.sp.incomings.dynamicGrouping + "' title='" + trans.sp.incomings.dynamicGroupingTooltip + "'>";
9188 menu += "</th><th width='1%' nowrap>";
9189 menu += "<input type=checkbox id=sortShowTotalRow " + (user_data.command.sumRow ? "checked" : "") + "> " + trans.sp.incomings.summation + " ";
9190 menu += "<input type=button id=sortQuick value='" + trans.sp.incomings.fastGrouping + "' title='" + trans.sp.incomings.fastGroupingTooltip + "'>";
9191 menu += "</th><th width='1%'>";
9192
9193 menu += "<input type=button id=sortByAttackId value='" + trans.sp.incomings.sortByAttackId + "' title='" + trans.sp.incomings.sortByAttackIdTooltip + "'>";
9194
9195 menu += "</th><th width='96%'>";
9196 menu += "<input type=button id=filterAttack value='" + trans.sp.incomings.showNewIncomings + "'>";
9197
9198 menu += "</th><th width='1%' nowrap>";
9199 menu += "<input type=button id=commandsImport value='" + trans.sp.incomings.commandsImport + "' title='" + trans.sp.incomings.commandsImportTooltip + "'>";
9200 menu += "</th></tr>";
9201 menu += "</table>";
9202
9203 // second row
9204 menu += "<table width='100%' class=vis>";
9205 menu += "<tr><th width='1%' nowrap>";
9206
9207 menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": ";
9208 menu += "</th>";
9209
9210 // generate one input field/button filter with a select for the first cells
9211 var defaultColumnFilters = (function() {
9212 var headerCells = $("tr:first th", overviewTable),
9213 cols = [],
9214 headerCellText;
9215
9216 for (i = 0; i < columnsToFilterCount; i++) {
9217 headerCellText = headerCells.eq(i).text();
9218 if (headerCellText.indexOf(" ") !== -1) {
9219 headerCellText = $.trim(headerCellText.substr(0, headerCellText.indexOf(" ")));
9220 }
9221 cols.push(headerCellText);
9222 }
9223 return cols;
9224 }());
9225
9226 /**
9227 * builds a textinput+select+button filter that filters rows based on table column index
9228 */
9229 function buildColumnFilter() {
9230 var i,
9231 defualtIndex = pers.get("incomingsColumnFilterIndex"),
9232 menu = "<th width='99%' nowrap>";
9233
9234 menu += "<input type='text' size='20' id='filterColumnValue'>";
9235 menu += "<select id='filterColumnIndex'>";
9236 for (i = 0; i < defaultColumnFilters.length; i++) {
9237 menu += "<option value='" + i + "'"
9238 + (defualtIndex == i ? " selected" : "") + ">"
9239 + defaultColumnFilters[i] + "</option>";
9240 }
9241 menu += "</select>";
9242 menu += "<input type='button' id='filterColumn' value='"
9243 + trans.sp.incomings.filterColumnButton + "'"
9244 + "'>";
9245 menu += "</th>";
9246 return menu;
9247 }
9248
9249 menu += buildColumnFilter();
9250
9251 //menu += "<th width='97%' nowrap>";
9252 //menu += "<input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>";
9253 //menu += "</th></tr>";
9254
9255
9256 menu += "</table>";
9257 overviewTable.before(menu);
9258
9259 $("#filterColumnIndex").change(function() {
9260 pers.set("incomingsColumnFilterIndex", $("#filterColumnIndex").val());
9261 });
9262
9263 // switch tooltips on reverse filter checkbox change
9264 $("#defReverseFilter").change( function () {
9265 var isChecked = $(this).is(":checked"),
9266 overviewTrans = trans.sp.incomings;
9267
9268 //$("#").attr("title", isChecked ? overviewTrans.continentFilterTooltip : overviewTrans.continentFilterTooltipReverse);
9269
9270 $("#filterColumn").attr(
9271 "title",
9272 overviewTrans.filterColumnButtonTooltip.replace(
9273 "{type}",
9274 isChecked ? overviewTrans.filterColumnButtonTooltipHide : overviewTrans.filterColumnButtonTooltipShow));
9275 }).change();
9276
9277
9278 // select all checkbox
9279 $("#select_all").replaceWith("<input type='checkbox' id='selectAll'>");
9280 $("#selectAll").change(function() {
9281 var isChecked = $("#selectAll").is(":checked");
9282 $("tr", overviewTable).find(":checkbox").prop("checked", isChecked);
9283 });
9284 // IMPORT os exported by other player
9285 $("#commandsImport").click(function() {
9286 if ($("#textsArea").size() == 0) {
9287 $(this).parent().parent().parent().append("<tr><td id=textsArea colspan=5></td></tr>");
9288 $("#textsArea").append(
9289 "<textarea cols=80 rows=10 id=commandImportText></textarea>"
9290 + "<br>"
9291 + "<input type=button value='" + trans.sp.incomings.commandsImport + "' id=commandsImportReal>"
9292 + "<input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>");
9293
9294 $("#closeTextsArea").click(function() {
9295 $("#textsArea").parent().remove();
9296 });
9297
9298 $("#commandsImportReal").click(function() {
9299 var commandsToImport;
9300 try {
9301 commandsToImport = JSON.parse($("#commandImportText").val());
9302 var test = commandsToImport[0].commandName;
9303 }
9304 catch (e) {
9305 alert(trans.sp.incomings.commandsImportError);
9306 }
9307
9308 var amountReplaced = 0,
9309 commandsSent = [],
9310 i;
9311
9312 for (i = 0; i < commandsToImport.length; i++) {
9313 commandsSent[commandsToImport[i].commandId] = commandsToImport[i].commandName;
9314 }
9315
9316 table.getVillageRows().each(function () {
9317 var firstCell = $("td:first", this),
9318 commandId = firstCell.find(":input:first").attr("name");
9319
9320 //q("inputfield: " + firstCell.find(":input:first").length);
9321 //q("commandId = " + commandId + " in cell: " + firstCell.text());
9322
9323 //assert(commandId, "couldn't find command id inputfield");
9324 //assert(commandId.indexOf("command_ids") === 0, "inputfields have been renamed");
9325 commandId = parseInt(commandId.match(/\d+/)[0], 10);
9326 if (typeof commandsSent[commandId] !== 'undefined') {
9327 var inputField = $(':input[id^="editInput"]', firstCell);
9328 //assert(inputField.length === 1, "couldn't find the inputfield");
9329 inputField.val(commandsSent[commandId]);
9330 inputField.next().click();
9331
9332 amountReplaced++;
9333 }
9334 });
9335
9336 alert(trans.sp.incomings.commandsImportSuccess
9337 .replace("{replaced}", amountReplaced)
9338 .replace("{total}", commandsToImport.length));
9339 });
9340 }
9341 });
9342
9343 // Sort by attack id (and add extra column)
9344 $("#sortByAttackId").click(function() {
9345 $(this).attr("disabled", true);
9346 table.fixTable();
9347 table.newColumns.after += 2;
9348
9349 var diffGroups = user_data.incomings.attackIdDescriptions;
9350 function getFancyAttackIdDiffDescription(diff) {
9351 var i;
9352 for (i = 0; i < diffGroups.length; i++) {
9353 if (diff < diffGroups[i].minValue) {
9354 return diffGroups[i].text;
9355 }
9356 }
9357
9358 return user_data.incomings.attackIdHigherDescription;
9359 }
9360
9361 // new column in header
9362 tableHandler.overviewTable.find("tr:first").append("<th>"+trans.sp.incomings.attackId+"</th><th>"+trans.sp.incomings.attackIdDifference+"</th>");
9363
9364 var rows = table.getVillageRows();
9365 rows.sortElements(function (rowA, rowB) {
9366 var a = $("input:first", rowA).attr("name").match(/\d+/)[0];
9367 var b = $("input:first", rowB).attr("name").match(/\d+/)[0];
9368 //q($("input:first", rowA).attr("name") + "=>" + a);
9369 return parseInt(a, 10) > parseInt(b, 10) ? 1 : -1;
9370 });
9371
9372 var previousRowAttackId = 0;
9373 rows.each(function() {
9374 var attackId = parseInt($(this).find("input:first").attr("name").match(/\d+/)[0], 10),
9375 diff = 0,
9376 diffDescription = " ";
9377
9378 if (previousRowAttackId != 0) {
9379 diff = Math.abs(attackId - previousRowAttackId);
9380 diffDescription = getFancyAttackIdDiffDescription(diff);
9381 }
9382 previousRowAttackId = attackId;
9383
9384 $(this).append("<td align=right>"+attackId+"</td><td>"+diffDescription+"</td>");
9385 });
9386 });
9387
9388 // QUICK sort: performs faster but also freezes the screen (ie no countdowns)
9389 // --> This might also be good in case the page is refreshing too often otherwise
9390 $("#sortQuick").click(function () {
9391 trackClickEvent("SortQuick");
9392 table.fixTable();
9393 table.hasTotalRows = true;
9394
9395 var newTable = "";
9396 var targets = [];
9397 var commandCounter = 0;
9398 var addTotalRow = $('#sortShowTotalRow').is(':checked');
9399
9400 table.getVillageRows().each(function () {
9401 var target = $("td:eq(1)", this).text();
9402 var village = getVillageFromCoords(target);
9403 if (village.isValid) {
9404 commandCounter++;
9405 if (targets[village.coord] == undefined) {
9406 targets.push(village.coord);
9407 targets[village.coord] = [];
9408 }
9409 targets[village.coord].push($(this));
9410 }
9411 });
9412
9413 var mod = 0;
9414 $.each(targets, function (i, v) {
9415 mod++;
9416 var rowColor = "row_" + (mod % 2 == 0 ? 'b' : 'a');
9417 var amount = 0;
9418 $.each(targets[v], function (index, row) {
9419 var villageId = row.find("td:eq(1) a:first").attr("href").match(/village=(\d+)/)[1];
9420 newTable += "<tr class='nowrap " + rowColor + "'"
9421 + (villageId == game_data.village.id ? " selected" : "") + ">"
9422 + row.html() + "</tr>";
9423 amount++;
9424 });
9425
9426 if (addTotalRow) {
9427 if (amount === 1) {
9428 newTable += "<tr class='" + rowColor + " total'><td align=right colspan=" + table.getColspan() + "> </td></tr>";
9429 } else {
9430 newTable += "<tr class='" + rowColor + " total'><td align=right colspan=" + table.getColspan() + "><b>" + trans.sp.incomings.amount + " " + amount + "</b> </td></tr>";
9431 }
9432 }
9433 });
9434
9435 var menu = $("tr:first", overviewTable).html();
9436 var totalRow = $("tr:last", overviewTable).html();
9437 overviewTable.html("<table id='incomings_table' class='vis'>" + menu + newTable + totalRow + "</table>");
9438
9439 table.setTotals(commandCounter, targets.length);
9440 });
9441
9442
9443
9444
9445
9446 // DYNAMIC sort incoming attacks
9447 $("#sortIt").click(function () {
9448 table.fixTable();
9449 trackClickEvent("Sort");
9450
9451 var rows = table.getVillageRows();
9452 rows.sortElements(function (a, b) {
9453 a = getVillageFromCoords($("td:eq(1)", a).text());
9454 b = getVillageFromCoords($("td:eq(1)", b).text());
9455
9456 return (a.x * 1000 + a.y) > (b.x * 1000 + b.y) ? 1 : -1;
9457 });
9458
9459 var amountOfVillages = 0;
9460 var current = "";
9461 rows.each(function () {
9462 var village = $("td:eq(1)", this);
9463 if (current != village.text()) {
9464 current = village.text();
9465 amountOfVillages++;
9466 }
9467 var type = amountOfVillages % 2 == 0 ? 'row_a' : 'row_b';
9468
9469 var villageId = village.find("a:first").attr("href").match(/village=(\d+)/)[1];
9470 this.className = "nowrap " + type + (villageId == game_data.village.id ? " selected" : "");
9471 });
9472
9473 table.setTotals(rows.size(), amountOfVillages);
9474 });
9475 /**
9476 *
9477 * @param {function} filterStrategy return true to hidethe row; false keep row visible (without reverse filter checkbox)
9478 * @param {Object} options
9479 */
9480 function filterVillageRows(filterStrategy, options) {
9481 options = $.extend({}, {
9482 checkboxReverses: true
9483 }, options);
9484
9485 var reverseFilter = options.checkboxReverses && $("#defReverseFilter").is(":checked"),
9486 goners = $(),
9487 villageCounter = 0;
9488
9489 trackClickEvent(options.gaEventName);
9490
9491 table.fixTable();
9492
9493 table.getVillageRows().each(function () {
9494 var self = $(this);
9495 if (!reverseFilter != !filterStrategy(self)) {
9496 goners = goners.add(self);
9497 } else {
9498 villageCounter++;
9499 }
9500 });
9501 goners.remove();
9502
9503 // Show totals
9504 table.setTotals(villageCounter);
9505 }
9506
9507 // Show new attacks only
9508 $("#filterAttack").click(function () {
9509 var strategy = function(row) {
9510 return $.trim($("td:first", row).text()) != trans.tw.command.attack;
9511 };
9512
9513 filterVillageRows(strategy, {
9514 gaEventName: "FilterNewAttacks",
9515 checkboxReverses: false
9516 });
9517 });
9518
9519
9520 // Filter rows on column 0 - 3 (command, target, origin, player)
9521 $("#filterColumn").click(function() {
9522 var filter = {
9523 index: $("#filterColumnIndex").val(),
9524 searchText: $.trim($("#filterColumnValue").val()).toLowerCase()
9525 };
9526
9527 var filterStrategy = function(row) {
9528 return row.find("td").eq(filter.index).text().toLowerCase().indexOf(filter.searchText) === -1;
9529 };
9530
9531 filterVillageRows(filterStrategy, {
9532 gaEventName: "column-" + $("#filterColumnIndex").text()
9533 });
9534 });
9535
9536
9537 } catch (e) { handleException(e, "overview-incomings"); }
9538 //console.timeEnd("overview-incomings");
9539 }());
9540 }
9541
9542 // make the editting groups box less wide
9543 // and add alternating row colors
9544 $("#edit_group_href").click(function () {
9545 var groupTable = $("#group_list");
9546 groupTable.width(300);
9547
9548 groupTable.find("th:first").attr("colspan", "3");
9549 var mod = 0;
9550 groupTable.find("tr:gt(0)").each(function () {
9551 mod++;
9552 $(this).addClass("row_" + (mod % 2 == 0 ? "a" : "b"));
9553 });
9554 });
9555
9556 // change troops overview link to active sangu page
9557 if (user_data.command.changeTroopsOverviewLink) {
9558 var troopsOverviewLink = $("#overview_menu a[href*='mode=units']");
9559 troopsOverviewLink.attr("href", troopsOverviewLink.attr("href") + "&type=own_home");
9560 }
9561
9562 if (user_data.overviews.addFancyImagesToOverviewLinks) {
9563 var overviewLinks = $("#overview_menu a");
9564 overviewLinks.each(function(index) {
9565 var overviewLink = $(this),
9566 imageToAdd = "";
9567
9568 switch (index) {
9569 case 0:
9570 // overviewLink.parent()
9571 // .css("background-image", 'url("https://www.tribalwars.vodka/graphic/icons/header.png")')
9572 // .css("background-repeat", "no-repeat")
9573 // .css("background-position", "-324px 0px")
9574 // .css("background-size", "200px Auto");
9575 //
9576 // overviewLink.prepend(" ");
9577 break;
9578 case 1:
9579 imageToAdd = "graphic/buildings/storage.png";
9580 break;
9581 case 2:
9582 imageToAdd = "graphic/buildings/market.png";
9583 break;
9584 case 3:
9585 if (overviewLink.parent().hasClass("selected")) {
9586 $("table.modemenu:last a", content_value).each(function(index) {
9587 imageToAdd = "";
9588 switch (index) {
9589 case 1:
9590 imageToAdd = "graphic/buildings/place.png";
9591 break;
9592 case 2:
9593 imageToAdd = "graphic/pfeil.png";
9594 break;
9595 case 3:
9596 case 4:
9597 $(this).css("opacity", "0.5");
9598 break;
9599 case 5:
9600 imageToAdd = "graphic/command/support.png";
9601 break;
9602 case 6:
9603 imageToAdd = "graphic/rechts.png";
9604 break;
9605 }
9606
9607 if (imageToAdd !== "") {
9608 $(this).prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text() + " > " + $(this).text()+"' /> ");
9609 }
9610 });
9611 }
9612
9613 imageToAdd = "graphic/unit/unit_knight.png";
9614 break;
9615 case 4:
9616 if (overviewLink.parent().hasClass("selected")) {
9617 $("table.modemenu:last a", content_value).each(function(index) {
9618 imageToAdd = "";
9619 switch (index) {
9620 case 1:
9621 imageToAdd = "graphic/command/attack.png";
9622 break;
9623 case 2:
9624 imageToAdd = "graphic/command/support.png";
9625 break;
9626 case 3:
9627 imageToAdd = "graphic/command/return.png";
9628 break;
9629 }
9630
9631 if (imageToAdd !== "") {
9632 $(this).prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text() + " > " + $(this).text()+"' /> ");
9633 }
9634 });
9635 }
9636
9637 imageToAdd = "graphic/command/attack.png";
9638 break;
9639 case 5:
9640 if (overviewLink.parent().hasClass("selected")) {
9641 $("table.modemenu:last a", content_value).each(function(index) {
9642 imageToAdd = "";
9643 switch (index) {
9644 case 1:
9645 imageToAdd = "graphic/command/attack.png";
9646 break;
9647 case 2:
9648 imageToAdd = "graphic/command/support.png";
9649 break;
9650 }
9651
9652 if (imageToAdd !== "") {
9653 $(this).prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text() + " > " + $(this).text()+"' /> ");
9654 }
9655 });
9656 }
9657
9658 imageToAdd = "graphic/unit/att.png";
9659 break;
9660 case 6:
9661 imageToAdd = "graphic/buildings/main.png";
9662 break;
9663 case 7:
9664 imageToAdd = "graphic/buildings/smith.png";
9665 break;
9666 case 8:
9667 imageToAdd = "graphic/group_right.png";
9668 overviewLink.prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text()+"' /> ");
9669 imageToAdd = "graphic/group_left.png";
9670 break;
9671 case 9:
9672 imageToAdd = "graphic/premium/coinbag_14x14.png";
9673 overviewLink.parent().width(150);
9674 break;
9675 }
9676 if (imageToAdd !== "") {
9677 overviewLink.prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text()+"' /> ");
9678 }
9679 });
9680 }
9681 }
9682
9683 var logoffLink = $("#linkContainer a:last");
9684 if (user_data.global.duplicateLogoffLink) {
9685 $("#linkContainer a:first").after(" - ").after(logoffLink.clone());
9686 }
9687
9688 logoffLink.before("<a target='_blank' title='"+trans.sp.sp.moreScriptsTooltip+"' href='"+server_settings.scriptsDatabaseUrl+"'>"+trans.sp.sp.moreScripts+"</a>")
9689 .before(" - <a target='_top' id='sanguPackageEditSettingsLink' href='"+getUrlString("screen=settings&mode=sangu")+"' title='" + trans.sp.sp.sanguLinkTitle + "'>Sangu Package</a> - ");
9690
9691 (function() {
9692 var position = $("#sanguPackageEditSettingsLink").position(),
9693 options = {
9694 left: position.left,
9695 top: ($(window).height() - 100)
9696 },
9697 content = {
9698 body: trans.sp.sp.firstTimeRunEditSettings
9699 };
9700
9701 createFixedTooltip("sanguActivatorSettingsTooltip", content, options);
9702 }());
9703
9704 (function() {
9705 //console.time("resourceColoring");
9706 try {
9707 var storage = parseInt($("#storage").text(), 10);
9708
9709 // Color resources based on how full the storage place is
9710 if (user_data.global.resources.active) {
9711 $("#wood,#iron,#stone").each(function () {
9712 var x = parseInt(this.innerHTML / storage * 10 - 1, 10);
9713 $(this).css("background-color", user_data.global.resources.backgroundColors[x]);
9714 });
9715 }
9716
9717 // Blink full resources
9718 if (user_data.global.resources.blinkWhenStorageFull) {
9719 $("#wood,#iron,#stone").filter(function () {
9720 return parseInt(this.innerHTML, 10) == storage;
9721 }).css({ "font-weight": "bolder", "color": "black" }).fadeOut().fadeIn();
9722 }
9723 } catch (e) { handleException(e, "resourcecoloring"); }
9724 //console.timeEnd("resourceColoring");
9725 }());
9726 // adjust links to incoming attacks/support
9727 // keep track of current amount of incomings
9728 if (user_data.global.incomings.editLinks || user_data.global.incomings.track) {
9729 (function() {
9730 //console.time("incomingsindicator");
9731 try {
9732 var incoming = $("table.box:last"),
9733 incomingAttacksLinks = $("a[href*='subtype=attacks']", incoming),
9734 variableReplacer = function (text) {
9735 var difference = "";
9736 if (sinceLastCheckTimeNew > 0) {
9737 difference += "+" + sinceLastCheckTimeNew;
9738 if (sinceLastCheckTimeArrived > 0) {
9739 difference += " ";
9740 }
9741 }
9742 if (sinceLastCheckTimeArrived > 0) {
9743 difference += "-" + sinceLastCheckTimeArrived;
9744 }
9745
9746 return text.replace("{difference}", difference)
9747 .replace("{elapsed}", lastCheckTimeElapsed)
9748 .replace("{time}", lastCheckTime)
9749 .replace("{current}", currentAmountOfIncomings
9750 .replace("{saved}", lastKnownAmountOfIncomings));
9751 };
9752
9753 if (incomingAttacksLinks.size() > 0) {
9754 if (user_data.global.incomings.editLinks) {
9755 incomingAttacksLinks.attr("href", incomingAttacksLinks.attr("href") + "&page=-1&group=0");
9756 }
9757 if (user_data.global.incomings.track) {
9758 incomingAttacksLinks.parent().css("white-space", "nowrap");
9759
9760 // Split current and new attacks in incomings link
9761 var incomingAttacksAmountLink = incomingAttacksLinks.last();
9762 var currentAmountOfIncomings = incomingAttacksAmountLink.text().match(/\d+/)[0];
9763 var lastKnownAmountOfIncomings = parseInt(pers.get("lastKnownAmountOfIncomings" + game_data.player.sitter), 10) || 0,
9764 sinceLastCheckTimeNew = parseInt(pers.get("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter), 10) || 0,
9765 sinceLastCheckTimeArrived = parseInt(pers.get("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter), 10) || 0;
9766
9767 var lastCheckTime = pers.get("lastKnownAmountOfIncomingsTime" + game_data.player.sitter);
9768 var lastCheckTimeElapsed;
9769 if (!lastCheckTime) {
9770 lastCheckTime = trans.sp.incomings.indicator.lastTimeCheckNotYetSet;
9771 lastCheckTimeElapsed = lastCheckTime;
9772 } else {
9773 lastCheckTime = new Date().getTime() - parseInt(lastCheckTime, 10);
9774 lastCheckTimeElapsed = prettyDate(lastCheckTime);
9775 lastCheckTime = twDateFormat(new Date(lastCheckTime));
9776 }
9777
9778 if (currentAmountOfIncomings != lastKnownAmountOfIncomings || sinceLastCheckTimeNew > 0 || sinceLastCheckTimeArrived > 0) {
9779 var newAttacks = currentAmountOfIncomings - lastKnownAmountOfIncomings;
9780 if (newAttacks > 0) {
9781 sinceLastCheckTimeNew += newAttacks;
9782 pers.set("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter, sinceLastCheckTimeNew);
9783
9784 } else if (newAttacks < 0) {
9785 sinceLastCheckTimeArrived -= newAttacks;
9786 pers.set("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter, sinceLastCheckTimeArrived);
9787 }
9788
9789 pers.set("lastKnownAmountOfIncomings" + game_data.player.sitter, currentAmountOfIncomings);
9790
9791 $("#incomings_amount").html(variableReplacer(user_data.global.incomings.indicator));
9792 incomingAttacksLinks.attr("title", variableReplacer(user_data.global.incomings.lastTimeCheckWarning));
9793 incomingAttacksLinks.fadeOut("slow").fadeIn("slow");
9794 }
9795
9796 // extra image to set the lastCheckTime on incomings overview page
9797 if (current_page.screen === "overview_villages" && current_page.mode === "incomings") {
9798 // Tooltip for first time users
9799 if (lastCheckTime == trans.sp.incomings.indicator.lastTimeCheckNotYetSet) {
9800 // show info tooltip
9801 var position = incomingAttacksAmountLink.position();
9802 var options = {
9803 left: position.left - 200,
9804 top: position.top + 35,
9805 width: 250
9806 };
9807 var content = {body: trans.sp.incomings.indicator.lastTimeCheckHintBoxTooltip.replace("{img}", "<img src='graphic/ally_forum.png'>")};
9808 createFixedTooltip("incomingsIndicatorHelp", content, options);
9809 }
9810
9811 // change last incomings-check time
9812 incomingAttacksLinks.last().parent().after(
9813 "<td class='box-item' id='changeLastCheckTimeBox' style='white-space: nowrap'><a href='#' id='changeLastCheckTime'> "
9814 + "<img src='graphic/ally_forum.png' style='padding-top: 5px' "
9815 + "title='"+variableReplacer(user_data.global.incomings.indicatorTooltip)+"'/> </a></td>");
9816
9817 // Set last incomings-check time
9818 $("#changeLastCheckTime").click(function() {
9819 var newCheckTime = new Date();
9820 pers.set("lastKnownAmountOfIncomingsTime" + game_data.player.sitter, newCheckTime.getTime());
9821 pers.set("lastKnownAmountOfIncomings" + game_data.player.sitter, currentAmountOfIncomings);
9822 pers.set("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter, 0);
9823 pers.set("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter, 0);
9824
9825 pers.setGlobal("fixedToolTip_incomingsIndicatorHelp", 1);
9826 $("#changeLastCheckTimeBox").fadeOut();
9827 window.location.href = window.location.href;
9828 });
9829 }
9830 }
9831 } else {
9832 // When there are no more incomings, stop tracking
9833 if (user_data.global.incomings.track) {
9834 pers.set("lastKnownAmountOfIncomings" + game_data.player.sitter, 0);
9835 pers.set("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter, 0);
9836 pers.set("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter, 0);
9837 }
9838 }
9839
9840 // change incoming support link
9841 if (user_data.global.incomings.editLinks) {
9842 var incomingSupport = $("a[href*='subtype=supports']", incoming);
9843 if (incomingSupport.size() > 0) {
9844 if (user_data.global.incomings.editLinks) {
9845 incomingSupport.attr("href", incomingSupport.attr("href") + "&page=-1&group=0");
9846 }
9847 }
9848 }
9849 } catch (e) { handleException(e, "incomingsindicator"); }
9850 //console.time("incomingsindicator");
9851 }());
9852 }
9853 if (server_settings.ajaxAllowed && user_data.global.visualizeFriends) {
9854 (function() {
9855 //console.time("friends");
9856 try {
9857 function Friends() {
9858 this.lastCheck = new Date().getTime();
9859 this.online = {
9860 names: "",
9861 amount: 0
9862 };
9863 this.offlineAmount = 0;
9864 }
9865
9866 /**
9867 * Insert a 'friends' link with visual online/offline indication
9868 */
9869 function updateTWFriendsLink() {
9870 var friendsLink = $("<a href='" + getUrlString("&screen=buddies") + "'></a>");
9871 friendsLink.html(
9872 trans.sp.rest.friendsOnline
9873 .replace("{friends}", friendsLink.text())
9874 .replace("{onlineimg}", "<img src='graphic/dots/green.png' />")
9875 .replace("{online#}", friends.online.amount)
9876 .replace("{offlineimg}", "<img src='graphic/dots/red.png' />")
9877 .replace("{offline#}", friends.offlineAmount)
9878 );
9879 if (friends.online.amount > 0) {
9880 friendsLink.attr("title", trans.sp.rest.friendsOnlineTitle.replace("{playerNames}", friends.online.names.substr(1)));
9881 }
9882 $("#sanguPackageEditSettingsLink").before(friendsLink).before(" - ");
9883 }
9884
9885 /**
9886 * Parse the #content_value and update the friends link.
9887 * Is called from ajax call.
9888 * @param {string} overview the #content_value of the friends page
9889 */
9890 function parseFriendsTable(overview) {
9891 var friendsTable = $("h3+table.vis:first", overview);
9892 if (friendsTable.size() == 1) {
9893 var friendRows = friendsTable.find("tr:gt(0)");
9894 friendRows.each(function() {
9895 var friendName = $.trim($("a:first", this).text());
9896 var statusIndicatorImage = $("img:first", this);
9897 if( statusIndicatorImage.length > 0 ) {
9898 if (/red\.png/.test(statusIndicatorImage.attr("src"))) {
9899 friends.offlineAmount++;
9900 } else {
9901 if (friendName != game_data.player.name) {
9902 friends.online.names += ", " + friendName;
9903 friends.online.amount++;
9904 }
9905 }
9906 }
9907 });
9908
9909 // localStorage save of online friends
9910 pers.set("friendsOnline", JSON.stringify(friends));
9911
9912 updateTWFriendsLink();
9913 }
9914 }
9915
9916 var friends = pers.get("friendsOnline");
9917
9918 // check friends page only every 5 minutes (or when on friends page itself)
9919 if ($("#village_link").val() == "/game.php?screen=buddies") {
9920 friends = new Friends();
9921 parseFriendsTable(content_value);
9922 }
9923 else {
9924 if (friends) {
9925 friends = JSON.parse(friends);
9926 }
9927 if (!friends || friends.lastCheck < new Date().getTime() - 1000 * 60 * 3) {
9928 friends = new Friends();
9929 ajax("buddies", parseFriendsTable);
9930 } else {
9931 updateTWFriendsLink();
9932 }
9933 }
9934 } catch (e) { handleException(e, "friends"); }
9935 //console.timeEnd("friends");
9936 }());
9937 }
9938
9939
9940
9941
9942 //var end_time = new Date();
9943 //console.timeEnd("SanguPackage");
9944 //q("" + pad(Math.abs(start_time.getTime() - end_time.getTime()), 3) + " -> " + location.search);
9945 }
9946}
9947
9948if (location.href.indexOf('sangu.be') !== -1) {
9949 // sangu.be
9950(function() {
9951 // Check current version with version on the sangu.be site
9952 var lastVersion = $("#sanguPackageVersion"),
9953 resultBox = $("#versionCheckResult");
9954
9955 if (lastVersion.length === 1) {
9956 resultBox.show();
9957 resultBox.css("padding", "20px");
9958 resultBox.css("margin", "10px");
9959 resultBox.css("font-size", 18);
9960 resultBox.css("height", 30);
9961 resultBox.css("text-align", "center");
9962
9963 if ('8.197.1'.indexOf(lastVersion.text()) === 0) {
9964 resultBox.css("background-color", "green");
9965 resultBox.text("Je hebt de laatste versie!");
9966 } else {
9967 resultBox.css("background-color", "red");
9968 resultBox.text("Er is een nieuwe versie beschikbaar!");
9969 }
9970 }
9971}());
9972
9973} else if (location.href.indexOf('tribalwars.nl') !== -1) {
9974 // TribalWars page
9975(function (func, GM_xmlhttpRequest) {
9976var lastCheck = sessionStorage.lastUpdateCheck,
9977 currentVersion = '8.197.1';
9978
9979function displayNewVersion() {
9980 var a = document.createElement('a');
9981 var linkText = document.createTextNode(" - Sangu Package Update!");
9982 a.appendChild(linkText);
9983 a.title = "Er is een update voor het Sangu Package beschikbaar!";
9984 a.href = "http://sangu.be";
9985 a.style.color = "black";
9986 a.style.fontWeight = "bolder";
9987 a.style.backgroundColor = "yellow";
9988
9989 document.getElementById("linkContainer").appendChild(a);
9990}
9991
9992if (typeof GM_xmlhttpRequest !== "undefined") {
9993 if (!lastCheck) {
9994 sessionStorage.lastUpdateCheck = "done";
9995 try
9996 {
9997 // GM_xmlhttpRequest didn't work when put in sangu_ready
9998 GM_xmlhttpRequest({
9999 method: "GET",
10000 url: "http://www.sangu.be/api/sangupackageversion.php",
10001 synchronous: false,
10002 onload: function(response) {
10003 if (response.responseText !== currentVersion) {
10004 sessionStorage.lastUpdateCheck = "hasNew";
10005 displayNewVersion();
10006 }
10007 }
10008 });
10009 }
10010 catch (e)
10011 {
10012 console.log("error fetching latest version number:");
10013 console.log(e);
10014 }
10015 } else if (lastCheck === "hasNew") {
10016 displayNewVersion();
10017 }
10018}
10019
10020 var script = document.createElement('script');
10021 script.setAttribute("type", "application/javascript");
10022 if (window.mozInnerScreenX !== undefined) {
10023 // Firefox has troubles with renaming commands, villages, ... (it works some of the time)
10024 // But waiting for document.ready slows down the script so only wait for this on FF
10025 // An optimization could be to put document.readys only around those blocks that are
10026 // problematic.
10027 script.textContent = '$(document).ready(' + func + ');';
10028
10029 } else {
10030 script.textContent = '(' + func + ')();';
10031 }
10032
10033 document.body.appendChild(script); // run the script
10034 document.body.removeChild(script); // clean up
10035}(sangu_ready, (typeof GM_xmlhttpRequest === "undefined" ? undefined : GM_xmlhttpRequest)));
10036
10037
10038}