Guest User

Untitled

a guest
Jan 24th, 2019
133
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 475.44 KB | None | 0 0
  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.nl/game.php?*
  8. // @include http://sangu.be/*
  9. // @include http://www.sangu.be/*
  10. // @version 8.119.5
  11. // @grant GM_xmlhttpRequest
  12. // ==/UserScript==
  13.  
  14. //We are Sangu. You will be assimilated. Resistance is Futile.
  15.  
  16. // The not-one-file source code can be found at:
  17. // https://github.com/SanguPackage/Script
  18.  
  19. function sangu_ready() {
  20. //var start_time = new Date();
  21. //console.time("SanguPackage");
  22. var /**
  23. * When game_data.majorVersion is different from Sangu version then activate sangu 'compatibility' mode (gray icon)
  24. */
  25. sangu_version = '8.119.5',
  26. /**
  27. * true: popup with crash dump, false: don't show the popup
  28. */
  29. sangu_crash = sangu_version.split(".").length === 4,
  30. /**
  31. * jQuery element of the cell (td) that contains all page specific widgets
  32. */
  33. content_value = $("#content_value"),
  34. /**
  35. * config/ Configuration per server (nl, de). Contains stuff like ajaxAllowed, etc
  36. */
  37. server_settings = {},
  38. /**
  39. * config/ Contains all translations except for the setting related translations in sangu_trans
  40. */
  41. trans = {},
  42. /**
  43. * config/ Contains all user settings
  44. */
  45. user_data = {},
  46. /**
  47. * config/ The current world configuration. settings like hasArchers, nightbonus, etc
  48. */
  49. world_config = {},
  50. /**
  51. * config/ Contains all data for this world (resources, units, buildings, units_off, unitsSize, ...)
  52. * What's in this variable depends on world_config.
  53. * This variable is a complete and utter mess :)
  54. */
  55. world_data = {},
  56. /**
  57. * Identifies the current page based on the querystring
  58. */
  59. current_page = {
  60. screen: game_data.screen,
  61. mode: game_data.mode
  62. },
  63. keyCodeMap = {
  64. 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pausebreak", 20: "capslock", 27: "escape", 32: " ",
  65. 33: "pageup", 34: "pagedown", 35: "end", 36: "home", 37: "arrow left", 38: "arrow up", 39: "arrow right", 40: "arrow down", 43: "+",
  66. 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",
  67. 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",
  68. 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",
  69. 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7", 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111: "/", 112: "f1",
  70. 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8", 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock",
  71. 145: "scrolllock", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'"
  72. };
  73.  
  74. server_settings = {
  75. /**
  76. * Calculate how many more days we can attack in vacation mode
  77. */
  78. maxSitDays: 60,
  79. helpdeskUrl: "https://forum.tribalwars.nl/showthread.php?137674-8-11-GM-Algemeen-discussietopic-Sangu-Package",
  80. /**
  81. * This needs to be here for 'historical' reasons (Innogames versionchecker API remembers email on the server)
  82. * when in 'compatibility' mode (gray sangu icon). Also used in the crash report.
  83. */
  84. sangu: "sangu.be",
  85. sanguEmail: "sangu@pongit.be",
  86. /**
  87. * More then 500 [ cannot be sent in messages or pasted in the noteblock
  88. */
  89. allowedSquareBrackets: 500,
  90. /**
  91. * Are ajax calls allowed on this server
  92. */
  93. ajaxAllowed: true,
  94. /*
  95. * async: true on AJAX calls is only allowed when this property is true
  96. */
  97. asyncAjaxAllowed: false,
  98. /**
  99. * True: we add a direct link in the place to fill in coordinates. False: Show coords in an input field
  100. */
  101. coordinateLinkAllowed: false,
  102. /**
  103. * Can we fill in the coordinates directly in the place (using the url querystring) from troops overview
  104. */
  105. autoFillCoordinatesAllowed: true,
  106. scriptsDatabaseUrl: "http://www.twscripts.nl/"
  107. };
  108.  
  109. //$.extend(server_settings, {
  110. // extraProperty: "yaye"
  111. //});
  112. /**
  113. * Contains all translation
  114. * The highest level is split in
  115. * - tw = translations that should be translated by their server equivalents (they are used somewhere in the html by Innogames)
  116. * - sp = new translations specific for the Sangu Package
  117. */
  118. trans = {
  119. tw: {
  120. units: {
  121. 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" },
  122. 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." },
  123. 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" },
  124. militia: "Militia"
  125. },
  126. all: {
  127. today: "vandaag om",
  128. tomorrow: "morgen om",
  129. dateOn: "op",
  130. timeOn: "om",
  131. farm: "Boerderij",
  132. wood: "Hout",
  133. iron: "IJzer",
  134. stone: "Leem",
  135. groups: "Groepen",
  136. continentPrefix: "C"
  137. },
  138. main: {
  139. loyaltyHeader: "Toestemming:"
  140. },
  141. command: {
  142. returnText: "Terugkeer",
  143. attack: "Aanval",
  144. support: "Ondersteuning",
  145. haul: "Buit:",
  146. abortedOperation: "Afgebroken commando",
  147. catapultTarget: "Katapultdoel:",
  148. buttonValue: "OK",
  149. attackOn: "Aanval op ",
  150. supportFor: "Ondersteuning voor ",
  151. walkingTimeTitle: "Duur:"
  152. },
  153. incoming: {
  154. defaultCommandName: "Bevel"
  155. },
  156. place: {
  157. troopMovements: "Troepenbewegingen"
  158. },
  159. market: {
  160. incomingTransports: "Binnenkomende transporten"
  161. },
  162. profile: {
  163. title: "Profiel",
  164. claimedBy: "Geclaimd door:",
  165. awardsWon: "Behaalde awards"
  166. },
  167. overview: {
  168. village: "Dorp",
  169. incomingTroops: "Aankomend"
  170. }
  171. },
  172. sp: {
  173. sp: {
  174. settings: {
  175. reset: "De standaard Sangu Package settings herstellen",
  176. resetAll: "Sangu Package 'fabrieksinstellingen' herstellen",
  177. configuration: "Configuratie",
  178. configurationFormTogglerTooltip: "Klik op de knoppen om de verschillende editeerschermen te openen",
  179. activate: "Activeer",
  180. deleteTooltip: "Verwijderen",
  181. addRecord: "» Toevoegen",
  182. exportSettings: "Instellingen exporteren",
  183. importSettings: "Instellingen importeren",
  184. 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.",
  185. importSettingsSuccess: "Settings zijn geïmporteerd!",
  186. importError: "Het ziet er naar uit dat de geplakte tekst foutief is.",
  187. importErrorContinueAnyway: "Toch importeren?"
  188. },
  189. donate: {
  190. title: "Donatie",
  191. whyWouldI: "Als je op regelmatige basis functionaliteit van het Sangu Package gebruikt, dan is dat een goede reden om een donatie te doen."
  192. + "<br><br>"
  193. + "Jouw dankbaarheid en financiële steun helpen me motiveren verder te blijven werken aan het Sangu Package.",
  194. 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 :)",
  195. notable: "Een aantal personen hebben reeds een notabele donatie gedaan:",
  196. buttonAmount: "Doneer €{amount}",
  197. beer: "Trakteer me een biertje",
  198. food: "Een spaghetti voor Wouter! (of pizza!)",
  199. yaye: "Een nieuw IT boek voor mijn verzameling!"
  200. },
  201. configuration: "Sangu Package configureren (v{version})",
  202. activatePackage: "Sangu Package activeren",
  203. deactivatePackage: "Sangu Package deactiveren",
  204. packageCrashTitle: "Het Sangu Package is gecrasht :)",
  205. packageCrashTooltip: "Crash!!! Klik op de bol om het crash rapport te bekijken. "
  206. + "Je kan dit rapport naar ons doorsturen waardoor we het probleem mogelijk kunnen oplossen.",
  207. packageCrash:
  208. "<a href='http://" + server_settings.sangu + "'>Controleer eerst of er een update is!</a><br>"
  209. + "<b>Foutmelding</b>: <i>{error}</i><br>"
  210. + "<b>Details</b>:<br>"
  211. + "<textarea style='width: 95%' rows='20' id='crashArea'>"
  212. + "Foutmelding: {error}\n"
  213. + "Pagina: {title} -> {page}\n"
  214. + "URL: {url}\n"
  215. + "Versie: {version}\n"
  216. + "Brower: {browser}\n"
  217. + "game_data: {game_data}\n"
  218. + "\n{stacktrace}\n"
  219. + "\n\n\n[HTML]\n"
  220. + "</textarea>"
  221. + "<br><br>Je kan de bug <a href='{forum-url}' target='_blank'>hier</a> melden."
  222. + "<br>Of je kan de bug <a href='mailto:{email}'>mailen</a>."
  223. + "<br><br><center><i>Een bug waarvan we niet weten dat ie bestaat zal ook niet gefixed worden!</i></center>"
  224. + "<br><center><b>Geef zoveel mogelijk informatie mee bij het sturen van een bugrapport!!!</b></center>",
  225.  
  226. activatePackageWithCompatibility: "Sangu Package (v{version}) mogelijk incompatibel met huidige TW versie",
  227. 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.",
  228. firstTimeRunEditSettings: "Klik op de nieuwe 'Sangu Package' link om het package naar jouw smaak in te stellen!",
  229. removeScriptWarning: "Niet meer tonen",
  230. moreScripts: "Meer scripts",
  231. moreScriptsTooltip: "Ga naar de site met alle goedgekeurde TW scripts",
  232. sanguLinkTitle: "Het package naar jouw smaak instellen"
  233. },
  234. all: {
  235. populationShort: "Pop",
  236. population: "Populatie",
  237. total: "Totaal",
  238. last: "Laatste",
  239. target: "Doel",
  240. targetEx: "Doelwit",
  241. more: "meer",
  242. less: "minder",
  243. all: "Alle",
  244. withText: "met",
  245. merchants: "Handelaren",
  246. further: "verder",
  247. closer: "dichter",
  248. fieldsSuffix: "(F{0})",
  249. close: "Sluiten"
  250. },
  251. main: {
  252. unitsReplacement: "Eigen",
  253. unitsOther: "Ondersteunende Eenheden",
  254. rallyPointTroops: "troepen",
  255. ownStackTitle: "Totale populatie van de eigen troepen",
  256. supportingStackTitle: "Totale populatie van de ondersteunende troepen",
  257. showHiddenDivs: "&raquo; Alle verborgen terugzetten ({amount} verborgen)",
  258. hideDiv: "Volledig verbergen"
  259. },
  260. map: {
  261. dodgeLastTagged: "Dodgetijd van de laatst getagde aanval"
  262. },
  263. tagger: {
  264. openButton: "Open Tagger",
  265. rename: "Herbenoemen",
  266. renameTooltip: "Alle bevelen waarvan de checkbox aangevinkt is hernoemen",
  267. incomingTroops: "Binnenkomende troepen",
  268. arrival: "Aankomst",
  269. arrivalIn: "Aankomst in",
  270. sentNow: "Zojuist",
  271. sentSeconds: "seconde(n)",
  272. sent1Minute: "1 minuut",
  273. sentMinutes: "minuten",
  274. sent1Hour: "1 uur",
  275. sentHours: "uren",
  276. sentOn: "Verstuurtijd",
  277. ago: "Geleden",
  278. arrivesInNightBonus: " (NACHT!)",
  279. tagIt: "Aanval Taggen",
  280. checkAllSupport: "Aanvinken van alle zichtbare ondersteuning",
  281. uncheckAllSupport: "Uitvinken van alle zichtbare ondersteuning",
  282. tagged: "Tagged!",
  283. dodgeTime: "Dodgetijd",
  284. slowest: "Traagst",
  285. slowestTip: "Traagste eenheid in het dorp",
  286. allAbove: "Alle vroegere aanvallen aanvinken",
  287. allBelow: "Alle latere aanvallen aanvinken",
  288. renameTo: "Hernoemen naar: ",
  289. switchModus: "&raquo; Alle aanvallen openen/sluiten",
  290. checkAllAttacks: "Aanvinken van alle zichtbare aanvallen",
  291. uncheckAllAttacks: "Uitvinken van alle zichtbare aanvallen",
  292. activeDodgeTime: "Actieve dodgetijd (wordt op de kaart getoond)",
  293. totalAttacksOnVillage: "Aantal aanvallen",
  294. renameButtonShortcutTooltip: "Shortcut: CTRL + {hitkey}"
  295. },
  296. place: {
  297. distance: "Afstand",
  298. backOn: "Terug op",
  299. onlyAttack: "1 aanval op {arrivalDateFirst} ({timeLeftFirst})",
  300. multipleAttack: "{amount} aanvallen tussen {arrivalDateFirst} ({timeLeftFirst}) en {arrivalDateLast} ({timeLeftLast})",
  301. changeSpeedImageTooltips: "{originalTitle} - Klik om de traagste eenheid te wijzigen"
  302. },
  303. jumper: {
  304. goToMap: "Ga naar de kaart"
  305. },
  306. command: {
  307. returnOn: "Terug op:",
  308. arrival: "Aankomst",
  309. dodgeNotFarEnough: "De dodge is niet ver genoeg!",
  310. dodgeMinuteReturn: "(Terugkeer na {minutes})",
  311. catapultImageTitle: "Klik om gebouw te vernietigen"
  312. },
  313. overviews: {
  314. totalVillages: "Aantal dorpen:",
  315. loadNextPage: "[volgende pagina laden]"
  316. },
  317. troopOverview: {
  318. help: "<b>Laat je looptijden uitrekenen door Sangu!</b><br>"
  319. + "Gebruik de nieuwe kolom uiterst rechts om de looptijden tot een ingegeven doeldorp te berekenen.<br>"
  320. + "<br>Je kan de eenheden icons ({unitIcon}) aanklikken om de snelheid van de traagste eenheid te wijzigen."
  321. + "<span style='line-height: 2'>"
  322. + "<br>Klikken wijzigt de <span style='border: 2px green dotted'>snelheid op de huidige pagina</span>. "
  323. + "<br>Dubbelklikken wijzigt de <span style='border: 3px red solid'>snelheid op alle pagina's</span>."
  324. + "</span>"
  325. + "<br>De cellen met de groene en rode rand geven de huidige traagst eenheid-snelheid aan."
  326. + "<br><br><b>De iconen in de 'Opdracht' kolom</b>:"
  327. + "<br>Gebruik <img src='graphic/dots/red.png'> om een rij te verwijderen."
  328. + "<br>Gebruik <img src='graphic/command/attack.png'> om naar de verzamelplaats te gaan."
  329. + "(gebruik de middelste muisknop om in een nieuwe tab te openen)",
  330. helpTitle: "Snel dorpen aanvallen (of ondersteunen)",
  331. removeVillage: "Dorp verwijderen",
  332. toThePlace: "Verzamelplaats",
  333. setTargetVillageButton: "OK",
  334. setTargetVillageButtonAlert: "Geef de coördinaten van het dorp dat je wil aanvallen (of ondersteunen)",
  335. commandTitle: "Opdracht",
  336. selectUnitSpeed: "Selecteer {0} als traagste eenheid. (Klik op deze pagina, Dubbel klik op alle pagina's.)",
  337. nightBonus: "Nacht?",
  338. village: "Dorp",
  339. filterTroops: "Filter",
  340. filterTroopsTooltip: "Toon enkel de dorpen met meer dan het aangegeven aantal eenheden",
  341. filterPopulation: "Filter populatie",
  342. filterPopulationTooltip: "Toon enkel de dorpen met meer/minder bevolking",
  343. filterWalkingTime: "Filter looptijd",
  344. filterWalkingTimeTooltip: "Toon enkel de dorpen met een langere looptijd (in uren) tot het doeldorp",
  345. calcStack: "Bereken stack",
  346. calcStackTooltip: "Toon de bevolking per dorp in de \"Nacht?\" kolom",
  347. filterNoble: "Toon edels",
  348. filterNobleTooltip: "Toon enkel de dorpen waar edels aanwezig zijn",
  349. filterUnderAttack: "Toon onder aanval",
  350. filterUnderAttackTooltip: "Toon enkel de dorpen die onder aanval zijn",
  351. sort: "Sorteren",
  352. sortTooltip: "Sorteren op looptijd tot doeldorp",
  353. restack: "Stack BB Codes",
  354. restackTitle: "<b>Alle dorpen met minstens {requiredDiff}k bevolking minder dan {to}k</b><br>"
  355. + "<font size='-2'>(configuratie wijzigbaar bij Sangu instellingen)</font>",
  356. cheapNobles: "Goedkope edelmannen beschikbaar",
  357.  
  358. filtersReverse: "De filtering omdraaien",
  359. filtersReverseInfo: "Filters omdraaien",
  360. freeTextFilter: "Tekst filter",
  361. freeTextFilterTooltip: "Dorpen {filterType} de tekst wegfilteren",
  362. freeTextFilterTooltipFilterTypeWith: "met",
  363. freeTextFilterTooltipFilterTypeWithout: "zonder",
  364. continentFilter: "Continent",
  365. continentFilterTooltip: "Alle dorpen in continent wegfilteren",
  366. continentFilterTooltipReverse: "Alle dorpen in continent tonen"
  367. },
  368. prodOverview: {
  369. filter: "Filter",
  370. filterFullGS: "Volle opslag",
  371. merchantTooltip: "Vink aan om handelaren te highlighten",
  372. merchantAmountTooltip: "Als de checkbox aangevinkt is worden dorpen met minder dan x handelaren in het rood gehighlight",
  373. bbCodes: "BB Codes",
  374. bbCodesInfo: "Gebruik IMG",
  375. filterTooltip: "Dorpen die niet aan de filtercriteria voldoen verbergen",
  376. filterTooltipReverse: "Dorpen die voldoen aan de filtercriteria highlighten",
  377. filterFullGSTooltip: "Dorpen waarbij niet minstens 1 van de grondstoffen vol is verbergen",
  378. filterFullGSTooltipReverse: "Dorpen waarbij minstens 1 van de grondstoffen vol is highlighten",
  379. filterAllTooltip: "Dorpen waarbij niet minstens 1 van de grondstoffen meer/minder dan x is verbergen",
  380. filterAllTooltipReverse: "Dorpen waarbij minstens 1 van de grondstoffen meer/minder dan x is highlighten",
  381. filter1Tooltip: "Dorpen waarbij er nier meer/minder dan x {0} is verbergen",
  382. filter1TooltipReverse: "Dorpen waarbij er meer/minder dan x {0} is highlighten",
  383. tooMuch: "Teveel:",
  384. tooMuchText: "Alle dorpen met minstens {diff}k meer grondstoffen dan {min}k",
  385. tooLittle: "Te weinig:",
  386. tooLittleText: "Alle dorpen met minstens {diff}k minder grondstoffen dan {min}k",
  387. bbCodeExtraInfo: "<br><font size='-2'>(configuratie wijzigbaar bij Sangu instellingen)</font>"
  388. },
  389. buildOverview: {
  390. optimistic: "Optimistisch",
  391. mark: "Duiden",
  392. filter: "Filteren"
  393. },
  394. smithOverview: {
  395. optimistic: "Optimistisch",
  396. mark: "Duiden",
  397. filter: "Filteren"
  398. },
  399. defOverview: {
  400. stackButton: "Totalen berekenen",
  401. stackTooltip: "Totale stack en afstanden berekenen",
  402. stackFilter: "Filter op stack",
  403. stackFilterTooltip: "Filter dorpen met meer/minder dan x totale stack vanbuiten het dorp",
  404. village: "Dorp:",
  405. distFilter: "Filter op afstand",
  406. distFilterTooltip: "Filter alle dorpen die verder/dichter dan x velden liggen van dorp y",
  407. stackBBCodes: "Stack BBCodes",
  408. stackBBCodesTooltip: "Bepaal BB codes en aantal troepen voor een stack tot x populatie voor alle zichtbare dorpen",
  409. filterNoSupport: "Zonder OS wegfilteren",
  410. filterNoSupportTooltip: "Wegfilteren van alle dorpen waar geen ondersteuning meer zichtbaar is",
  411. extraFiltersSupport: "Ondersteunende dorpen filters:",
  412. extraFiltersDefense: "Ondersteuning filters:",
  413. extraFiltersReverse: "De filtering omdraaien",
  414. extraFiltersInfo: "Filters omdraaien",
  415. distFilter2: "Afstand filter",
  416. freeTextFilter: "Tekst filter",
  417. barbarianFilter: "Barbarendorpen",
  418. barbarianFilterTooltip: "Toon alle ondersteuningen naar barbarendorpen",
  419. nobleFilter: "Alle edel-ondersteuning tonen",
  420. nobleFilterRev: "Alle edel-ondersteuning wegfilteren",
  421. spyFilter: "Alle verkenner-ondersteuning tonen",
  422. spyFilterRev: "Alle verkenner-ondersteuning wegfilteren",
  423. attackFilter: "Alle aanval-ondersteuning tonen",
  424. attackFilterRev: "Alle aanval-ondersteuning wegfilteren",
  425. supportFilter: "Alle verdediging-ondersteuning tonen",
  426. supportFilterRev: "Alle verdediging-ondersteuning wegfilteren",
  427. otherPlayerFilterShow: "tonen",
  428. otherPlayerFilterHide: "wegfilteren",
  429. otherPlayerFilterTo: "Alle ondersteuningen naar andere spelers {action}",
  430. otherPlayerFilterFrom: "Alle ondersteuningen van andere spelers {action}",
  431.  
  432. filterTooltipVillageTypeSupporting: "Ondersteunende dorpen",
  433. filterTooltipVillageTypeSupported: "Ondersteunde dorpen",
  434. freeTextFilterTooltip: "{villageType} {filterType} de tekst wegfilteren",
  435. freeTextFilterTooltipFilterTypeWith: "met",
  436. freeTextFilterTooltipFilterTypeWithout: "zonder",
  437. distanceFilterTooltip: "{villageType} die {filterType} dan het aangegeven aantal velden liggen wegfilteren",
  438. distanceFilterTooltipFilterTypeCloser: "dichter",
  439. distanceFilterTooltipFilterTypeFurther: "verder",
  440.  
  441. totalFromOtherVillages: "totaal uit andere dorpen",
  442. totalInOtherVillages: "totaal in andere dorpen",
  443. freeText: "Vrij tekstveld (wordt niet opgeslagen!):",
  444. fieldsPrefix: "F{0}",
  445. thousandSuffix: "k",
  446. totalVillages: "Dorpen ({0})",
  447. distanceToVillageNoneEntered: "Geef een coördinaat! (eerste tekstveld)",
  448. distanceToVillage: "Afstand tot {0}",
  449. filterUnderAttack: "Filter onder aanval"
  450. },
  451. commands: {
  452. filterReturn: "Filter terugkeer",
  453. filterReturnTooltip: "'Teruggestuurd' en 'Terugkeer' bevelen verbergen",
  454. totalRows: "Somlijn",
  455. group: "Groeperen",
  456. totalRowsText: "{0}x OS = {1} pop",
  457. totalVillagesSupport: "Ondersteunde dorpen:",
  458. totalVillagesAttack: "Aangevallen dorpen:",
  459. totalSupport: "Ondersteuningen",
  460. totalAttack: "Aanvallen",
  461. bbCodeExport: "BBCode Export",
  462. bbCodeExportTooltip: "Overblijvende aanvallen exporteren",
  463. supportPlayerExport: "Ondersteuning exporteren",
  464. supportPlayerExportTooltip: "Geef de naam van de speler waarvoor je de ondersteuning wil exporteren "
  465. + "(of laat leeg om alle ondersteuningen te exporteren). Door de export als mededeling "
  466. + "naar de andere speler door te sturen "
  467. + "kan deze jouw gestuurde troepen als bevelnaam zetten. (Hij heeft daarvoor natuurlijk"
  468. + " ook het Sangu Package nodig :)",
  469. filtersReverse: "De filtering omdraaien",
  470. filtersReverseInfo: "Filters omdraaien",
  471. freeTextFilter: "Tekst filter",
  472. freeTextFilterTooltip: "Aanvallen {filterType} de tekst wegfilteren",
  473. freeTextFilterTooltipFilterTypeWith: "met",
  474. freeTextFilterTooltipFilterTypeWithout: "zonder",
  475. nobleFilter: "Alle edelaanvallen tonen",
  476. nobleFilterRev: "Alle edelaanvallen wegfilteren",
  477. spyFilter: "Alle verkenneraanvallen tonen",
  478. spyFilterRev: "Alle verkenneraanvallen wegfilteren",
  479. tableTotal: "Bevel ({0})",
  480. fakeFilter: "Alle fake aanvallen wegfilteren",
  481. fakeFilterRev: "Alle fake aanvallen tonen",
  482. continentFilter: "Continent",
  483. continentFilterTooltip: "Alle dorpen in continent wegfilteren",
  484. continentFilterTooltipReverse: "Alle dorpen in continent tonen",
  485. exportAttackHeader: "{village} {#} aanvallen, laatste [b]{lastAttack}[/b]",
  486. exportDefenseHeader: "{village} {support#} ondersteuningen voor [b]{totalStack} pop[/b]",
  487. exportCompleteHeader: "{village} {#} aanvallen, laatste [b]{lastAttack}[/b]\n+ {support#} ondersteuningen voor [b]{totalStack} pop[/b]",
  488. exportNone: "Geen ondersteuning gevonden!"
  489. },
  490. groups: {
  491. villageFilter: "Dorpsnaam",
  492. villageFilterTitle: "Alle dorpen met de tekst in de dorpsnaam wegfilteren",
  493. villageFilterTitleRev: "Alle dorpen met de tekst in de dorpsnaam tonen",
  494. pointsFilter: "Punten",
  495. amountFilter: "Aantal",
  496. groupNameFilter: "Groepsnaam",
  497. amountFilterTitle: "Alle dorpen met minder groepen wegfilteren",
  498. amountFilterTitleRev: "Alle dorpen met meer groepen wegfilteren",
  499. pointsFilterTitle: "Alle dorpen met minder punten wegfilteren",
  500. pointsFilterTitleRev: "Alle dorpen met meer punten wegfilteren",
  501. farmFilterTitle: "Alle dorpen met minder populatie wegfilteren",
  502. farmFilterTitleRev: "Alle dorpen met meer populatie wegfilteren",
  503. groupNameFilterTitle: "Alle dorpen met de tekst in een groepsnaam wegfilteren",
  504. groupNameFilterTitleRev: "Alle dorpen met de tekst in een groepsnaam tonen"
  505. },
  506. snob: {
  507. canProduce: "Je kan meteen produceren:"
  508. },
  509. profile: {
  510. twStatsMap: "TWStats Kaart",
  511. externalPage: "(Extern)",
  512. internalPage: "(Intern)",
  513. conquers: "Overnames",
  514. villages: "Dorpen:",
  515. graphPoints: "Punten",
  516. graphVillages: "Dorpen",
  517. graphOD: "OD Totaal",
  518. graphODD: "OD Verdediging",
  519. graphODA: "OD Aanval",
  520. graphODS: "OD Ondersteuning",
  521. graphRank: "Rang",
  522. graphMembers: "Leden",
  523. graphTWMap: "TribalWarsMap.com"
  524. },
  525. incomings: {
  526. dynamicGrouping: "Dynamisch groeperen",
  527. dynamicGroupingTooltip: "Groepeert trager maar bevriest de pagina niet",
  528. summation: "Somlijn",
  529. fastGrouping: "Snel groeperen",
  530. fastGroupingTooltip: "Groepeert sneller en bevriest de pagina (geen refreshs wanneer een aanval binnenkomt)",
  531. showNewIncomings: "Toon nieuwe aanvallen",
  532. sortByAttackId: "Sorteer op aanvalsid",
  533. sortByAttackIdTooltip: "Een kleiner aanvalsid betekent een eerder verstuurde aanval",
  534. amount: "Aanvallen:",
  535. attackId: "Aanvalsid",
  536. attackIdDifference: "Verschil",
  537. filterColumnButton: "Kolom filter",
  538. filterColumnButtonTooltip: "Alle bevelen waarbij de geselecteerde kolom de ingegeven tekst bevat {type}",
  539. filterColumnButtonTooltipHide: "verbergen",
  540. filterColumnButtonTooltipShow: "tonen",
  541.  
  542. indicator: {
  543. lastTimeCheckHintBoxTooltip: "Klik op {img} om de laatste tijdcheck met de huidige tijd te vervangen.",
  544. lastTimeCheckNotYetSet: "(nog niet)"
  545. },
  546. commandsImport: "Ondersteuning importeren",
  547. commandsImportTooltip: "Ondersteuning naar jouw dorpen kan op jouw account ingelezen worden"
  548. + " door de andere speler zijn bevelen te laten exporteren via Sangu Package (Pagina Overzicht: Bevelen)"
  549. + " en die export hier te plakken.",
  550. commandsImportError: "Fout bij het inladen van de ondersteuningen.\nHet zou er zoals dit moeten uitzien: \n"
  551. + '[{"commandName": "702|459 (speler) Zw=1 (Pop: 1)", "commandId": "7538763"}]',
  552. commandsImportSuccess: "{replaced} van de {total} ondersteuningen zijn hernoemd."
  553. },
  554. rest: {
  555. sittingAttackTill: "Aanvallen en verdedigen van dorpen niet in eigen beheer tot:",
  556. friendsOnline: "Vrienden {friends} ({onlineimg} {online#} | {offlineimg} {offline#})",
  557. friendsOnlineTitle: "Online: {playerNames}"
  558. }
  559. }
  560. };
  561.  
  562. /**
  563. * Log the parameter to the console (print yaye when undefined)
  564. */
  565. function q(what) { console.log(typeof what === "undefined" ? "yaye" : what); }
  566.  
  567. /**
  568. * Alert the parameter (yaye when undefined)
  569. */
  570. function qa(what) { alert(typeof what === "undefined" ? "yaye" : what); }
  571.  
  572. /**
  573. * Show crash report
  574. */
  575. function sangu_alert(e, title) {
  576. var activator = $("#sangu_activator");
  577.  
  578. activator
  579. .attr("src", "graphic/dots/grey.png")
  580. .attr("title", trans.sp.sp.packageCrashTooltip);
  581.  
  582. (function() {
  583. var position = $("#storage").position(),
  584. options = {
  585. left: position.left - 150,
  586. top: position.top + 35
  587. },
  588. content = {body: trans.sp.sp.packageCrashTooltip, title: trans.sp.sp.packageCrashTitle};
  589.  
  590. createFixedTooltip("sanguCrashTooltip", content, options);
  591. }());
  592.  
  593. activator.click(function() {
  594. var currentPageHtml = document.documentElement.innerHTML,
  595. position = $("#storage").position(),
  596. options = {
  597. left: $(window).width() / 2 - 300,
  598. top: position.top + 35,
  599. width: 600,
  600. showOnce: false
  601. },
  602. game_dataSubset = {
  603. majorVersion: game_data.majorVersion,
  604. market: game_data.market,
  605. world: game_data.world,
  606. sitter: game_data.player.sitter,
  607. village_id: game_data.village.id,
  608. player_id: game_data.player.id,
  609. player_name: game_data.player.name,
  610. ally_id: game_data.player.ally_id,
  611. villages: game_data.player.villages,
  612. premium: game_data.features.Premium.active/*,
  613. account_manager: game_data.features.AccountManager.active,
  614. farm_manager: game_data.features.FarmAssistent.active*/
  615. },
  616. content = {
  617. title: trans.sp.sp.packageCrashTitle,
  618. body: trans.sp.sp.packageCrash
  619. .replace("{forum-url}", server_settings.helpdeskUrl)
  620. .replace("{title}", title)
  621. .replace(/\{error\}/g, e.message)
  622. .replace("{page}", JSON.stringify(current_page))
  623. .replace("{url}", document.location.href)
  624. .replace("{version}", sangu_version)
  625. .replace("{browser}", JSON.stringify($.browser))
  626. .replace("{game_data}", JSON.stringify(game_dataSubset))
  627. .replace("{stacktrace}", e.stack ? e.stack + "\n\n" + e.stacktrace : "assertion?")
  628. .replace("{email}", server_settings.sanguEmail)
  629. .replace("{html}", currentPageHtml)
  630. };
  631.  
  632. createFixedTooltip("sanguCrash", content, options);
  633. $("#crashArea").val($("#crashArea").val() + currentPageHtml);
  634.  
  635. return false;
  636. });
  637.  
  638. for(i = 0; i < 7; i++) {
  639. activator.fadeTo('slow', 0.2).fadeTo('slow', 1.0);
  640. }
  641. if (sangu_crash) {
  642. activator.click();
  643. }
  644. }
  645.  
  646. /**
  647. * Failed assertions show the crash report!
  648. */
  649. function assert(shouldBeTruthy, message) {
  650. if (!shouldBeTruthy) {
  651. sangu_alert({message: message || "(broken assertion)"});
  652. }
  653. }
  654.  
  655. /**
  656. * Show crash report
  657. */
  658. function handleException(e, title) {
  659. sangu_alert(e, title);
  660. }
  661. function pad(number, length) {
  662. var str = '' + number;
  663. while (str.length < length) {
  664. str = '0' + str;
  665. }
  666. return str;
  667. }
  668.  
  669. /**
  670. * Gets a value from the querystring (or returns "")
  671. * @param {string} name the name of the querystring parameter
  672. * @param {string} [url] when omitted, the current location.url is assumed
  673. */
  674. function getQueryStringParam(name, url) {
  675. name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
  676. var regexS = "[\\?&]" + name + "=([^&#]*)";
  677. var regex = new RegExp(regexS);
  678. if( url == undefined && name == "village" ) {
  679. return game_data.village.id;
  680. } else {
  681. var results = regex.exec(url == undefined ? window.location.href : url);
  682. if (results == null) {
  683. return "";
  684. } else {
  685. return results[1];
  686. }
  687. }
  688. }
  689.  
  690. /**
  691. * Get a TW url taking account sitting etc in account
  692. * @param {string} url provide the url starting from &screen=
  693. * @param {number} [villageId] when omitted the current village is assumed
  694. */
  695. function getUrlString(url, villageId) {
  696. if (url.indexOf("?") == -1) {
  697. var link = location.href.substr(0, location.href.indexOf("?"));
  698. link += "?village=" + (villageId ? villageId : getQueryStringParam("village"));
  699. var isSit = getQueryStringParam("t");
  700. if (isSit) {
  701. link += "&t=" + isSit;
  702. }
  703.  
  704. if (url.indexOf("=") == -1) {
  705. return link + "&screen=" + url;
  706. } else {
  707. return link + "&" + url;
  708. }
  709. } else {
  710. return url;
  711. }
  712. }
  713.  
  714. /**
  715. * Perform an ajax call (if the server allows it)
  716. * @param {string} screen passed to getUrlString. (start from &screen=)
  717. * @param {function} strategy executed on success. Has parameter text (content of the parameter depends on opts.contentValue)
  718. * @param {object} [opts] object with properties
  719. * {false|number} [villageId] passed to getUrlString. Default is false which defaults to current village. Otherwise pass a village id.
  720. * {boolean=true} [contentValue] true (default): only return the #content_value. false: return entire DOM HTML
  721. * {boolean=true} [async] defaults to true
  722. */
  723. function ajax(screen, strategy, opts) {
  724. if (!server_settings.ajaxAllowed) {
  725. alert("Ajax is not allowed on this server.");
  726. return;
  727. }
  728.  
  729. opts = $.extend({}, { villageId: false, contentValue: true, async: false }, opts);
  730.  
  731. $.ajax({
  732. url: getUrlString(screen, opts.villageId),
  733. async: server_settings.asyncAjaxAllowed ? opts.async : false,
  734. success: function(text) {
  735. text = opts.contentValue ? $("#content_value", text) : text;
  736. strategy(text);
  737. }
  738. });
  739. }
  740.  
  741. function spSpeedCookie(setter) {
  742. if (setter == undefined) {
  743. var speedCookie = pers.get("targetVillageSpeed");
  744. if (speedCookie == '') {
  745. speedCookie = 'ram';
  746. }
  747. return speedCookie;
  748. } else {
  749. if (setter.indexOf('_') == 4) {
  750. setter = setter.substr(setter.indexOf('_') + 1);
  751. }
  752. pers.set("targetVillageSpeed", setter);
  753. return setter;
  754. }
  755. }
  756.  
  757. function spTargetVillageCookie(setter) {
  758. if (setter == undefined) {
  759. return pers.get("targetVillageCoord");
  760. } else {
  761. pers.set("targetVillageCoord", setter);
  762. return setter;
  763. }
  764. }
  765.  
  766. function getDistance(x1, x2, y1, y2, speed) {
  767. var dist = {};
  768. dist.fields = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
  769. dist.travelTime = dist.fields * (speed == '' ? world_data.unitsSpeed.unit_ram : world_data.unitsSpeed['unit_' + speed]);
  770. dist.arrivalTime = getDateFromTW($("#serverTime").text(), true);
  771. dist.arrivalTime.setTime(dist.arrivalTime.getTime() + (dist.travelTime * 60 * 1000));
  772. dist.isNightBonus = isDateInNightBonus(dist.arrivalTime);
  773.  
  774. if (speed == 'snob' && dist.travelTime > world_config.maxNobleWalkingTime) {
  775. dist.html = "<font color='" + user_data.colors.error + "'><b>" + twDurationFormat(dist.travelTime) + "</b></font>";
  776. dist.isNightBonus = true;
  777. } else {
  778. var displayTime = twDateFormat(dist.arrivalTime);
  779. if (speed != 'merchant' && dist.isNightBonus) {
  780. displayTime = "<font color='" + user_data.colors.error + "'><b>" + displayTime + "</b></font>";
  781. }
  782. dist.html = user_data.walkingTimeDisplay
  783. .replace("{duration}", twDurationFormat(dist.travelTime))
  784. .replace("{arrival}", displayTime);
  785. }
  786. if (dist.fields == 0) {
  787. dist.html = "";
  788. }
  789.  
  790. return dist;
  791. }
  792. /*
  793. _gaq.push(['b._setAccount', 'UA-30075487-3']);
  794. */
  795. /**
  796. * Send click to google analytics
  797. * @param {string} action
  798. */
  799. function trackClickEvent(action) {
  800. trackEvent("ButtonClick", action);
  801. }
  802.  
  803. /**
  804. * google analytics event tracking
  805. */
  806. function trackEvent(category, action, label) {
  807. // category: clicks (downloads, ...)
  808. // action: which button clicked
  809. if (typeof label === 'undefined') {
  810. label = getQueryStringParam("screen");
  811. var mode = getQueryStringParam("mode");
  812. if (mode) label += "-" + mode;
  813. }
  814.  
  815. //_gaq.push(['b._setAccount', 'UA-30075487-3']);
  816. //_gaq.push(['b._trackPageview']);
  817. // _gat._getTrackerByName('b')._trackEvent("SanguPackage", "Loaded", "withGetB");
  818. try
  819. {
  820. _gat._getTrackerByName('b')._trackEvent(category, action, label);
  821. }
  822. catch (e) {
  823. // no crash report for this
  824. }
  825. }
  826.  
  827. function fillRallyPoint(units) {
  828. var script = "";
  829. $.each(world_data.units, function (i, v) {
  830. if (units[v] != undefined && units[v] > 0) {
  831. script += "document.forms[0]." + v + ".value=\"" + units[v] + "\";";
  832. } else {
  833. script += "document.forms[0]." + v + ".value=\"\";";
  834. }
  835. });
  836.  
  837. return script;
  838. }
  839.  
  840. /**
  841. * Tries to find village coords in str and convert it to a 'village' object
  842. * @param {string} str the string to be converted to a village object
  843. * @param {true|} looseMatch !!!Do not provide a value for looseMatch when converting a real village name.!!!
  844. * It should be set to true when it was the user that provided the input str. When true,
  845. * a str like 456-789 would also match. (so that Sangu Package users don't have to use | but can instead
  846. * use anything to seperate the 2 coordinates).
  847. * @returns {object} object with parameters isValid: false when the string could not be matched and true with extra properties
  848. * x, y, coord, validName (=html friendly id name) and continent
  849. */
  850. function getVillageFromCoords(str, looseMatch) {
  851. // if str is "villageName (X|Y) C54" then the villageName could be something like "456-321"
  852. // the regex then thinks that the villageName are the coords
  853. // looseMatch
  854. var targetMatch = looseMatch != undefined ? str.match(/(\d+)\D(\d+)/g) : str.match(/(\d+)\|(\d+)/g);
  855. if (targetMatch != null && targetMatch.length > 0) {
  856. var coordMatch = targetMatch[targetMatch.length - 1].match(/(\d+)\D(\d+)/);
  857. var village = { "isValid": true, "coord": coordMatch[1] + '|' + coordMatch[2], "x": coordMatch[1], "y": coordMatch[2] };
  858.  
  859. village.validName = function () { return this.x + '_' + this.y; };
  860. village.continent = function () { return this.y.substr(0, 1) + this.x.substr(0, 1); };
  861.  
  862. return village;
  863. }
  864. return { "isValid": false };
  865. }
  866.  
  867. function buildAttackString(villageCoord, unitsSent, player, isSupport, minimum, haulDescription) {
  868. var seperator = " ";
  869. if (minimum == undefined) {
  870. minimum = 0;
  871. }
  872.  
  873. var totalPop = 0;
  874. var renamed = villageCoord == null ? "" : villageCoord + seperator;
  875. var sent = "";
  876. $.each(world_data.units, function (i, val) {
  877. var amount = unitsSent[val];
  878. if (amount != 0) {
  879. if (val == "snob") {
  880. renamed += trans.tw.units.names[val] + "! ";
  881. }
  882. else if (amount >= minimum) {
  883. sent += ", " + trans.tw.units.shortNames[val] + "=" + amount;
  884. }
  885.  
  886. totalPop += amount * world_data.unitsPositionSize[i];
  887. }
  888. });
  889.  
  890. if (player) {
  891. renamed += '(' + player + ')' + seperator;
  892. }
  893. if (sent.length > 2) {
  894. sent = sent.substr(2);
  895. }
  896.  
  897. if (isSupport) {
  898. sent += seperator + "(" + trans.sp.all.populationShort + ": " + formatNumber(totalPop) + ")";
  899. }
  900.  
  901. if (user_data.attackAutoRename.addHaul && typeof haulDescription !== 'undefined') {
  902. sent += " (" + trans.tw.command.haul + " " + haulDescription + ")";
  903. }
  904.  
  905. return renamed + sent;
  906. }
  907.  
  908. function calcTroops(units) {
  909. // units is an array of numbers; keys are the unit names (without unit_)
  910. var x = {};
  911. x.totalDef = 0;
  912.  
  913. function removeElement(arr, element) {
  914. var idx = arr.indexOf(element);
  915. if (idx != -1) {
  916. arr.splice(idx, 1);
  917. }
  918. return arr;
  919. }
  920.  
  921. // heavy doesn't count in determining whether the village is def/off (since you got some crazy guys using hc as offense and defense:)
  922. $.each(removeElement(world_data.units_def, 'heavy'), function (i, v) { x.totalDef += units[v] * world_data.unitsSize['unit_' + v]; });
  923. x.totalOff = 0;
  924. $.each(removeElement(world_data.units_off, 'heavy'), function (i, v) { x.totalOff += units[v] * world_data.unitsSize['unit_' + v]; });
  925.  
  926. x.isDef = x.totalDef > x.totalOff;
  927. x.isScout = units.spy * world_data.unitsSize.unit_spy > x.totalDef + x.totalOff;
  928. x.isMatch = function (type) { return (type == 'all' || (type == 'def' && this.isDef) || (type == 'off' && !this.isDef)); };
  929.  
  930. x.getSlowest =
  931. function () {
  932. var slowest_unit = null;
  933. $.each(world_data.units, function (i, v) {
  934. if (units[v] > 0 && (slowest_unit == null || world_data.unitsSpeed["unit_" + slowest_unit] < world_data.unitsSpeed["unit_" + v])) {
  935. slowest_unit = v;
  936. }
  937. });
  938. return slowest_unit;
  939. };
  940.  
  941. x.colorIfNotRightAttackType =
  942. function (cell, isAttack) {
  943. var isSet = false;
  944. if (units.snob != undefined && units.snob > 0) {
  945. if (isAttack) {
  946. if (units.snob > 1) {
  947. isSet = true;
  948. cell.css("background-color", user_data.colors.error).css("border", "1px solid black");
  949. cell.animate({
  950. width: "70%",
  951. opacity: 0.4,
  952. marginLeft: "0.6in",
  953. fontSize: "3em",
  954. borderWidth: "10px"
  955. }, 5000, function () {
  956. // Animation complete.
  957. });
  958. } else {
  959. return;
  960. }
  961. } else {
  962. isSet = true;
  963. }
  964. }
  965. else if (x.totalDef + x.totalOff < user_data.command.filterFakeMaxPop) {
  966. // fake
  967. return;
  968. }
  969.  
  970. if (!isSet && (x.isScout || x.isMatch(isAttack ? 'off' : 'def'))) {
  971. return;
  972. }
  973. cell.css("background-color", user_data.colors.error);
  974. };
  975.  
  976. return x;
  977. }
  978.  
  979.  
  980. function stackDisplay(totalFarm, stackOptions) {
  981. // TODO: this function is only used on main village overview
  982. if (stackOptions == undefined) {
  983. stackOptions = {};
  984. }
  985. var farmSize = game_data.village.buildings.farm * world_config.farmLimit;
  986.  
  987. var stackDesc = '<b>' + formatNumber(totalFarm);
  988. if (stackOptions.showFarmLimit && world_config.farmLimit > 0) {
  989. stackDesc += ' / ' + formatNumber(farmSize);
  990. }
  991.  
  992. if (stackOptions.percentage) {
  993. stackDesc += ' (' + stackOptions.percentage + ')</b>';
  994. }
  995.  
  996. var bgColor = getStackColor(totalFarm, farmSize);
  997. if (stackOptions.cell == undefined) {
  998. return {
  999. color: bgColor,
  1000. desc: stackDesc,
  1001. cssColor: "style='background-color:" + bgColor + "'"
  1002. };
  1003. } else {
  1004. if (stackOptions.appendToCell) {
  1005. stackOptions.cell.append(" &raquo; " + stackDesc);
  1006. } else {
  1007. stackOptions.cell.html(stackDesc);
  1008. }
  1009. if (!stackOptions.skipColoring) {
  1010. stackOptions.cell.css("background-color", bgColor);
  1011. }
  1012. }
  1013. }
  1014.  
  1015. /**
  1016. * Gets the configured stack backgroundcolor for the given stackTotal
  1017. * @param stackTotal {number}
  1018. * @returns {color}
  1019. */
  1020. function getStackColor(stackTotal) {
  1021. var color = null,
  1022. arrayToIterate,
  1023. farmLimitModifier;
  1024.  
  1025. if (world_config.farmLimit > 0) {
  1026. arrayToIterate = user_data.farmLimit.acceptableOverstack;
  1027. farmLimitModifier = 30 * world_config.farmLimit;
  1028. } else {
  1029. arrayToIterate = user_data.farmLimit.unlimitedStack;
  1030. farmLimitModifier = 1; // = No modifier
  1031. }
  1032.  
  1033. if (arrayToIterate.length > 0) {
  1034. $.each(arrayToIterate, function (index, configValue) {
  1035. if (color == null && stackTotal < farmLimitModifier * configValue) {
  1036. if (index === 0) {
  1037. color = "";
  1038. } else {
  1039. color = user_data.farmLimit.stackColors[index - 1];
  1040. //q(stackTotal +"<"+ farmLimitModifier +"*"+ configValue);
  1041. //q("return " + (index - 1) + "->" + color);
  1042. }
  1043. return false;
  1044. }
  1045. });
  1046.  
  1047. if (color != null) {
  1048. //q(stackTotal + " -> " + color);
  1049. return color;
  1050. }
  1051. return user_data.farmLimit.stackColors[user_data.farmLimit.stackColors.length - 1];
  1052. }
  1053.  
  1054. return "";
  1055. }
  1056. var modernizr = (function () {
  1057. // Difference in capital letter with the Modernizr library
  1058. // So nothing will break should TW start making use of it
  1059. return {
  1060. localstorage: (function supports_html5_storage() {
  1061. try {
  1062. return 'localStorage' in window && window['localStorage'] !== null;
  1063. } catch (e) {
  1064. return false;
  1065. }
  1066. })()
  1067. };
  1068. })();
  1069.  
  1070. var pers;
  1071. (function (pers) {
  1072. function getKey(key) {
  1073. return 'sangu_' + key;
  1074. }
  1075.  
  1076. function getWorldKey(key) {
  1077. return 'sangu_' + game_data.world + '_' + key;
  1078. }
  1079.  
  1080. function getCookie(key) {
  1081. key = getWorldKey(key);
  1082. return (function() {
  1083. var x, cooks, cookie;
  1084. if (document.cookie.match(/;/)) {
  1085. cooks = document.cookie.split("; ");
  1086. for (x = 0; x < cooks.length; x++) {
  1087. cookie = cooks[x];
  1088. if (cookie.match(key + "=")) {
  1089. return cookie.replace(key + "=", "");
  1090. }
  1091. }
  1092. } else {
  1093. if (document.cookie.match(key + "=")) {
  1094. return document.cookie.replace(key + "=", "");
  1095. }
  1096. }
  1097.  
  1098. return '';
  1099. })();
  1100. }
  1101.  
  1102. function getGlobal(key) {
  1103. key = getKey(key);
  1104. if (modernizr.localstorage) {
  1105. var value = localStorage[key];
  1106. return typeof value === 'undefined' ? '' : value;
  1107. } else {
  1108. return getCookie(key);
  1109. }
  1110. }
  1111.  
  1112. function getSession(key) {
  1113. key = getWorldKey(key);
  1114. if (modernizr.localstorage) {
  1115. var value = sessionStorage[key];
  1116. return typeof value === 'undefined' ? '' : value;
  1117. } else {
  1118. return getCookie(key);
  1119. }
  1120. }
  1121.  
  1122. function get(key) {
  1123. return getGlobal(key);
  1124. }
  1125.  
  1126. function setCookie(key, value, expireMinutes) {
  1127. key = getWorldKey(key);
  1128. (function() {
  1129. var date_obj = new Date(),
  1130. time = date_obj.getTime();
  1131. if (typeof expireMinutes === 'undefined') {
  1132. time += 60 * 1000 * 24 * 356;
  1133. } else {
  1134. time += expireMinutes * 1000 * 60;
  1135. }
  1136. date_obj.setTime(time);
  1137.  
  1138. document.cookie = key + "=" + value + ";expires=" + date_obj.toGMTString() + ";";
  1139. })();
  1140. }
  1141.  
  1142. function setGlobal(key, value) {
  1143. key = getKey(key);
  1144. if (modernizr.localstorage) {
  1145. localStorage[key] = value;
  1146. } else {
  1147. setCookie(key, value);
  1148. }
  1149. }
  1150.  
  1151. function setSession(key, value) {
  1152. key = getWorldKey(key);
  1153. if (modernizr.localstorage) {
  1154. sessionStorage[key] = value;
  1155. } else {
  1156. setCookie(key, value);
  1157. }
  1158. }
  1159.  
  1160. function set(key, value) {
  1161. setGlobal(key, value);
  1162. }
  1163.  
  1164. function removeSessionItem(key) {
  1165. key = getKey(key);
  1166. if (modernizr.localstorage) {
  1167. sessionStorage.removeItem(key);
  1168. }
  1169. // fuck cookies
  1170. }
  1171.  
  1172. function clear() {
  1173. if (modernizr.localstorage) {
  1174. sessionStorage.clear();
  1175. localStorage.clear();
  1176. }
  1177. }
  1178.  
  1179. pers.removeSessionItem = removeSessionItem;
  1180. pers.getWorldKey = getWorldKey;
  1181. pers.getKey = getKey;
  1182. pers.set = set;
  1183. pers.setCookie = setCookie;
  1184. pers.setGlobal = setGlobal;
  1185. pers.setSession = setSession;
  1186. pers.get = get;
  1187. pers.getCookie = getCookie;
  1188. pers.getGlobal = getGlobal;
  1189. pers.getSession = getSession;
  1190. pers.clear = clear;
  1191. })(pers || (pers = {}));
  1192. $.fn.sortElements = (function () {
  1193. var sort = [].sort;
  1194. return function (comparator, getSortable) {
  1195. getSortable = getSortable || function () { return this; };
  1196. var placements = this.map(function () {
  1197. var sortElement = getSortable.call(this),
  1198. parentNode = sortElement.parentNode,
  1199. // Since the element itself will change position, we have
  1200. // to have some way of storing its original position in
  1201. // the DOM. The easiest way is to have a 'flag' node:
  1202. nextSibling = parentNode.insertBefore(
  1203. document.createTextNode(''),
  1204. sortElement.nextSibling
  1205. );
  1206.  
  1207. return function () {
  1208. if (parentNode === this) {
  1209. throw new Error("You can't sort elements if any one is a descendant of another.");
  1210. }
  1211.  
  1212. // Insert before flag:
  1213. parentNode.insertBefore(this, nextSibling);
  1214. // Remove flag:
  1215. parentNode.removeChild(nextSibling);
  1216. };
  1217. });
  1218.  
  1219. return sort.call(this, comparator).each(function (i) {
  1220. placements[i].call(getSortable.call(this));
  1221. });
  1222. };
  1223. })();
  1224.  
  1225. $.fn.outerHTML =
  1226. function () {
  1227. return $('<div>').append(this.clone()).remove().html();
  1228. };
  1229.  
  1230. /**
  1231. * Create a dialog box on a fixed position with self closing functionality
  1232. * @param {string} id The DOM ID of the div
  1233. * @param content .title: Short title. Defaults to Sangu Package.
  1234. * .body: The HTML to show in the body of the tooltip
  1235. * @param options .top: CSS top in px
  1236. * .left: CSS left in px
  1237. * .width: CSS width in px. Defaults to 350.
  1238. * .showOnce: If true the tooltip will never be shown again once closed. Defaults to true.
  1239. */
  1240. function createFixedTooltip(id, content, options) {
  1241. if (typeof options.width === 'undefined') {
  1242. options.width = 350;
  1243. }
  1244. if (typeof options.showOnce === 'undefined') {
  1245. options.showOnce = true;
  1246. }
  1247. if (typeof content.title === 'undefined') {
  1248. content.title = "Sangu Package";
  1249. }
  1250.  
  1251. var persKey = "fixedToolTip_"+id; // Other implementations depend on this naming
  1252. if (!options.showOnce || pers.getGlobal(persKey) == '') {
  1253. content_value.after('<div id="' + id + '" class="vis" style="z-index: 100001; margin: 2px; '
  1254. + 'width: '+options.width+'px; display: block; position:absolute; top: '+options.top+'px; left: '+options.left+'px; border: 1px solid black; background-color: #F4E4BC">'
  1255. + '<h4>' + '<img class="'+id+'closeTooltip" style="float: right; cursor: pointer;" src="graphic/minus.png">' + content.title + '</h4>'
  1256. + '<div style="display: block; text-align: left; margin: 2px;">' + content.body + '</div>'
  1257. + '</div>');
  1258.  
  1259. $("."+id+"closeTooltip", "#" + id).click(function() {
  1260. $("#" + id).hide();
  1261. if (options.showOnce) {
  1262. pers.setGlobal(persKey, "1");
  1263. }
  1264. });
  1265. }
  1266. }
  1267.  
  1268. function createSpoiler(button, content, opened) {
  1269. return "<div id='spoiler'><input type='button' value='" + button + "' onclick='toggle_spoiler(this)' /><div><span style='display:" + (opened ? 'block' : 'none') + "'>" + content + "</span></div></div>";
  1270. }
  1271.  
  1272. function createMoveableWidget(id, title, content) {
  1273. return '<div id=' + id + '+ class="vis moveable widget"><h4><img style="float: right; cursor: pointer;"'
  1274. + ' onclick="return VillageOverview.toggleWidget(\'' + id + '\', this);" src="graphic/minus.png">'
  1275. + title + '</h4><div style="display: block;">' + content + '</div></div>';
  1276. }
  1277.  
  1278. function printCoord(village, desc) {
  1279. if (server_settings.coordinateLinkAllowed) {
  1280. return "<a href=# onclick=\"$('#inputx').val("+village.x+"); $('#inputy').val("+village.y+"); return false;\">" + desc + "</a>";
  1281. } else {
  1282. return "<b>" + desc + "</b> <input type=text onclick='this.select(); this.focus()' size=7 value='" + village.x + '|' + village.y + "'>";
  1283. }
  1284. }
  1285.  
  1286. // Activate / deactivate the tool
  1287. var isSanguActive = pers.get("sanguActive") == "true";
  1288. if (location.href.indexOf('changeStatus=') > -1) {
  1289. isSanguActive = location.href.indexOf('changeStatus=true') > -1;
  1290. pers.set("sanguActive", isSanguActive);
  1291. pers.setGlobal("fixedToolTip_sanguActivatorTooltip", 1);
  1292. }
  1293.  
  1294. var activatorImage = isSanguActive ? "green" : 'red';
  1295. var activatorTitle = (!isSanguActive ? trans.sp.sp.activatePackage : trans.sp.sp.deactivatePackage) + " (v" + sangu_version + ")";
  1296.  
  1297. function isSanguCompatible() {
  1298. return sangu_version.indexOf(game_data.majorVersion) === 0;
  1299. }
  1300.  
  1301. // Check for new version
  1302. var loginMonitor = pers.get("sanguLogin");
  1303. if (typeof GM_xmlhttpRequest !== "undefined" && !isSanguCompatible() && loginMonitor !== '') {
  1304. var parts = loginMonitor.match(/(\d+)/g);
  1305. if (parseInt(parts[2], 10) != (new Date()).getDate()) {
  1306. GM_xmlhttpRequest({
  1307. method: "GET",
  1308. url: "http://www.sangu.be/api/sangupackageversion.php",
  1309. onload: function (response) {
  1310. console.log(response.status, response.responseText.substring (0, 80));
  1311. }
  1312. });
  1313.  
  1314. }
  1315. }
  1316.  
  1317. if (pers.get("forceCompatibility") === '' || pers.get("forceCompatibility") === 'false') {
  1318. if (isSanguActive) {
  1319. // Check compatibility with TW version
  1320. if (!isSanguCompatible()) {
  1321. try {
  1322. ScriptAPI.register('Sangu Package', sangu_version, 'Laoujin', server_settings.sanguEmail);
  1323. } catch (e) {
  1324. $("#script_list a[href$='mailto:"+server_settings.sanguEmail+"']").after(" &nbsp;<a href='' id='removeScriptWarning'>"+trans.sp.sp.removeScriptWarning+"</a>");
  1325. $("#removeScriptWarning").click(function() {
  1326. pers.set("forceCompatibility", "true");
  1327. });
  1328. }
  1329. }
  1330. }
  1331.  
  1332. // gray icon when tw version doesn't match
  1333. if (!isSanguCompatible()) {
  1334. activatorImage = "grey";
  1335. activatorTitle = trans.sp.sp.activatePackageWithCompatibility.replace("{version}", sangu_version);
  1336. }
  1337. }
  1338.  
  1339. $("#storage").parent()
  1340. .after(
  1341. "<td class='icon-box' nowrap><a href=" + location.href.replace("&changeStatus=" + isSanguActive, "")
  1342. + "&changeStatus=" + (!isSanguActive) + "><img src='graphic/dots/" + activatorImage
  1343. + ".png' title='" + activatorTitle
  1344. + "' id='sangu_activator' /></a>&nbsp;</td>");
  1345.  
  1346. // First time run message - Position beneath resource/storage display
  1347. if (!isSanguActive) {
  1348. (function() {
  1349. var position = $("#storage").position(),
  1350. options = {
  1351. left: position.left - 150,
  1352. top: position.top + 35
  1353. },
  1354. content = {body: trans.sp.sp.firstTimeRun.replace("{img}", "<img src='graphic/dots/red.png' />")};
  1355.  
  1356. createFixedTooltip("sanguActivatorTooltip", content, options);
  1357. }());
  1358. } else {
  1359. (function() {
  1360. var position = $("#storage").position(),
  1361. options = {
  1362. left: position.left - 150,
  1363. top: position.top + 35
  1364. },
  1365. 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!'};
  1366.  
  1367. createFixedTooltip("twTacticsTooltip", content, options);
  1368. }());
  1369. }
  1370.  
  1371. // User config
  1372. // Configure the Sangu Package
  1373.  
  1374. /*
  1375. user_data = pers.get('sangusettings');
  1376. if (user_data !== '') {
  1377. user_data = JSON.parse(user_data);
  1378.  
  1379. } else {*/
  1380. user_data = {
  1381. proStyle: true,
  1382. displayDays: false, /* true: display (walking)times in days when > 24 hours. false: always displays in hours */
  1383. walkingTimeDisplay: "{duration} || {arrival}",
  1384.  
  1385. colors: {
  1386. error: "#FF6347",
  1387. good: "#32CD32",
  1388. special: "#00FFFF",
  1389. neutral: "#DED3B9"
  1390. },
  1391.  
  1392. global: {
  1393. resources: {
  1394. active: true, /* All pages: true/false: color the resources based on how much the storage is filled */
  1395. 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 */
  1396. blinkWhenStorageFull: true /* All pages: Blink the resources if the storage is full */
  1397. },
  1398. incomings: {
  1399. editLinks: true, /* All pages: Edit the incoming attacks/support links: add "show all groups" and "show all pages" to the original links */
  1400. track: true,
  1401. indicator: "({current} <small>{difference}</small>)",
  1402. indicatorTooltip: "Laatste tijdcheck: {elapsed} geleden",
  1403. lastTimeCheckWarning: "Aanvallen: {difference}. Laatste tijdcheck: {elapsed} geleden"
  1404. },
  1405. visualizeFriends: true,
  1406. duplicateLogoffLink: false
  1407. },
  1408.  
  1409. scriptbar: {
  1410. editBoxCols: 700,
  1411. editBoxRows: 12
  1412. },
  1413.  
  1414. main: {
  1415. 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'] */
  1416. 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 */
  1417. ajaxLoyalty: true /* Get the loyalty at the building construction/destruction page */
  1418. },
  1419.  
  1420. other: {
  1421. calculateSnob: true, /* nobles: calculates how many nobles can be produced immediately */
  1422. reportPublish: ["own_units", "own_losses", "opp_units", "opp_losses", "carry", "buildings", "own_coords", "opp_coords", "belief"] /* Publishing report: automatically check the 'show' checkboxes */
  1423. },
  1424.  
  1425. market: {
  1426. resizeImage: true,
  1427. autoFocus: true
  1428. },
  1429.  
  1430. farmLimit: {
  1431. stackColors: ['#DED3B9', '#3CB371', '#FF6347'],
  1432. acceptableOverstack: [0.5, 1.2, 1.35], /* Different pages: % of acceptable overstack (only relevant for farmlimit worlds) */
  1433. unlimitedStack: [24000, 60000, 100000] /* Different pages: Calculate stacks based on total troops (for non farmlimit worlds) */
  1434. },
  1435.  
  1436. command: { /* features for the own troops overview page */
  1437. changeTroopsOverviewLink: true, /* Change the link to the own troops overview */
  1438. middleMouseClickDeletesRow2: false, /* Let the new default overwrite the old one */
  1439.  
  1440. filterMinPopulation: 18000, /* Default number filled in to filter on village stack */
  1441. filterMinDefaultType: 'axe', /* This unit type is by default selected in the filter dropdown */
  1442. filterMinDefault: 5000, /* The default number filled in to filter on troop amounts */
  1443. 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 */
  1444. filterMinOther: 5000, /* Use this number as the default when the unit is not present in filterMin */
  1445. filterAutoSort: true, /* Automatically sort the list on walking distance when entering a target village */
  1446.  
  1447. /* These features apply to the commands overview page */
  1448. sumRow: true, /* Add a totalrow between different villages */
  1449. filterFakeMaxPop: 300, /* Commands fake filter: Everything below 300 pop is considered a fake attack */
  1450. bbCodeExport: { /* BB code export */
  1451. requiredTroopAmount: 100
  1452. }
  1453. },
  1454.  
  1455. incomings: {
  1456. attackIdDescriptions: [
  1457. {minValue: 10, text: "&nbsp;"},
  1458. {minValue: 50, text: "10-50"},
  1459. {minValue: 100, text: "50-100"},
  1460. {minValue: 200, text: "100-200"},
  1461. {minValue: 500, text: "200-500"},
  1462. {minValue: 1000, text: "500-1000"},
  1463. {minValue: 5000, text: "1000-5000"}
  1464. ],
  1465. attackIdHigherDescription: "5000+"
  1466. },
  1467.  
  1468.  
  1469. overviews: {
  1470. addFancyImagesToOverviewLinks: true
  1471. },
  1472.  
  1473. incoming: { /* Features for the built in TW tagger */
  1474. autoOpenTagger: true, /* Open the tagger automatically if the incoming attack has not yet been renamed */
  1475. forceOpenTagger: true, /* Always open the tagger automatically */
  1476. 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. */
  1477. villageBoxSize: 600, /* Adjust the width of the table with the village information (support for 2-click) */
  1478. invertSort: true /* true=noblemen at the top and scouts at the bottom of the table */
  1479. },
  1480.  
  1481. overview: { /* The default village overview page */
  1482. ajaxSeperateSupport: true, /* Village overview: Seperate own and supported troops */
  1483. ajaxSeperateSupportStacks: true, /* Village overview: Calculate stacks for own and supported troops */
  1484. canHideDiv: true
  1485. },
  1486.  
  1487. mainTagger2: {
  1488. active: true,
  1489. autoOpen: true,
  1490. inputBoxWidth: 300,
  1491. defaultDescription: "{xy} OK",
  1492. otherDescs:
  1493. [
  1494. { active: true, name: "Dodgen", hitKey: "D", renameTo: "{xy}----------------------------------------- DODGE THIS" },
  1495. { active: true, name: "Nacht", hitKey: "N", renameTo: "{xy} NIGHTBONUS" },
  1496. { active: true, name: "Check stack", hitKey: "P", renameTo: "{xy}----------------------------------------- CHECK STACK" },
  1497. { active: true, name: "Timen!", hitKey: "T", renameTo: "{xy}***************************************** TIME IT!" },
  1498. { active: true, name: "Edelen!", hitKey: "E", renameTo: "{xy}----------------------------------------- NOBLE!!" },
  1499. { active: false, name: "Leeg1", hitKey: "L", renameTo: "It has to be, automatically" },
  1500. { active: false, name: "Leeg2", hitKey: "U", renameTo: "Check it out, you'd better work it out" },
  1501. { active: false, name: "Leeg3", hitKey: "Y", renameTo: "Change to another route" },
  1502. { active: false, name: "Leeg4", hitKey: "O", renameTo: "My techniques, strategies, abilities" }
  1503. ],
  1504. keepReservedWords: true,
  1505. reservedWords: [
  1506. "Edel.", "Edelman",
  1507. "Ram", "Kata.", "Katapult",
  1508. "Zcav.", "Zware cavalerie",
  1509. "Lcav.", "Lichte Cavalerie", "Bereden boog", "Bboog.",
  1510. "Verk.", "Verkenner",
  1511. "Bijl", "Zwaard", "Speer", "Boog",
  1512. "Ridder"
  1513. ],
  1514. autoOpenCommands: false,
  1515. minutesDisplayDodgeTimeOnMap: 3,
  1516. minutesWithoutAttacksDottedLine: 3 * 60,
  1517. colorSupport: '#FFF5DA' /* Main village overview: give incoming support a different background color */
  1518. },
  1519.  
  1520. villageInfo4: [
  1521. {
  1522. /* On info_village page add extra link to attack. */
  1523. active: true,
  1524. off_link: {
  1525. name: "Aanvalleuh!",
  1526. group: 0,
  1527. filter: {
  1528. active: true,
  1529. unit: "axe",
  1530. amount: 5000
  1531. },
  1532. sort: true,
  1533. changeSpeed: "ram",
  1534. icon: "graphic/unit/unit_knight.png"
  1535. },
  1536. def_link: {
  1537. name: "Verdedigen!",
  1538. group: 0,
  1539. filter: {
  1540. active: true,
  1541. unit: "spear",
  1542. amount: 4000
  1543. },
  1544. sort: true,
  1545. changeSpeed: "spear",
  1546. icon: "graphic/command/support.png"
  1547. }
  1548. },
  1549. {
  1550. /* On info_village page add extra link to attack. */
  1551. active: false,
  1552. off_link: {
  1553. name: "&raquo; off2",
  1554. group: 0,
  1555. filter: {
  1556. active: false,
  1557. unit: "axe",
  1558. amount: 4000
  1559. },
  1560. sort: true,
  1561. changeSpeed: "ram"
  1562. },
  1563. def_link: {
  1564. name: "&raquo; Snelle Os!",
  1565. group: 0,
  1566. filter: {
  1567. active: true,
  1568. unit: "spear",
  1569. amount: 1000
  1570. },
  1571. sort: true,
  1572. changeSpeed: "spear"
  1573. }
  1574. }
  1575. ],
  1576.  
  1577. resources: {
  1578. requiredResDefault: 250000,
  1579. requiredMerchants: 50,
  1580. filterMerchants: true,
  1581. filterRows: false,
  1582. bbcodeMinimumDiff: 50000,
  1583. highlightColor: "#FF7F27"
  1584. },
  1585.  
  1586. jumper: {
  1587. enabled: true,
  1588. autoShowInputbox: false
  1589. },
  1590.  
  1591. attackAutoRename: {
  1592. active: true,
  1593. addHaul: false
  1594. },
  1595.  
  1596. confirm: {
  1597. addExtraOkButton: false,
  1598. replaceNightBonus: true,
  1599. replaceTribeClaim: true,
  1600. addCatapultImages: true
  1601. },
  1602.  
  1603. place: {
  1604. attackLinks: {
  1605. scoutVillage: 100,
  1606. scoutPlaceLinks: [5, 100, 500],
  1607. scoutPlaceLinksName: "Scout{amount}",
  1608.  
  1609. fakePlaceLink: true,
  1610. fakePlaceExcludeTroops: [],
  1611. fakePlaceLinkName: "Fake",
  1612.  
  1613. noblePlaceLink: true, /* (de)Activate all noble links */
  1614. noblePlaceLinkFirstName: "NobleFirst", /* Name for the first noble which has most troops */
  1615.  
  1616. noblePlaceLinkSupportName: "NobleMin", /* snob with only minimal support */
  1617. noblePlaceLinksForceShow: true, /* Show NobleMin also where is only one 1 snob in the village */
  1618. nobleSupport: [
  1619. { amount: 50, unit: 'light', villageType: 'off' },
  1620. { amount: 50, unit: 'heavy', villageType: 'def'}
  1621. ],
  1622.  
  1623. noblePlaceLinkDivideName: "NobleDivide",
  1624. noblePlaceLinkDivideAddRam: false /* false: Rams are not sent along with NobleDivide */
  1625. },
  1626. customPlaceLinks:
  1627. [
  1628. // use minus zero numbers to leave so many units at home
  1629. { active: true, type: 'def', name: 'AllDef', spear: 25000, heavy: 5000, archer: 25000, sword: 25000, sendAlong: 0 },
  1630. { active: true, type: 'def', name: '1/2-Zc', spear: 4000, heavy: 1000, sendAlong: 500 },
  1631. { 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 },
  1632. { active: true, type: 'off', name: 'Bijl', spear: 25000, axe: 25000, spy: 1, light: 5000, heavy: 5000, marcher: 5000, sendAlong: 0 },
  1633. { 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] },
  1634.  
  1635. { active: false, type: 'def', name: 'AlleDef', spear: 25000, sword: 25000, heavy: 5000, archer: 25000, sendAlong: 0 },
  1636. { active: false, type: 'def', name: '3deZc', spear: 2500, heavy: 650, sendAlong: 0 },
  1637. { active: false, type: 'def', name: '4deZc', spear: 2000, heavy: 500, sendAlong: 0 },
  1638. { active: false, type: 'def', name: 'HelftZw', spear: 5000, sword: 5000, sendAlong: 500 },
  1639. { active: false, type: 'def', name: '3deZw', spear: 3300, sword: 3300, sendAlong: 0 },
  1640. { active: false, type: 'def', name: '4deZw', spear: 2500, sword: 2500, sendAlong: 0 }
  1641. ]
  1642. },
  1643.  
  1644. /**
  1645. * units_support_detail: options on the 2 def troop overview pages
  1646. * on bbcode restack - and others!!)
  1647. */
  1648. restack: {
  1649. to: 72000,
  1650. requiredDifference: 1000,
  1651. fieldsDistanceFilterDefault: 30,
  1652. filterReverse: true,
  1653. autohideWithoutSupportAfterFilter: true,
  1654. calculateDefTotalsAfterFilter: true,
  1655. defaultPopulationFilterAmount: 80000, /* this isn't related to restack */
  1656. removeRowsWithoutSupport: false
  1657. },
  1658.  
  1659. showPlayerProfileOnVillage: false,
  1660. profile: {
  1661. show: true,
  1662. moveClaim: true,
  1663. mapLink: {
  1664. show: true,
  1665. fill: '#000000',
  1666. zoom: '200',
  1667. grid: true,
  1668. playerColor: '#ffff00',
  1669. tribeColor: '#0000FF',
  1670. centreX: 500,
  1671. centreY: 500,
  1672. ownColor: '#FFFFFF',
  1673. markedOnly: true,
  1674. yourTribeColor: "#FF0000"
  1675. },
  1676. playerGraph: [["points", false], ["villages", false], ["od", false], ["oda", false], ["odd", false], ["rank", false]], // small / big / false
  1677. tribeGraph: [["points", false], ["villages", false], ["od", false], ["oda", false], ["odd", false], ["rank", false], ["members", 'big', true]],
  1678. twMapPlayerGraph: { player: [true, true], p_player: [false, false], oda_player: [true, false], odd_player: [true, false], ods_player: [true, false] },
  1679. twMapTribeGraph: { tribe: [true, true], p_tribe: [false, false], oda_tribe: [true, false], odd_tribe: [true, false] },
  1680.  
  1681. popup: {
  1682. show: true,
  1683. width: 900,
  1684. height: 865,
  1685. left: 50,
  1686. top: 50
  1687. }
  1688. },
  1689. smithy:
  1690. [
  1691. ['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]}],
  1692. ['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]}],
  1693. ['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]}]
  1694. ],
  1695. buildings: {
  1696. main: [20, 20],
  1697. barracks: [25, 25],
  1698. stable: [20, 20],
  1699. garage: [1, 5],
  1700. church: [0, 1],
  1701. church_f: [0, 1],
  1702. snob: [1, 3],
  1703. smith: [20, 20],
  1704. place: [1, 1],
  1705. statue: [0, 1],
  1706. market: [10, 20],
  1707. wood: [30, 30],
  1708. stone: [30, 30],
  1709. iron: [30, 30],
  1710. farm: [30, 30],
  1711. storage: [30, 30],
  1712. hide: [0, 10],
  1713. wall: [20, 20]
  1714. }
  1715. };
  1716. //}
  1717.  
  1718. (function() {
  1719. var saved_data = pers.get('sangusettings');
  1720. if (saved_data !== '') {
  1721. user_data = $.extend(true, user_data, JSON.parse(saved_data));
  1722. }
  1723. }());
  1724.  
  1725. if (isSanguActive) {
  1726. // world config: global game settings
  1727. world_config = {
  1728. hasMilitia: false,
  1729. nightbonus: {
  1730. active: false,
  1731. from: 0,
  1732. till: 0
  1733. },
  1734. smithyLevels: true,
  1735. hasChurch: false,
  1736. hasArchers: false,
  1737. hasKnight: false,
  1738. speed: 1,
  1739. unitSpeed: 1,
  1740. farmLimit: 0,
  1741. minFake: 0,
  1742. hasMinFakeLimit: false,
  1743. coins: false,
  1744. maxNobleWalkingTime: 999
  1745. };
  1746.  
  1747. if (pers.get('worldconfig') !== '') {
  1748. world_config = JSON.parse(pers.get("worldconfig"));
  1749.  
  1750. } else {
  1751. // load new world through tw API
  1752. if (server_settings.ajaxAllowed) {
  1753. function world_config_setter_unit(configBag, unitInfoXml) {
  1754. configBag.hasMilitia = $("config militia", unitInfoXml).length !== 0;
  1755. }
  1756.  
  1757. function world_config_setter(configBag, infoXml) {
  1758. configBag.nightbonus = {
  1759. active: $("night active", infoXml).text() === "1",
  1760. from: parseInt($("night start_hour", infoXml).text(), 10),
  1761. till: parseInt($("night end_hour", infoXml).text(), 10)
  1762. };
  1763. configBag.smithyLevels = $("game tech", infoXml).text() === "1" || $("game tech", infoXml).text() === "0";
  1764. configBag.hasChurch = $("game church", infoXml).text() !== "0";
  1765. configBag.hasArchers = $("game archer", infoXml).text() !== "0";
  1766. configBag.hasKnight = $("game knight", infoXml).text() !== "0";
  1767. configBag.speed = parseFloat($("config speed", infoXml).text());
  1768. configBag.unitSpeed = parseFloat($("config unit_speed", infoXml).text());
  1769. configBag.farmLimit = parseInt($("game farm_limit", infoXml).text(), 10);
  1770. configBag.minFake = parseInt($("game fake_limit", infoXml).text(), 10) / 100;
  1771. configBag.hasMinFakeLimit = configBag.minFake > 0;
  1772. configBag.coins = $("snob gold", infoXml).text() === "1";
  1773. configBag.maxNobleWalkingTime = parseInt($("snob max_dist", infoXml).text(), 10) * configBag.speed * configBag.unitSpeed;
  1774. }
  1775.  
  1776. function world_config_getter(world) {
  1777. // world nl: http://nl16.tribalwars.nl/
  1778. // world de: http://de90.die-staemme.de/
  1779. if (typeof world === 'undefined') world = '';
  1780.  
  1781. var world_config = {};
  1782. $.ajax({
  1783. url: world + "interface.php?func=get_unit_info",
  1784. async: false,
  1785. success: function(xml) {
  1786. world_config_setter_unit(world_config, xml);
  1787. }
  1788. });
  1789.  
  1790. $.ajax({
  1791. url: world + "interface.php?func=get_config",
  1792. async: false,
  1793. success: function(xml) {
  1794. world_config_setter(world_config, xml);
  1795. }
  1796. });
  1797. return world_config;
  1798. }
  1799. world_config = world_config_getter();
  1800.  
  1801. } else {
  1802. // Not allowed to get data with ajax: need to store the configuration here
  1803. //world_config = (function() {
  1804. // paste the world configurations for all worlds on servers that disallow ajax
  1805. //})();
  1806. alert("No configurations present for this server! (see world_config.js)\nContinueing with default settings.");
  1807. }
  1808.  
  1809. pers.set("worldconfig", JSON.stringify(world_config));
  1810. }
  1811. // world config
  1812. // RESOURCES
  1813. world_data.resources = ['holz', 'lehm', 'eisen'];
  1814. world_data.resources_en = ['wood', 'stone', 'iron'];
  1815.  
  1816. // BUILDINGS
  1817. world_data.buildingsSize =
  1818. [
  1819. ["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]],
  1820. ["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]],
  1821. ["stable", [8, 9, 11, 13, 15, 18, 21, 24, 28, 33, 38, 45, 53, 62, 72, 84, 99, 115, 135, 158]],
  1822. ["garage", [8, 9, 11, 13, 15, 18, 21, 24, 28, 33, 38, 45, 53, 62, 72]],
  1823. ["snob", [80, 94, 110]],
  1824. ["smith", [20, 23, 27, 32, 37, 44, 51, 60, 70, 82, 96, 112, 132, 154, 180, 211, 247, 289, 338, 395]],
  1825. ["place", [0]],
  1826. ["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]],
  1827. ["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]],
  1828. ["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]],
  1829. ["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]],
  1830. ["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]],
  1831. ["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]],
  1832. ["hide", [2, 2, 3, 3, 4, 4, 5, 6, 7, 8]],
  1833. ["wall", [5, 6, 7, 8, 9, 11, 13, 15, 18, 21, 24, 28, 33, 38, 45, 53, 62, 72, 84, 99]]
  1834. ];
  1835.  
  1836. world_data.buildingsPoints =
  1837. [
  1838. ["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]],
  1839. ["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]],
  1840. ["stable", [20, 24, 29, 35, 41, 50, 60, 72, 86, 103, 124, 149, 178, 214, 257, 308, 370, 444, 532, 639]],
  1841. ["garage", [24, 29, 35, 41, 50, 60, 72, 86, 103, 124, 149, 178, 214, 257, 308]],
  1842. ["snob", [512, 614, 737]],
  1843. ["smith", [19, 23, 27, 33, 39, 47, 57, 68, 82, 98, 118, 141, 169, 203, 244, 293, 351, 422, 506, 607]],
  1844. ["place", [0]],
  1845. ["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]],
  1846. ["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]],
  1847. ["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]],
  1848. ["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]],
  1849. ["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]],
  1850. ["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]],
  1851. ["hide", [5, 6, 7, 9, 10, 12, 15, 18, 21, 26]],
  1852. ["wall", [8, 10, 12, 14, 17, 20, 24, 29, 34, 41, 50, 59, 71, 86, 103, 123, 148, 177, 213, 256]]
  1853. ];
  1854.  
  1855. world_data.buildings = ["main", "barracks", "stable", "garage"];
  1856. if (world_config.hasChurch) {
  1857. world_data.buildingsSize.push(["church", [5000, 7750, 12013]]);
  1858. world_data.buildingsSize.push(["church_f", [5]]);
  1859. world_data.buildings.push("church");
  1860. }
  1861. world_data.buildings = world_data.buildings.concat(["snob", "smith", "place"]);
  1862. if (world_config.hasKnight) {
  1863. world_data.buildingsSize.push(["statue", [10]]);
  1864. world_data.buildingsPoints.push(["statue", [24]]);
  1865. world_data.buildings.push("statue");
  1866. }
  1867. world_data.buildings = world_data.buildings.concat(["market", "wood", "stone", "iron", "farm", "storage", "hide", "wall"]);
  1868.  
  1869.  
  1870. // UNITS
  1871. 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 };
  1872. 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 };
  1873.  
  1874. world_data.units_def = ["spear", "sword", "heavy"];
  1875. world_data.units_off = ["axe", "light", "heavy"];
  1876. if (!world_config.hasArchers && !world_config.hasKnight) {
  1877. world_data.unitsPositionSize = [1, 1, 1, 2, 4, 6, 5, 8, 100];
  1878. world_data.units = ["spear", "sword", "axe", "spy", "light", "heavy", "ram", "catapult", "snob"];
  1879. } else {
  1880. world_data.units = ["spear", "sword", "axe"];
  1881. world_data.unitsPositionSize = [1, 1, 1];
  1882. if (world_config.hasArchers) {
  1883. world_data.units_off.push("marcher");
  1884. world_data.units_def.push("archer");
  1885. $.extend(world_data.unitsSize, { "unit_archer": 1 }, { "unit_marcher": 5 });
  1886. $.extend(world_data.unitsSpeed, { "unit_archer": 18 }, { "unit_marcher": 10 });
  1887. world_data.units.push("archer");
  1888. world_data.unitsPositionSize.push(1);
  1889. }
  1890. world_data.units.push("spy");
  1891. world_data.unitsPositionSize.push(2);
  1892. world_data.units.push("light");
  1893. world_data.unitsPositionSize.push(4);
  1894. if (world_config.hasArchers) {
  1895. world_data.units.push("marcher");
  1896. world_data.unitsPositionSize.push(5);
  1897. }
  1898. world_data.units.push("heavy");
  1899. world_data.unitsPositionSize.push(6);
  1900. world_data.units.push("ram");
  1901. world_data.unitsPositionSize.push(5);
  1902. world_data.units.push("catapult");
  1903. world_data.unitsPositionSize.push(8);
  1904. if (world_config.hasKnight) {
  1905. $.extend(world_data.unitsSize, { "unit_knight": 10 });
  1906. $.extend(world_data.unitsSpeed, { "unit_knight": 10 });
  1907. world_data.units.push("knight");
  1908. world_data.unitsPositionSize.push(10);
  1909. }
  1910. world_data.units.push("snob");
  1911. world_data.unitsPositionSize.push(100);
  1912. }
  1913.  
  1914. // Unit speed adjustments
  1915. world_config.maxNobleWalkingTime *= world_data.unitsSpeed.unit_snob;
  1916. var speedModifier = world_config.speed * world_config.unitSpeed;
  1917. if (speedModifier != 1) {
  1918. $.each(world_data.unitsSpeed, function (index, value) {
  1919. world_data.unitsSpeed[index] = world_data.unitsSpeed[index] / speedModifier;
  1920. });
  1921. }
  1922.  
  1923. /**
  1924. * Adds a . thousands separator
  1925. */
  1926. function formatNumber(nStr) {
  1927. nStr += '';
  1928. var x = nStr.split('.');
  1929. var x1 = x[0];
  1930. var x2 = x.length > 1 ? '.' + x[1] : '';
  1931. var rgx = /(\d+)(\d{3})/;
  1932. while (rgx.test(x1)) {
  1933. x1 = x1.replace(rgx, '$1' + '.' + '$2');
  1934. }
  1935. return x1 + x2;
  1936. }
  1937. // DATETIME FUNCTIONS
  1938. function prettyDate(diff, showSeconds) {
  1939. diff = diff / 1000;
  1940. if (diff < 0) {
  1941. return "&nbsp;";
  1942. }
  1943. if (diff < 60) {
  1944. if (showSeconds) {
  1945. return diff + " " + trans.sp.tagger.sentSeconds;
  1946. }
  1947. return trans.sp.tagger.sentNow;
  1948. }
  1949. if (diff < 120) {
  1950. return trans.sp.tagger.sent1Minute;
  1951. }
  1952. if (diff < 3600) {
  1953. return Math.floor(diff / 60) + " " + trans.sp.tagger.sentMinutes;
  1954. }
  1955. if (diff < 7200) {
  1956. return trans.sp.tagger.sent1Hour + ", " + Math.floor((diff - 3600) / 60) + " " + trans.sp.tagger.sentMinutes;
  1957. }
  1958. return Math.floor(diff / 3600) + " " + trans.sp.tagger.sentHours + ", " + Math.floor((diff % 3600) / 60) + " " + trans.sp.tagger.sentMinutes;
  1959. }
  1960.  
  1961. function twDurationFormat(num) {
  1962. var days = 0;
  1963. if (user_data.displayDays) {
  1964. days = Math.floor(num / 1440);
  1965. }
  1966. num -= days * 1440;
  1967. var hours = Math.floor(num / 60);
  1968. num -= hours * 60;
  1969. var mins = Math.floor(num);
  1970. num -= mins;
  1971. var secs = Math.round(num * 60);
  1972.  
  1973. if (days > 0) {
  1974. return days + '.' + pad(hours, 2) + ':' + pad(mins, 2) + ':' + pad(secs, 2);
  1975. } else {
  1976. return pad(hours, 2) + ':' + pad(mins, 2) + ':' + pad(secs, 2);
  1977. }
  1978. }
  1979.  
  1980. function twDateFormat(dat, alwaysPrintFullDate, addYear) {
  1981. var day = dat.getDate();
  1982. var cur = new Date().getDate();
  1983.  
  1984. if (!alwaysPrintFullDate && day == cur) {
  1985. return trans.tw.all.today + " " + pad(dat.getHours(), 2) + ':' + pad(dat.getMinutes(), 2) + ':' + pad(dat.getSeconds(), 2);
  1986. }
  1987. else if (!alwaysPrintFullDate && day == cur + 1) {
  1988. return trans.tw.all.tomorrow + " " + pad(dat.getHours(), 2) + ':' + pad(dat.getMinutes(), 2) + ':' + pad(dat.getSeconds(), 2);
  1989. }
  1990. else if (addYear) {
  1991. 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() + ")";
  1992. } else {
  1993. 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() + ")";
  1994. }
  1995. }
  1996.  
  1997. function getTimeFromTW(str) {
  1998. // NOTE: huh this actually returns the current date
  1999. // with some new properties with the "str" time
  2000. //17:51:31
  2001. var timeParts = str.split(":");
  2002. var seconds = timeParts[2];
  2003. var val = {};
  2004. val.hours = parseInt(timeParts[0], 10);
  2005. val.minutes = parseInt(timeParts[1], 10);
  2006. if (seconds.length > 2) {
  2007. var temp = seconds.split(".");
  2008. val.seconds = parseInt(temp[0], 10);
  2009. val.milliseconds = parseInt(temp[1], 10);
  2010. } else {
  2011. val.seconds = parseInt(seconds, 10);
  2012. }
  2013. val.totalSecs = val.seconds + val.minutes * 60 + val.hours * 3600;
  2014. return val;
  2015. }
  2016.  
  2017. function getDateFromTW(str, isTimeOnly) {
  2018. //13.02.11 17:51:31
  2019. var timeParts, seconds;
  2020. if (isTimeOnly) {
  2021. timeParts = str.split(":");
  2022. seconds = timeParts[2];
  2023. var val = new Date();
  2024. val.setHours(timeParts[0]);
  2025. val.setMinutes(timeParts[1]);
  2026. if (seconds.length > 2) {
  2027. var temp = seconds.split(".");
  2028. val.setSeconds(temp[0]);
  2029. val.setMilliseconds(temp[1]);
  2030. } else {
  2031. val.setSeconds(seconds);
  2032. }
  2033. return val;
  2034. } else {
  2035. var parts = str.split(" ");
  2036. var dateParts = parts[0].split(".");
  2037. timeParts = parts[1].split(":");
  2038. seconds = timeParts[2];
  2039. var millis = 0;
  2040. if (seconds.length > 2) {
  2041. var temp = seconds.split(".");
  2042. seconds = temp[0];
  2043. millis = temp[1];
  2044. } if (dateParts[2].length == 2) {
  2045. dateParts[2] = (new Date().getFullYear() + '').substr(0, 2) + dateParts[2];
  2046. }
  2047.  
  2048. return new Date(dateParts[2], (dateParts[1] - 1), dateParts[0], timeParts[0], timeParts[1], seconds, millis);
  2049. }
  2050. }
  2051.  
  2052. function getDateFromTodayTomorrowTW(str) {
  2053. var currentT = new Date();
  2054. var dateParts = [];
  2055. var parts = $.trim(str).split(" ");
  2056. if (str.indexOf(trans.tw.all.tomorrow) != -1) {
  2057. // morgen om 06:35:29 uur
  2058. dateParts[0] = currentT.getDate() + 1;
  2059. dateParts[1] = currentT.getMonth();
  2060. } else if (str.indexOf(trans.tw.all.today) != -1) {
  2061. // vandaag om 02:41:40 uur
  2062. dateParts[0] = currentT.getDate();
  2063. dateParts[1] = currentT.getMonth();
  2064. } else {
  2065. // op 19.05. om 11:31:51 uur
  2066. dateParts = parts[1].split(".");
  2067. dateParts[1] = parseInt(dateParts[1], 10) - 1;
  2068. }
  2069.  
  2070. // last part is "hour" but there is a script from lekensteyn that
  2071. // corrects the projected arrival time each second
  2072. // the script has not been updated to add the word "hour" after the time.
  2073. var timeParts = parts[parts.length - 2].split(":");
  2074. if (timeParts.length === 1) {
  2075. timeParts = parts[parts.length - 1].split(":");
  2076. }
  2077.  
  2078. var seconds = timeParts[2];
  2079. var millis = 0;
  2080. if (seconds.length > 2) {
  2081. var temp = seconds.split(".");
  2082. seconds = temp[0];
  2083. millis = temp[1];
  2084. }
  2085.  
  2086. return new Date(new Date().getFullYear(), dateParts[1], dateParts[0], timeParts[0], timeParts[1], seconds, millis);
  2087. }
  2088.  
  2089. function isDateInNightBonus(date) {
  2090. if (!world_config.nightbonus.active) return false;
  2091. return date.getHours() >= world_config.nightbonus.from && date.getHours() < world_config.nightbonus.till;
  2092. }
  2093. function getBuildingSpace() {
  2094. var total = 0;
  2095. for (var building = 0; building < world_data.buildingsSize.length; building++) {
  2096. var b = world_data.buildingsSize[building];
  2097. if (parseInt(game_data.village.buildings[b[0]], 10) > 0) {
  2098. total += b[1][parseInt(game_data.village.buildings[b[0]], 10) - 1];
  2099. }
  2100. }
  2101. return total;
  2102. }
  2103.  
  2104. function getBuildingPoints() {
  2105. var total = 0;
  2106. for (var building = 0; building < world_data.buildingsPoints.length; building++) {
  2107. var b = world_data.buildingsPoints[building];
  2108. if (parseInt(game_data.village.buildings[b[0]], 10) > 0) {
  2109. total += b[1][parseInt(game_data.village.buildings[b[0]], 10) - 1];
  2110. }
  2111. }
  2112. return total;
  2113. }
  2114.  
  2115. if (user_data.jumper.enabled) {
  2116. (function() {
  2117. //console.time("jumper");
  2118. try {
  2119. var cell = "<span style='display: none;' id=sanguJumperFrame>";
  2120. cell += "<input type=text type=text size=6 id=sangujumper style='height: 16px; border: 0; top: -2px; position: relative'>";
  2121. cell += "</span>";
  2122. cell += "&nbsp;<a href=# id=sangujumperOpen><span class='icon ally internal_forum' title='" + trans.sp.jumper.goToMap + "'></span></a>";
  2123. $("#menu_row2").append("<td>" + cell + "</td>");
  2124.  
  2125. $("#sangujumper").keyup(function (e) {
  2126. if (e.which == 13) {
  2127. $("#sangujumperOpen").click();
  2128. }
  2129. });
  2130.  
  2131. $("#sangujumperOpen").click(function () {
  2132. var input = $("#sangujumper");
  2133. if ($("#sanguJumperFrame").is(":visible")) {
  2134. var village = getVillageFromCoords(input.val(), true);
  2135. if (village.isValid) {
  2136. trackClickEvent("JumperOpen_RealValue");
  2137. // Jump to coordinates on the map
  2138. location.href = getUrlString("&screen=map&x=" + village.x + "&y=" + village.y);
  2139.  
  2140. } else {
  2141. // incorrect coordinates
  2142. if (!$("#sangujumperpos").is(":visible")) {
  2143. $("#sangujumperpos").show();
  2144. input.css("border", "1px solid red");
  2145. } else
  2146. $("#sangujumperpos").hide();
  2147. }
  2148. } else {
  2149. // activate mapJumper
  2150. var input = $("#sangujumper");
  2151. if (input.val() == "") {
  2152. $("#sanguJumperFrame").fadeIn();
  2153. } else {
  2154. $("#sanguJumperFrame").show();
  2155. $("#sangujumperOpen").click();
  2156. }
  2157. }
  2158.  
  2159. return false;
  2160. });
  2161.  
  2162. if (user_data.jumper.autoShowInputbox) {
  2163. $("#sangujumperOpen").click();
  2164. }
  2165. } catch (e) { handleException(e, "jumper"); }
  2166. //console.timeEnd("jumper");
  2167. }());
  2168. }
  2169. // Send usage statistics to GA once/day
  2170. (function() {
  2171. //console.time("ga");
  2172. try {
  2173. var loginMonitor = pers.get("sanguLogin");
  2174. if (loginMonitor !== '') {
  2175. var parts = loginMonitor.match(/(\d+)/g);
  2176. loginMonitor = new Date(parts[0], parts[1]-1, parts[2]);
  2177.  
  2178. //if (Math.abs(loginMonitor.getTime() - (new Date()).getTime()) > 1000 * 3600 * 24) {
  2179. if (parseInt(parts[2], 10) != (new Date()).getDate()) {
  2180. loginMonitor = '';
  2181. }
  2182. }
  2183. if (loginMonitor === '') {
  2184. loginMonitor = new Date();
  2185. loginMonitor.setHours(0, 0, 0);
  2186. loginMonitor = loginMonitor.getFullYear() + '-' + pad(loginMonitor.getMonth()+1, 2) + '-' + pad(loginMonitor.getDate(), 2);
  2187. trackEvent("ScriptUsage", "DailyUsage", loginMonitor);
  2188. pers.set("sanguLogin", loginMonitor);
  2189.  
  2190. // also log world/tribe usage
  2191. trackEvent("ScriptUsage", "WorldUsage", game_data.world);
  2192. trackEvent("ScriptUsage", "TribeUsage", game_data.world + " " + game_data.player.ally_id);
  2193. trackEvent("ScriptUsage", "HasPremium", game_data.features.Premium.active ? "Yes" : "No"); // Do we need to support non PA users?
  2194. trackEvent("ScriptUsage", "HasAM", game_data.features.AccountManager.active ? "Yes" : "No"); // Do we need to do stuff on the AM pages?
  2195. }
  2196. } catch (e) { handleException(e, "ga"); }
  2197. //console.timeEnd("ga");
  2198. }());
  2199.  
  2200. q("-------------------------------------------------------------------- Start: "+sangu_version);
  2201.  
  2202. // BEGIN PAGE PROCESSING
  2203. switch (current_page.screen) {
  2204. case "overview":
  2205. // MAIN VILLAGE OVERVIEW
  2206. (function() {
  2207. /**
  2208. * The slowest unit in the village in the form unit_spear
  2209. */
  2210. var slowest_unit = null;
  2211.  
  2212. (function() {
  2213. /**
  2214. * Each key is in the form unit_sword and holds the total amount of the type in the village
  2215. * (own and supporting troops combined)
  2216. */
  2217. var totalUnits = {},
  2218. /**
  2219. * Total population of all units (own + supporting)
  2220. */
  2221. totalFarm = 0,
  2222. /**
  2223. * Own population only (total - supporting)
  2224. */
  2225. ownFarmTotal = 0,
  2226. /**
  2227. * jQuery div with the troops in the village (becomes the own troops only div)
  2228. */
  2229. unitTable = $("#show_units"),
  2230. /**
  2231. * HTML table builder string for the supporting troops div
  2232. */
  2233. supportingTroopsTable = "<table class=vis width='100%'>";
  2234.  
  2235. try {
  2236. $("#show_units > h4").prepend(trans.sp.main.unitsReplacement);
  2237.  
  2238. // calculate current stack
  2239. $("table:first td", unitTable).not(":last").each(function () {
  2240. var unit = $('img', this)[0].src,
  2241. unitsSize,
  2242. unitAmount;
  2243.  
  2244. unit = unit.substr(unit.lastIndexOf('/') + 1);
  2245. unit = unit.substr(0, unit.lastIndexOf('.'));
  2246. unitsSize = world_data.unitsSize[unit];
  2247. unitAmount = $('strong', this);
  2248. unitAmount[0].id = "spAmount" + unit;
  2249. unitAmount = unitAmount[0].innerHTML;
  2250. if( unit.match("knight") && !unitAmount ) {
  2251. unitAmount = 1;
  2252. }
  2253. totalUnits[unit] = unitAmount;
  2254. totalFarm += unitsSize * unitAmount;
  2255.  
  2256. if (slowest_unit == null || world_data.unitsSpeed[slowest_unit] < world_data.unitsSpeed[unit]) {
  2257. slowest_unit = unit;
  2258. }
  2259. });
  2260.  
  2261. // fetch own troops
  2262. if (user_data.overview.ajaxSeperateSupport && totalFarm > 0) {
  2263. if (server_settings.ajaxAllowed) {
  2264. ajax("place",
  2265. function (placeText) {
  2266. if (placeText.find(".unitsInput").size() > 0) {
  2267. slowest_unit = null;
  2268. placeText.find(".unitsInput").each(function () {
  2269. // separate own / supporting troops
  2270. var unit = 'unit_' + this.id.substr(this.id.lastIndexOf("_") + 1);
  2271. var unitAmount = $(this).next().text().substr(1);
  2272. unitAmount = parseInt(unitAmount.substr(0, unitAmount.length - 1), 10);
  2273. var unitsSize = world_data.unitsSize[unit];
  2274. ownFarmTotal += unitsSize * unitAmount;
  2275.  
  2276. var unitLabel = $("#spAmount" + unit);
  2277. var supportingTroopsAmount = totalUnits[unit] - unitAmount;
  2278. if (supportingTroopsAmount > 0) {
  2279. var unitDesc = $.trim(unitLabel.parent().text());
  2280. unitDesc = unitDesc.substr(unitDesc.indexOf(" ") + 1);
  2281. supportingTroopsTable +=
  2282. "<tr><td>" + unitLabel.prev().outerHTML()
  2283. + " <b>" + formatNumber(supportingTroopsAmount)
  2284. + "</b> "
  2285. + unitDesc + "</td></tr>";
  2286. }
  2287.  
  2288. if (unitAmount > 0) {
  2289. unitLabel.text(unitAmount);
  2290. if (slowest_unit == null || world_data.unitsSpeed[slowest_unit] < world_data.unitsSpeed[unit]) {
  2291. slowest_unit = unit;
  2292. }
  2293. } else {
  2294. unitLabel.parent().parent().hide();
  2295. }
  2296. });
  2297.  
  2298. } else {
  2299. ownFarmTotal = totalFarm; // No rally point
  2300. }
  2301. }, {async: false});
  2302.  
  2303. } else {
  2304. ownFarmTotal = totalFarm; // No ajax
  2305. }
  2306.  
  2307. if (slowest_unit != null) {
  2308. $("#slowestUnitCell").html("<img title='"+trans.sp.tagger.slowestTip+"' src='graphic/unit/" + slowest_unit + ".png'>").attr("slowestUnit", slowest_unit);
  2309. }
  2310.  
  2311. if (ownFarmTotal > 0 && user_data.overview.ajaxSeperateSupportStacks) {
  2312. // stack in the village
  2313. unitTable.find("table:first").append("<tr><td><span class='icon header population' title='" + trans.sp.main.ownStackTitle + "'></span>" + stackDisplay(ownFarmTotal).desc + "</td></tr>");
  2314. }
  2315. if (totalFarm - ownFarmTotal > 0) {
  2316. // stack from other villages
  2317. supportingTroopsTable += "<tr><td><a href='" + getUrlString("screen=place&mode=units") + "'>&raquo; " + trans.sp.main.rallyPointTroops + "</a></td></tr>";
  2318. if (user_data.overview.ajaxSeperateSupportStacks) {
  2319. (function() {
  2320. var supportDisplay = stackDisplay(totalFarm - ownFarmTotal, { showFarmLimit: true });
  2321. supportingTroopsTable +=
  2322. '<tr><td style="border-top: 1px solid #85550d ;background-color: ' + supportDisplay.color + '">'
  2323. + '<span class="icon header population" title="' + trans.sp.main.supportingStackTitle
  2324. + '"></span>'
  2325. + '<b>' + supportDisplay.desc + '</b>' + '</td></tr>';
  2326. }());
  2327. }
  2328.  
  2329. unitTable.after(createMoveableWidget("os_units", trans.sp.main.unitsOther, supportingTroopsTable + "</table>"));
  2330. }
  2331.  
  2332. // total stack
  2333. (function() {
  2334. var cell = $("#order_level_farm"),
  2335. isClassicOverview = cell.length !== 0,
  2336. percentage,
  2337. stackDetails,
  2338. cellContent;
  2339.  
  2340. if (isClassicOverview) {
  2341. cell = cell.parent();
  2342. if (game_data.features.Premium.active) {
  2343. cell = cell.next();
  2344. }
  2345. percentage = world_config.farmLimit == 0 ? "" : cell.children().html();
  2346. stackDisplay(
  2347. totalFarm, {
  2348. showFarmLimit: true,
  2349. percentage: percentage ? percentage.substr(0, percentage.indexOf('%') + 1) : "",
  2350. cell: cell,
  2351. appendToCell: !game_data.features.Premium.active
  2352. });
  2353.  
  2354. } else {
  2355. stackDetails = stackDisplay(
  2356. totalFarm, {
  2357. showFarmLimit: true,
  2358. percentage: $("#l_farm .building_extra").html()
  2359. });
  2360.  
  2361. //cellContent = '<tr><td style="border-top: 1px solid #85550d ;background-color: ' + stackDetails.color + '">' + '<b>' + trans.tw.all.farm + ': ' + stackDetails.desc + '</b>' + '</td></tr>';
  2362. cellContent = ' | <b>' + trans.tw.all.farm + ': ' + stackDetails.desc + '</b>';
  2363. $("#show_units tbody:first td:last").append(cellContent).css("border-top", "1px solid #85550d").css("background-color", stackDetails.color);
  2364. }
  2365. }());
  2366. }
  2367. }
  2368. catch (e) {
  2369. handleException(e, "supportingunits");
  2370. }
  2371. }());
  2372. // Incoming/outgoing attacks
  2373. var mainTable = $("#overviewtable");
  2374. var incomingTable = $("#show_incoming_units table.vis:first");
  2375. var outgoingTable = $("#show_outgoing_units");
  2376. if (incomingTable.size() == 1 || outgoingTable.size() == 1) {
  2377. if (incomingTable.size() == 1) {
  2378. // tagger - add header
  2379. // inputBoxWidth : clicking the button focusses the newly created inputbox
  2380. // solution is to no longer show inputboxes on screen load
  2381. /*if (user_data.mainTagger2.inputBoxWidth != null) {
  2382. $("a.rename-icon", incomingTable).click();
  2383. $("span.quickedit", incomingTable).each(function() {
  2384. var renameSpan = this;
  2385. //setTimeout(function() {
  2386. $("span.quickedit-edit input:first", renameSpan).width(user_data.mainTagger2.inputBoxWidth);
  2387. //}, 1);
  2388. });
  2389. }*/
  2390.  
  2391. if (user_data.mainTagger2.active && incomingTable.has("img[src*='attack']").size() != 0) {
  2392. $("th:first", incomingTable).append("<input type=button value='" + trans.sp.tagger.openButton + "' id=openTaggerButton>");
  2393. $("#openTaggerButton").click(function () {
  2394. $(this).hide();
  2395.  
  2396. incomingTable.click(function (e) {
  2397. if (e.target.nodeName === 'IMG') {
  2398. var direction = $(e.target).attr("direction");
  2399. if (direction.length > 0) {
  2400. var rowIndex = parseInt($(e.target).attr("rowIndex"), 10);
  2401. direction = direction == "up";
  2402. $("input.incAt", incomingTable).each( function () {
  2403. var rowIndexAttributeValue = parseInt($(this).attr("rowIndex"), 10);
  2404. if ((direction && rowIndexAttributeValue <= rowIndex) || (!direction && rowIndexAttributeValue >= rowIndex)) {
  2405. $(this).prop("checked", true);
  2406. } else {
  2407. $(this).prop("checked", false);
  2408. }
  2409. });
  2410. }
  2411. }
  2412. });
  2413.  
  2414. var rows = $("tr", incomingTable);
  2415. var dodgeMenu = "<tr><td>";
  2416. dodgeMenu += '<img src="graphic/command/support.png" alt="" id="checkSupport" title="' + trans.sp.tagger.checkAllSupport + '" />';
  2417. dodgeMenu += "&nbsp;";
  2418. dodgeMenu += '<img src="graphic/command/return.png" alt="" id="uncheckSupport" title="' + trans.sp.tagger.uncheckAllSupport + '" />';
  2419. dodgeMenu += "<th colspan=3>";
  2420. dodgeMenu += trans.sp.tagger.renameTo + "<input type=textbox size=30 id=commandInput value='" + user_data.mainTagger2.defaultDescription + "'></th>";
  2421. dodgeMenu += "<th>" + trans.sp.tagger.slowest + "</th>";
  2422. dodgeMenu += "</td>";
  2423. dodgeMenu += "<td colspan=1 id=slowestUnitCell>";
  2424. if (slowest_unit != null) {
  2425. dodgeMenu += "<img title='"+trans.sp.tagger.slowestTip+"' src='graphic/unit/" + slowest_unit + ".png' slowestunit='" + slowest_unit + "'>";
  2426. }
  2427. dodgeMenu += "</td></tr>";
  2428. incomingTable.find("tbody:first").prepend(dodgeMenu);
  2429.  
  2430. // checkbox manipulation
  2431. $("#uncheckSupport").click(function () {
  2432. $("input.incSupport", incomingTable).prop("checked", false);
  2433. });
  2434.  
  2435. $("#checkSupport").click(function () {
  2436. $("input.incSupport", incomingTable).prop("checked", true);
  2437. });
  2438.  
  2439. var buttonParent = $("#commandInput").parent();
  2440. var commandIdToCoordCache = []; // No Ajax call on multiple renames with {xy}
  2441. function renameCommand(commandName) {
  2442. var dodgeCell; // capture last cell for dodgeCell coloring
  2443.  
  2444. function getCommandIdFromDodgeCell(dodgeCell) {
  2445. return Number(dodgeCell.find("span.quickedit").first().attr("data-id"));
  2446. }
  2447.  
  2448. function getVillageCoordsFromCommandId(commandId, callback) {
  2449. if (server_settings.ajaxAllowed) {
  2450. if (commandIdToCoordCache[commandId]) {
  2451. callback(commandIdToCoordCache[commandId]);
  2452.  
  2453. } else {
  2454. ajax('screen=info_command&type=other&id='+commandId, function (overview) {
  2455. var originVillageLink = $(".village_anchor:first", overview).find("a[href]"),
  2456. originVillageDesc = originVillageLink.html(),
  2457. originVillage = getVillageFromCoords(originVillageDesc);
  2458.  
  2459. commandIdToCoordCache[commandId] = originVillage.coord;
  2460.  
  2461. callback(originVillage.coord);
  2462. });
  2463. }
  2464. }
  2465. callback('');
  2466. }
  2467.  
  2468. function executeRename(dodgeCell, commandName) {
  2469. function keepTwIcon(dodgeCell, commandName) {
  2470. var oldName = $(".quickedit-label", dodgeCell).text().toUpperCase(),
  2471. newName = commandName,
  2472. i,
  2473. unitName;
  2474.  
  2475. for (i = 0; i < user_data.mainTagger2.reservedWords.length; i++) {
  2476. unitName = user_data.mainTagger2.reservedWords[i];
  2477. if (oldName.indexOf(unitName.toUpperCase()) !== -1) {
  2478. newName = unitName + ' ' + newName;
  2479. return newName; // Only one icon possible
  2480. }
  2481. }
  2482. return newName;
  2483. }
  2484.  
  2485. var button = dodgeCell.find("input[type='button']"),
  2486. newName = user_data.mainTagger2.keepReservedWords ? keepTwIcon(dodgeCell, commandName) : commandName;
  2487.  
  2488. button.prev().val(newName);
  2489. button.click();
  2490. }
  2491.  
  2492. $("input.taggerCheckbox", incomingTable).each(function () {
  2493. var openRenameButton;
  2494.  
  2495. if ($(this).is(":checked")) {
  2496. dodgeCell = $(this).parent().next();
  2497.  
  2498. openRenameButton = $("a.rename-icon", dodgeCell);
  2499. if (openRenameButton.is(":visible")) {
  2500. openRenameButton.click();
  2501. }
  2502.  
  2503. if (commandName.indexOf("{xy}") !== -1) {
  2504. getVillageCoordsFromCommandId(getCommandIdFromDodgeCell(dodgeCell), function(vilCoords) {
  2505. var nameWithCoords = commandName.replace("{xy}", vilCoords);
  2506. setTimeout(executeRename(dodgeCell, nameWithCoords),200);
  2507. });
  2508.  
  2509. } else {
  2510. setTimeout(executeRename(dodgeCell, commandName),200);
  2511. }
  2512. }
  2513. });
  2514.  
  2515. if (dodgeCell != null) {
  2516. var unitSpeed = $("#slowestUnitCell img").attr("slowestunit");
  2517. if (unitSpeed != undefined) {
  2518. dodgeCell = dodgeCell.parent().find("td").last().prev();
  2519. pers.setCookie("sanguDodge" + getQueryStringParam("village"), unitSpeed + "~" + dodgeCell.text(), user_data.mainTagger2.minutesDisplayDodgeTimeOnMap);
  2520.  
  2521. $(".dodgers", incomingTable).css("background-color", "").attr("title", "");
  2522. dodgeCell.css("background-color", user_data.colors.good).attr("title", trans.sp.tagger.activeDodgeTime);
  2523. }
  2524. }
  2525. }
  2526.  
  2527. // std tag button
  2528. var button = $("<input type=button title='" + trans.sp.tagger.renameTooltip + "' value='" + trans.sp.tagger.rename + "' onclick='select();'>");
  2529. button.click(function () {
  2530. trackClickEvent("MainTagger-CustomRename");
  2531. var tagName = $("#commandInput").val();
  2532. renameCommand(tagName);
  2533. });
  2534. buttonParent.append(button);
  2535.  
  2536. if (user_data.mainTagger2.otherDescs != null && user_data.mainTagger2.otherDescs != false) {
  2537. $.ctrl = function(key, callback, args) {
  2538. $(document).keydown(function(e) {
  2539. if(!args) args=[]; // IE barks when args is null
  2540. if(e.keyCode == key.charCodeAt(0) && e.ctrlKey) {
  2541. e.preventDefault();
  2542. e.stopPropagation();
  2543. callback.apply(this, args);
  2544. return false;
  2545. }
  2546. });
  2547. };
  2548. // custom buttons
  2549. $.each(user_data.mainTagger2.otherDescs, function (index, val) {
  2550. if (val.active) {
  2551. var button = $("<input type=button title='" + trans.sp.tagger.renameButtonShortcutTooltip.replace("{hitkey}", val.hitKey)
  2552. + "' data-rename-to='" + val.renameTo + "' value='" + val.name
  2553. + "' class=\"mainTaggerButtons\">").click(
  2554. function () {
  2555. // Cannot use input:checked : this works for Firefox but there is a bug in Opera
  2556. trackClickEvent("MainTagger-ConfigRename");
  2557. renameCommand($(this).attr("data-rename-to"));
  2558. });
  2559.  
  2560. buttonParent.append(button);
  2561. }
  2562. $.ctrl(val.hitKey, function(s) {
  2563. trackClickEvent("MainTagger-ConfigRename");
  2564. renameCommand(val.renameTo);
  2565. });
  2566. });
  2567. }
  2568.  
  2569. // add checkboxes
  2570. var lastRowIndex = rows.size(),
  2571. lastSend = 0,
  2572. prevSendTime = 0,
  2573. firstNight = true,
  2574. amountOfAttacks = 0;
  2575.  
  2576. rows.each(function (rowIndex, rowValue) {
  2577. var row = $(rowValue);
  2578. if (rowIndex == 0) {
  2579. // headerrow
  2580. var header = "<td width=1% nowrap>";
  2581. header += "<img src='graphic/command/attack.png' title='" + trans.sp.tagger.checkAllAttacks + "' id=checkAll>&nbsp;<img src='graphic/command/cancel.png' title='" + trans.sp.tagger.uncheckAllAttacks + "' id=uncheckAll>";
  2582. header += "</td>";
  2583.  
  2584. 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%'>&nbsp;</th>" + "</tr>");
  2585.  
  2586. $("#checkAll").click(function () {
  2587. $("input.incAt", incomingTable).prop("checked", true);
  2588. });
  2589.  
  2590. $("#uncheckAll").click( function () {
  2591. $("input.incAt", incomingTable).prop("checked", false);
  2592. });
  2593.  
  2594. } else {
  2595. // non header row types
  2596. if (row.find("th").size() != 0) {
  2597. // this part is only executed when attacks can be ignored
  2598. // select all checkbox row (right above link rows)
  2599. $("th:first", row).replaceWith("<th><input type=checkbox id=selectAllIgnore> " + $("th:first", row).text() + "</th>");
  2600. $("#selectAllIgnore").click(function () {
  2601. var ingoreBoxes = $("input[name^='id_']", incomingTable);
  2602. var isChecked = $("#selectAllIgnore").is(":checked");
  2603. ingoreBoxes.each(function() {
  2604. $(this).attr("checked", isChecked);
  2605. });
  2606. });
  2607.  
  2608. row.prepend("<td title='" + trans.sp.tagger.totalAttacksOnVillage + "' align=center><b># " + amountOfAttacks + "</b></td>").find("td:last").attr("colspan", 4);
  2609.  
  2610. } else if (row.find("td").size() == 1) {
  2611. // link-rows (bottom)
  2612. if ($("#switchModus").size() == 0) {
  2613. if ($("#selectAllIgnore").size() == 0) {
  2614. // attack hiding disabled in tw settings -> there is not yet a totalrow
  2615. row.prepend("<td title='" + trans.sp.tagger.totalAttacksOnVillage + "' align=center><b># " + amountOfAttacks + "</b></td>");
  2616. } else {
  2617. row.prepend("<td>&nbsp;</td>");
  2618. }
  2619.  
  2620. row.before("<tr><td>&nbsp;</td><td colspan=5><a href='' id=switchModus>" + trans.sp.tagger.switchModus + "</a></td></tr>");
  2621. $("#switchModus").click(function () {
  2622. trackClickEvent("MainTagger-OpenClose");
  2623. var editSpans = $("input.incAt", incomingTable).parent().parent().find("span.quickedit"),
  2624. isInDisplayMode = function (editSpan) {
  2625. return editSpan.find("span:first").is(":visible");
  2626. },
  2627. switchToOpen = isInDisplayMode(editSpans.first());
  2628.  
  2629. editSpans.each(function() {
  2630. var editSpan = $(this),
  2631. isDisplayMode = isInDisplayMode(editSpan);
  2632.  
  2633. if (switchToOpen && isDisplayMode) {
  2634. // make input form visible
  2635. $("a.rename-icon", editSpan).click();
  2636. //setTimeout(function() {
  2637. $("span.quickedit-edit input:first", editSpan).width(user_data.mainTagger2.inputBoxWidth);
  2638. //}, 1);
  2639.  
  2640. } else if (!switchToOpen && !isDisplayMode) {
  2641. // make label display visible
  2642. editSpan.find("span:first").show();
  2643. editSpan.find("span:last").remove();
  2644. }
  2645. });
  2646.  
  2647. return false;
  2648. });
  2649. } else {
  2650. row.prepend("<td>&nbsp;</td>");
  2651. }
  2652. row.find("td:last").attr("colspan", 5);
  2653. } else {
  2654. // normal incoming rows
  2655. var checkboxCell = "<td><input type=checkbox rowIndex=" + rowIndex + " class='taggerCheckbox ";
  2656. var incomingType = $("img[src*='graphic/command/support.png']", this).size() == 1 ? 'incSupport' : "incAt";
  2657. checkboxCell += incomingType + "'";
  2658. if (rowIndex == 1) {
  2659. checkboxCell += " id=checkFirst";
  2660. }
  2661.  
  2662. var currentArrivalTime = getDateFromTodayTomorrowTW($("td:eq(1)", this).text());
  2663. if (incomingType == 'incAt' && isDateInNightBonus(currentArrivalTime)) {
  2664. // nightbonus
  2665. row.find("td:eq(1)").css("background-color", user_data.colors.error);
  2666. }
  2667.  
  2668. // extra column with dodge time
  2669. if (incomingType == 'incAt') {
  2670. var dodgeTime = getTimeFromTW($("td:eq(2)", this).text());
  2671. row.find("td:last").before("<td class=dodgers>" + twDurationFormat(dodgeTime.totalSecs / 2 / 60) + "</td>");
  2672. amountOfAttacks++;
  2673. } else {
  2674. row.append("<td>&nbsp;</td>");
  2675. }
  2676.  
  2677. // dotted line after x hours no incomings
  2678. if (prevSendTime == 0 || (currentArrivalTime - prevSendTime) / 1000 / 60 > user_data.mainTagger2.minutesWithoutAttacksDottedLine) {
  2679. if (prevSendTime != 0) {
  2680. row.find("td").css("border-top", "1px dotted black");
  2681. }
  2682.  
  2683. prevSendTime = currentArrivalTime;
  2684. }
  2685.  
  2686. // black line after each nightbonus
  2687. if (lastSend == 0 || currentArrivalTime > lastSend) {
  2688. if (lastSend != 0) {
  2689. row.find("td").css("border-top", "1px solid black");
  2690. firstNight = false;
  2691. }
  2692.  
  2693. lastSend = new Date(currentArrivalTime);
  2694. if (lastSend.getHours() >= world_config.nightbonus.till) {
  2695. lastSend.setDate(lastSend.getDate() + 1);
  2696. lastSend.setHours(world_config.nightbonus.from);
  2697. lastSend.setMinutes(0);
  2698. lastSend.setSeconds(0);
  2699. } else if (lastSend.getHours() < world_config.nightbonus.from) {
  2700. lastSend.setHours(world_config.nightbonus.from);
  2701. lastSend.setMinutes(0);
  2702. lastSend.setSeconds(0);
  2703. } else {
  2704. lastSend.setHours(world_config.nightbonus.till);
  2705. lastSend.setMinutes(0);
  2706. lastSend.setSeconds(0);
  2707. }
  2708. }
  2709.  
  2710. // Automatically select?
  2711. if (incomingType == "incAt") {
  2712. if (firstNight) {
  2713. var isDefaultDesc = false;
  2714. if (!isDefaultDesc) {
  2715. checkboxCell += " checked=true";
  2716. }
  2717. }
  2718.  
  2719. $("span:eq(2)", row).find("input:first").click(function () {
  2720. $(this).select();
  2721. });
  2722.  
  2723. // extra buttons
  2724. $("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'>");
  2725. }
  2726.  
  2727. row.prepend(checkboxCell + "></td>");
  2728.  
  2729. if (user_data.mainTagger2.colorSupport != null && incomingType != "incAt") {
  2730. row.find("td").css("background-color", user_data.mainTagger2.colorSupport);
  2731. }
  2732. }
  2733. }
  2734. });
  2735. });
  2736. }
  2737. }
  2738.  
  2739. // show tagger?
  2740. if (user_data.mainTagger2.autoOpen) {
  2741. $("#openTaggerButton").click();
  2742. }
  2743.  
  2744. // Show attack rename inputboxes
  2745. if (user_data.mainTagger2.autoOpenCommands) {
  2746. $("#switchModus").click();
  2747. }
  2748.  
  2749. // BUG: This breaks the TW remembering of the div positions!!
  2750. var newLayout = "<tbody><tr><td colspan=2><div class='outerBorder' id=myprettynewcell>";
  2751. newLayout += "</div></td></tr></tbody>";
  2752. mainTable.append(newLayout);
  2753.  
  2754. var prettyCell = $("#myprettynewcell");
  2755. prettyCell.append($("#show_incoming_units"));
  2756. prettyCell.append($("#show_outgoing_units"));
  2757. }
  2758. if (user_data.overview.canHideDiv) {
  2759. //console.time("main_overview_deletebuttons");
  2760.  
  2761. /**
  2762. * Array with domIds of the hideable divs
  2763. * @type {Array}
  2764. */
  2765. var currentlyHidden = pers.get("mainvillage_hiddendivs");
  2766. currentlyHidden = currentlyHidden ? JSON.parse(currentlyHidden) : [];
  2767.  
  2768. // add the X images
  2769. $("#leftcolumn,#rightcolumn").find("div.moveable").each(function() {
  2770. var self = $(this),
  2771. domId = this.id;
  2772.  
  2773. if (!self.hasClass("hidden_widget")) {
  2774. if (currentlyHidden.indexOf(domId) !== -1) {
  2775. self.hide();
  2776. } else {
  2777. var header = self.find("h4:first");
  2778. header.prepend(
  2779. '<span class="sanguHide" '
  2780. + " title='" + trans.sp.main.hideDiv + "'"
  2781. + ' data-divid="' + domId + '"></span>');
  2782. }
  2783. }
  2784. });
  2785.  
  2786. // X image event
  2787. $(".sanguHide", content_value).click(function() {
  2788. var toHideId = $(this).attr("data-divid");
  2789. currentlyHidden.push(toHideId);
  2790. $("#" + toHideId).hide();
  2791. q(currentlyHidden);
  2792.  
  2793. pers.set("mainvillage_hiddendivs", JSON.stringify(currentlyHidden));
  2794. });
  2795.  
  2796. // css for X image
  2797. var deleteImage = "data:image/png;base64,"
  2798. + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAAXNSR0IArs4c6QAAAARnQU1BAACx"
  2799. + "jwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41"
  2800. + "LjExR/NCNwAAAT5JREFUOE9jmBqv1R8uD0F9oTI9wZJdAaLI7A5fwTYv3g4fgU4/4VZ3Lgag6OYV"
  2801. + "fUd3zj13aAkeBFQAVFZrx8DQGyIN5Nw6t+7p9W14EFABUFm9AwMD0GqgAUChDw/340FABUBljY5M"
  2802. + "DN0BYsRrADkJ6Bs0DZe2NL68sfHN3R1XtrfCBSEaKm0YGIAeR9awoj22M1p5z+SIHX0hczI0t/fF"
  2803. + "oGtodGJG1vD8+ubqYPXOEMnJMTI9EYqPz69E1oDFDw/PreyPUkw1YiiwYV9Z5fDq1lZkDVj8sKgh"
  2804. + "NFiTIcdHPd5RIc2Se/eUZGQNWPwARH1VMU+vbb51akV7UQhcEKEBzQ+4EERDqRUDA9BZxGsotGBg"
  2805. + "AMY28UkDpKHJmYX4xAfSAPQH0GXlNlAGEBVbMQAlkNn55gz5QNKCIdOUAQAxTOqhn6cegQAAAABJ"
  2806. + "RU5ErkJggg==";
  2807.  
  2808. var css = document.createElement("style");
  2809. css.type = "text/css";
  2810. css.innerHTML = ".sanguHide { margin-left: 2px; float: right; cursor: pointer; "
  2811. + "background: url(" + deleteImage + "); width: 16px; height: 16px; }";
  2812. document.body.appendChild(css);
  2813.  
  2814. // show everything link
  2815. content_value.append(
  2816. "<br><a href='#' id='resetSanguMenu'>"
  2817. + trans.sp.main.showHiddenDivs.replace("{amount}", currentlyHidden.length)
  2818. + "</a>"
  2819. );
  2820.  
  2821. $("#resetSanguMenu").click(function() {
  2822. pers.set("mainvillage_hiddendivs", "");
  2823. location.reload();
  2824. });
  2825.  
  2826.  
  2827.  
  2828. //console.timeEnd("main_overview_deletebuttons");
  2829. }
  2830. }());
  2831. break;
  2832.  
  2833. case "map":
  2834. (function() {
  2835. //console.time("dodge_fromMainTagger");
  2836. try {
  2837. var isDodge = pers.getCookie("sanguDodge" + getQueryStringParam("village"));
  2838. if (isDodge) {
  2839. // Display dodge time and slowest unit in the village (cookied from the mainTagger)
  2840. isDodge = isDodge.split("~");
  2841. var header = $("h2:first", content_value);
  2842. $("tbody:first", content_value)
  2843. .prepend(
  2844. "<tr><td><table width=100% cellpadding=0 cellspacing=0><tr><td width=99% style='font-size: 18pt'><b>" + header.html()
  2845. + "</b></td><td nowrap width=250><div title='" + trans.sp.map.dodgeLastTagged + "' style='border: 1px solid black; padding: 2px; background-color: "
  2846. + (isDodge[0] == 'unit_snob' ? user_data.colors.special : user_data.colors.good) + "'><img src=graphic/unit/" + isDodge[0] + ".png> <b>" + isDodge[1]
  2847. + "</b></div></td></tr></table></td></tr>");
  2848. header.remove();
  2849. }
  2850. } catch (e) { handleException(e, "dodge_fromMainTagger-"); }
  2851. //console.timeEnd("dodge_fromMainTagger");
  2852. }());
  2853. break;
  2854.  
  2855. case "report":
  2856. if (current_page.mode === 'publish') {
  2857. // Nice to haves when publishing a report
  2858. (function() {
  2859. try {
  2860. if (location.href.indexOf('published=1') == -1 && user_data.other.reportPublish != null) {
  2861. $.each(user_data.other.reportPublish, function (i, v) { $("#" + v).prop("checked", true); });
  2862. } else {
  2863. $("h3~p:nth-child(4)").each(function () {
  2864. var input = $("h3~p a")[0].href;
  2865. if (input.indexOf("?t=") != -1) {
  2866. input = input.substr(0, input.indexOf("?"));
  2867. }
  2868. $(this).append('<br><input type="text" size="75" onclick="this.select(); this.focus()" value="[url]' + input + '[/url]" />');
  2869. input = input.substr(input.lastIndexOf('/') + 1);
  2870. $(this).append('<br><input type="text" size="75" onclick="this.select(); this.focus()" value="[report_display]' + input + '[/report_display]" />');
  2871. $(this).append('<br><input type="text" size="75" onclick="this.select(); this.focus()" value="[report]' + input + '[/report]" />');
  2872. });
  2873. }
  2874. } catch (e) { handleException(e, "report"); }
  2875. }());
  2876. }
  2877. break;
  2878.  
  2879. case "main":
  2880. // Alternating row colors
  2881. $("#buildings,#build_queue").find("tr:odd").addClass("row_b");
  2882. (function() {
  2883. //console.time("main-renamevillage");
  2884. try {
  2885. if (user_data.main.villageNames != null && user_data.main.villageNames.length > 0) {
  2886. var showButtons = true;
  2887. $.each(user_data.main.villageNames, function (i, v) { if (game_data.village.name == v) showButtons = false; });
  2888.  
  2889. if (showButtons) {
  2890. var submitButton = $("input[type='submit']:last");
  2891. $.each(user_data.main.villageNames, function (i, v) {
  2892. // rename village to one of the provided villageNames options
  2893. var button = $("<input type=button class='btn' value='" + v + "'>")
  2894. .click(function () {
  2895. trackClickEvent("RenameVillage");
  2896. $("input[name='name']").val(v);
  2897. if (user_data.main.villageNameClick) {
  2898. $("input[type='submit']").click();
  2899. }
  2900. });
  2901. var input = submitButton.parent().append(button);
  2902. });
  2903. }
  2904. }
  2905. } catch (e) { handleException(e, "place-"); }
  2906. //console.timeEnd("main-renamevillage");
  2907. }());
  2908. // show loyalty when building
  2909. // destroy button is disabled now (but for how long?)
  2910. if (server_settings.ajaxAllowed && user_data.main.ajaxLoyalty) {
  2911. ajax("overview", function (overview) {
  2912. var loyalty = $("#show_mood div.vis_item", overview);
  2913. if (loyalty.size() == 1) {
  2914. $(".modemenu tr:first").append("<td><b>" + trans.tw.main.loyaltyHeader + "</b> " + loyalty.html() + "</td>");
  2915. }
  2916. });
  2917. }
  2918. break;
  2919.  
  2920. case "snob":
  2921. if (current_page.mode === "train" || current_page.mode === null || current_page.mode === "produce") {
  2922. if (user_data.other.calculateSnob && !world_config.coins) {
  2923. // Calculate for how many nobles/snobs we've got packages
  2924. (function() {
  2925. try {
  2926. //var table = $("table.vis:eq(1)", content_value);
  2927. var table = $("table.vis[width='100%']", content_value).first();
  2928. var cost = $("td:eq(1)", table).html();
  2929. cost = parseInt(cost.substr(0, cost.indexOf(" ")), 10);
  2930. var stored = $("tr:eq(1) td:eq(1)", table).html();
  2931. stored = parseInt(stored.substr(0, stored.indexOf(" ")), 10);
  2932. var canProduce = 0;
  2933. while (stored > cost) {
  2934. stored -= cost;
  2935. cost++;
  2936. canProduce++;
  2937. }
  2938.  
  2939. var sumtable = $("table.main #content_value > table table.vis:last");
  2940. assert(sumtable.length, "no snob sumtable");
  2941. sumtable.append("<tr><th>" + trans.sp.snob.canProduce
  2942. + "</th><td style='border: 1px solid black'><img src='/graphic/unit/unit_snob.png'><b>"
  2943. + canProduce + "</b> " +
  2944. "+ <img src='graphic/res.png'>"
  2945. + stored + "</td></tr>");
  2946.  
  2947. } catch (e) { handleException(e, "snob"); }
  2948. }());
  2949. }
  2950. }
  2951. break;
  2952.  
  2953. case "info_command":
  2954. if ($("#running_times").size() > 0) {
  2955. // ---------------------------------------INCOMING ATTACK
  2956. (function() {
  2957. //console.time("info_command-incoming");
  2958. try {
  2959. var link = $("#contentContainer tr:eq(10) a:last");
  2960. link.one('click', function () {
  2961. var infoTable = $("#contentContainer");
  2962. var table = $("#running_times");
  2963.  
  2964. // convert runningtime to seconds
  2965. // TODO: there is a function for this: getTimeFromTW
  2966. function convertTime(cell) {
  2967. var time = $(cell).find("td:eq(1)").text();
  2968. time = time.match(/(\d+):(\d+):(\d+)/);
  2969.  
  2970. var obj = {};
  2971. obj.hours = parseInt(time[1], 10);
  2972. obj.minutes = parseInt(time[2], 10);
  2973. obj.seconds = parseInt(time[3], 10);
  2974. obj.totalSeconds = obj.hours * 3600 + obj.minutes * 60 + obj.seconds;
  2975.  
  2976. return obj;
  2977. }
  2978.  
  2979. // Sort on runningtime
  2980. var unitRows = $("tr:gt(1)", table);
  2981. unitRows.sortElements(function (a, b) {
  2982. return convertTime(a).totalSeconds > convertTime(b).totalSeconds ? 1 : -1;
  2983. });
  2984.  
  2985. // header sent times
  2986. $("th:first", table).attr("colspan", 5);
  2987. $("th:eq(2)", table).after("<th>" + trans.sp.tagger.sentOn + "</th><th>" + trans.sp.tagger.ago + "</th>");
  2988.  
  2989. var infoCell = $("td", infoTable);
  2990. var attacker = infoCell.eq(5).text();
  2991. var attackerVillageName = infoCell.eq(7).text();
  2992. var attackerVillage = getVillageFromCoords(attackerVillageName);
  2993. var defender = infoCell.eq(10).text();
  2994. var defenderVillage = getVillageFromCoords(infoCell.eq(12).text());
  2995. var arrivalTime = getDateFromTW(infoCell.eq(14).text());
  2996. var fields = parseInt(getDistance(attackerVillage.x, defenderVillage.x, attackerVillage.y, defenderVillage.y).fields, 10);
  2997.  
  2998. var isNightbonus = isDateInNightBonus(arrivalTime);
  2999. if (isNightbonus) {
  3000. infoCell.eq(14).css("background-color", user_data.colors.error);
  3001. }
  3002.  
  3003. var remainingRunningTime = convertTime($("tr:eq(9)", infoTable)),
  3004. plausibleSpeedFound = false;
  3005.  
  3006. unitRows.each(function () {
  3007. var unit = $("img:first", this).attr("src");
  3008. unit = unit.substr(unit.lastIndexOf("unit_") + 5);
  3009. unit = unit.substr(0, unit.indexOf("."));
  3010.  
  3011. if (unit == "spear") {
  3012. $(this).hide();
  3013. } else {
  3014. var runningTime = convertTime(this),
  3015. newDate = new Date(arrivalTime.getTime() - runningTime.totalSeconds * 1000),
  3016. sendAt = prettyDate((new Date()).getTime() - newDate.getTime()),
  3017. troopsRow = this,
  3018. str;
  3019.  
  3020. // Extra column with time sent
  3021. $("td:eq(2)", troopsRow).before("<td>" + twDateFormat(newDate, true) + "</td><td>" + sendAt + "</td>");
  3022.  
  3023. // Rename default command name for each speed
  3024. if (user_data.incoming.renameInputTexbox) {
  3025. str = user_data.incoming.renameInputTexbox;
  3026.  
  3027. var attackId = $("span.quickedit", this).attr("data-id");
  3028. str = str.replace("{village}", attackerVillageName).replace("{c}", attackerVillage.continent()).replace("{id}", attackId);
  3029. str = str.replace("{player}", attacker).replace("{xy}", attackerVillage.coord).replace("{unit}", trans.tw.units.twShortNames[unit]);
  3030. str = str.replace("{fields}", fields);
  3031. if (str.indexOf("{night}") != -1) {
  3032. if (isNightbonus) {
  3033. str = str.replace("{night}", trans.sp.tagger.arrivesInNightBonus);
  3034. } else {
  3035. str = str.replace("{night}", "");
  3036. }
  3037. }
  3038.  
  3039. if (false) {
  3040. // don't show rename inputs, just the labels
  3041. $("span.quickedit-label", troopsRow).text(str).show();
  3042. } else {
  3043. // show the rename inputboxes on form load
  3044. $("span.quickedit-label", troopsRow).text(str);
  3045. setTimeout(function() {
  3046. $("a.rename-icon", troopsRow).click();
  3047. $("#focusPlaceHolder").focus();
  3048. }, 1);
  3049. }
  3050.  
  3051. if (runningTime.totalSeconds > remainingRunningTime.totalSeconds && !plausibleSpeedFound) {
  3052. plausibleSpeedFound = true;
  3053.  
  3054. $("table:first", content_value).prepend(
  3055. "<input type=submit class='btn' id=focusPlaceHolder value='"
  3056. + trans.sp.tagger.tagIt
  3057. + " (" + trans.tw.units.twShortNames[unit] + ")'"
  3058. + " data-command-name='" + str + "'"
  3059. + ">");
  3060.  
  3061. $("#focusPlaceHolder").click(function () {
  3062. trackClickEvent("TagDefault");
  3063. $("#command_comment").text($(this).attr("data-command-name"));
  3064. $("#command_comment+a").click();
  3065. setTimeout(function() {
  3066. $("#quickedit-rename input:last").click();
  3067. }, 1);
  3068. $(this).val(trans.sp.tagger.tagged).attr("disabled", "disabled");
  3069. });
  3070.  
  3071. if (unit == "snob") {
  3072. $("tr:last td", table).css("background-color", user_data.colors.error);
  3073. }
  3074. }
  3075. }
  3076.  
  3077. // Possible send times (now) in bold
  3078. if (runningTime.totalSeconds > remainingRunningTime.totalSeconds) {
  3079. $(this).css("font-weight", "bold");
  3080. }
  3081. }
  3082. });
  3083.  
  3084. // nobles can only walk so far
  3085. var nobles = $("tr:last", table);
  3086. if (convertTime(nobles).totalSeconds / 60 > world_config.maxNobleWalkingTime) {
  3087. nobles.find("td").css("text-decoration", "line-through");
  3088. }
  3089.  
  3090. if (user_data.incoming.invertSort) {
  3091. unitRows.sortElements(function (a, b) {
  3092. return convertTime(a).totalSeconds < convertTime(b).totalSeconds ? 1 : -1;
  3093. });
  3094. }
  3095. });
  3096.  
  3097. // AUTO OPEN TAGGER
  3098. if (user_data.incoming.forceOpenTagger || (user_data.incoming.autoOpenTagger && $("#labelText").text() == trans.tw.incoming.defaultCommandName)) {
  3099. link.click();
  3100. }
  3101.  
  3102. if (user_data.proStyle && user_data.incoming.villageBoxSize != null && user_data.incoming.villageBoxSize != false) {
  3103. $("table:first", content_value).css("width", user_data.incoming.villageBoxSize);
  3104. }
  3105.  
  3106. } catch (e) { handleException(e, "info_command-incoming"); }
  3107. //console.timeEnd("info_command-incoming");
  3108. }());
  3109.  
  3110. } else {
  3111. (function() {
  3112. //console.time("info_command-command");
  3113. try {
  3114. // Own attack/support/return ---------------------------------------------------------------------------------- Own attack/support/return
  3115. var infoTable = $("table.vis:first", content_value);
  3116. var type = $("h2:first", content_value).text();
  3117. var catapultTargetActive = infoTable.find("tr:eq(5) td:eq(0)").text() == trans.tw.command.catapultTarget;
  3118.  
  3119. infoTable.width(600);
  3120.  
  3121. // Add troop returntime and annulation return time
  3122. var isSupport = type.indexOf(trans.tw.command.support) == 0;
  3123. var offset = 5;
  3124. if (catapultTargetActive) {
  3125. offset += 1;
  3126. }
  3127. var arrivalCell = infoTable.find("tr:eq(" + (offset + 1) + ") td:last");
  3128.  
  3129. if (type.indexOf(trans.tw.command.returnText) == -1
  3130. && type.indexOf(trans.tw.command.abortedOperation) == -1) {
  3131.  
  3132. var duration = getTimeFromTW(infoTable.find("tr:eq(" + offset + ") td:last").text());
  3133. var imgType = !isSupport ? "attack" : "support";
  3134. arrivalCell.prepend("<img src='graphic/command/" + imgType + ".png' title='" + trans.sp.command.arrival + "'>&nbsp; " + trans.tw.all.dateOn + " ").css("font-weight", "bold");
  3135. var stillToRun = getTimeFromTW(infoTable.find("tr:eq(" + (offset + 2) + ") td:last").text());
  3136.  
  3137. var cancelCell = infoTable.find("tr:last").prev();
  3138. var canStillCancel = cancelCell.has("a").length;
  3139. if (canStillCancel) {
  3140. cancelCell.find("td:first").attr("colspan", "1").attr("nowrap", "nowrap");
  3141. var returnTime = getDateFromTW($("#serverTime").text(), true);
  3142. returnTime = new Date(returnTime.valueOf() + (duration.totalSecs - stillToRun.totalSecs) * 1000);
  3143. cancelCell.append("<td>" + trans.sp.command.returnOn + "</td><td id=returnTimer>" + twDateFormat(returnTime, true, true).substr(3) + "</td>");
  3144.  
  3145. setInterval(function timeCounter() {
  3146. var timer = $("#returnTimer");
  3147. var newTime = new Date(getDateFromTW(timer.text()).valueOf() + 2000);
  3148. timer.text(twDateFormat(newTime, true, true).substr(3));
  3149. }, 1000);
  3150.  
  3151. cancelCell = cancelCell.prev();
  3152. }
  3153.  
  3154. if (type.indexOf(trans.tw.command.attack) == 0) {
  3155. var returnTimeCell = cancelCell.find("td:last");
  3156. returnTimeCell.html("<img src='graphic/command/return.png' title='" + cancelCell.find("td:first").text() + "'>&nbsp; <b>" + returnTimeCell.text() + "</b>");
  3157. }
  3158. } else {
  3159. var imgType = type.indexOf(trans.tw.command.abortedOperation) == 0 ? imgType = "cancel" : "return";
  3160. arrivalCell.prepend("<img src='graphic/command/" + imgType + ".png' title='" + trans.sp.command.arrival + "'>&nbsp; " + trans.tw.all.dateOn + " ").css("font-weight", "bold");
  3161. }
  3162.  
  3163. var player = infoTable.find("td:eq(7) a").text();
  3164. var village = getVillageFromCoords(infoTable.find("td:eq(9) a").text());
  3165. var second = infoTable.find("td:eq(" + (13 + (catapultTargetActive ? 2 : 0)) + ")").text();
  3166. var haulDescription = "";
  3167.  
  3168. if (type.indexOf(trans.tw.command.returnText) == 0) {
  3169. infoTable = $("> table.vis:last", content_value);
  3170. if (infoTable.find("td:first").text() == trans.tw.command.haul) {
  3171. haulDescription = infoTable.find("td:last").text().match(/\s(\d+)\/(\d+)$/);
  3172. if (haulDescription) {
  3173. haulDescription = formatNumber(haulDescription[1]) + " / " + formatNumber(haulDescription[2]);
  3174. } else {
  3175. assert(infoTable.find("td:last").text() + " didn't match regexp for tw.command.haul");
  3176. }
  3177. infoTable = infoTable.prev();
  3178. }
  3179. infoTable = infoTable.find("tr:last");
  3180. } else {
  3181. infoTable = $("> table.vis:last", content_value);
  3182. }
  3183.  
  3184. var unitsSent = {};
  3185. $.each(world_data.units, function (i, val) {
  3186. unitsSent[val] = parseInt($("td:eq(" + i + ")", infoTable).text(), 10);
  3187. });
  3188. var unitsCalc = calcTroops(unitsSent);
  3189. unitsCalc.colorIfNotRightAttackType($("h2:first", content_value), !isSupport);
  3190.  
  3191. if (user_data.attackAutoRename.active) {
  3192. $.each($('.quickedit'), function(){
  3193. var renamed = buildAttackString(village.coord, unitsSent, player, isSupport, 0, haulDescription),
  3194. commandID = $(this).attr('data-id'),
  3195. $this = $(this);
  3196.  
  3197. if (server_settings.ajaxAllowed) {
  3198. $.ajax({
  3199. url: game_data.link_base_pure+'info_command&ajaxaction=edit_other_comment&id='+commandID+'&h='+game_data.csrf+'&',
  3200. method: 'post',
  3201. data: { text: renamed },
  3202. success:function() {
  3203. $this.find(".quickedit-label:first").text(renamed);
  3204. }
  3205. });
  3206. }
  3207. });
  3208. }
  3209.  
  3210. /*if (server_settings.ajaxAllowed) {
  3211. ajax("overview", function(overviewtext) {
  3212. var idnumberlist = [];
  3213. var index = 0;
  3214. var links = $(overviewtext).find("#show_outgoing_units").find("table").find("td:first-child").find("a:first-child").find("span");
  3215. //^enkel 'find codes, dus alles wegselecteren wat onnodig is.
  3216.  
  3217. links.each(function(){
  3218. var idgetal = $(this).attr('id').match(/\d+/);
  3219. idnumberlist[index]=idgetal[0];
  3220. index++;
  3221. $.trim(idnumberlist[index]);
  3222. });
  3223.  
  3224. idthisattack= location.href.match(/id=(\d+)/);// deze aanval ophalen
  3225. var idthisattacktrim = $.trim(idthisattack[1]); //eerste callback: Datgeen tussen haakjes dus. En gelijk maar trimmen, voor het geval dat.
  3226. var counter=$.inArray(idthisattacktrim, idnumberlist);
  3227. var arraylength = idnumberlist.length;
  3228. var arraylengthminusone = arraylength -1;
  3229. if (counter != arraylengthminusone) {
  3230. var nextcommandID = idnumberlist[(counter +1)];}
  3231. if (counter != 0) {
  3232. var lastcommandID = idnumberlist[(counter - 1)];
  3233. }
  3234. villageid = location.href.match(/village=(\d+)/);
  3235. //alert(villageid[1]);
  3236. if (counter != 0) {
  3237. 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>');
  3238. }
  3239. else {
  3240. content_value.find("h2").after('<table><tr><td id="lastattack" style="width:83%"><b> XX</b></td> </tr> </table>');
  3241. }
  3242. if (counter != arraylengthminusone){
  3243. $("#lastattack").after('<td id="nextcommand" ><a href="/game.php?village=' + villageid + '&id=' + nextcommandID + '&type=own&screen=info_command">'+ trans.sp.command.nextAttack+ '</a></td>');
  3244. }
  3245. else {
  3246. $("#lastattack").after('<td id="nextcommand"><b>XX</b></td>');
  3247. }
  3248.  
  3249. //alert("Hoi");
  3250. }, {});
  3251. }*/
  3252.  
  3253. // When sending os, calculate how much population in total is sent
  3254. if (isSupport) {
  3255. var totalPop = 0;
  3256. $.each(world_data.units, function (i, val) {
  3257. var amount = unitsSent[val];
  3258. if (amount != 0) {
  3259. totalPop += amount * world_data.unitsPositionSize[i];
  3260. }
  3261. });
  3262.  
  3263. var unitTable = $("table.vis:last", content_value);
  3264. unitTable.find("tr:first").append('<th width="50"><span class="icon header population" title="' + trans.sp.all.population + '"></span></th>');
  3265. unitTable.find("tr:last").append('<td>' + formatNumber(totalPop) + '</td>');
  3266. }
  3267. } catch (e) { handleException(e, "info_command-command"); }
  3268. //console.timeEnd("info_command-command");
  3269. }());
  3270. }
  3271. break;
  3272.  
  3273. case "market":
  3274. (function() {
  3275. try {
  3276. if (location.href.indexOf('try=confirm_send') > -1) {
  3277. if (user_data.proStyle && user_data.market.autoFocus) {
  3278. $("input[type='submit']").focus();
  3279. }
  3280. }
  3281. else if (location.href.indexOf('&mode=') == -1 || location.href.indexOf('&mode=send') > -1) {
  3282. if (location.href.indexOf('try=confirm_send') == -1) {
  3283. // Spice up market:
  3284. // 120 x 106 pixels: There are market images that are smaller
  3285. // Making all images equally large results in the OK button remaining on the same place
  3286. if (user_data.proStyle && user_data.market.resizeImage) {
  3287. $("img[src*='big_buildings/market']").width(120).height(106);
  3288. }
  3289.  
  3290. // New last village:
  3291. $("input[type='submit']").click(function () {
  3292. var village = getVillageFromCoords($("#inputx").val() + "|" + $("#inputy").val());
  3293. if (village.isValid) {
  3294. pers.set("lastVil", village.coord);
  3295. }
  3296. });
  3297.  
  3298. // Add last & target
  3299. var vilHome = getVillageFromCoords(game_data.village.coord);
  3300.  
  3301. var targetLocation = $("#inputx").parent().parent().parent();
  3302. var cookie = pers.get("lastVil");
  3303. var coord = getVillageFromCoords(cookie);
  3304. var htmlStr = '';
  3305. if (coord.isValid) {
  3306. var dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, 'merchant');
  3307. htmlStr = printCoord(coord, "&raquo; " + trans.sp.all.last + ": " + coord.x + "|" + coord.y);
  3308. htmlStr += "&nbsp; <span id=lastVilTime>" + dist.html + "</span>";
  3309. }
  3310.  
  3311. // Add target village
  3312. var target = getVillageFromCoords(spTargetVillageCookie());
  3313. if (target.isValid) {
  3314. var dist = getDistance(target.x, vilHome.x, target.y, vilHome.y, 'merchant');
  3315. if (htmlStr.length > 0) {
  3316. htmlStr += "<br>";
  3317. }
  3318. htmlStr += printCoord(target, "&raquo; " + trans.sp.all.target + ": " + target.x + "|" + target.y) + " &nbsp;<span id=targetVilTime>" + dist.html + "</span>";
  3319. }
  3320.  
  3321. if (htmlStr.length > 0) {
  3322. targetLocation.append("<tr><td colspan=2>" + htmlStr + "</td></tr>");
  3323. }
  3324.  
  3325. // Calculate total resources sent
  3326. var table = $("table.vis:last");
  3327. if (table.prev().text() == trans.tw.market.incomingTransports) {
  3328. var sent = { stone: 0, wood: 0, iron: 0 };
  3329. table.find("tr:gt(0)").each(function () {
  3330. var cell = $(this).find("td:eq(1)");
  3331. var resources = $.trim(cell.text().replace(/\./g, "").replace(/\s+/g, " ")).split(" ");
  3332.  
  3333. for (var i = 0; i < resources.length; i++) {
  3334. if (resources[i]) {
  3335. var restype = cell.find("span.icon:eq(" + i + ")");
  3336. for (var resIndex = 0; resIndex < world_data.resources_en.length; resIndex++) {
  3337. if (restype.hasClass(world_data.resources_en[resIndex])) {
  3338. sent[world_data.resources_en[resIndex]] += parseInt(resources[i], 10);
  3339. }
  3340. }
  3341. }
  3342. }
  3343. });
  3344.  
  3345. table.append("<tr><th>" + trans.sp.all.total + ":</th><td colspan=3><img src=graphic/holz.png> " + formatNumber(sent.wood) + "&nbsp; <img src=graphic/lehm.png> " + formatNumber(sent.stone) + "&nbsp; <img src=graphic/eisen.png> " + formatNumber(sent.iron) + "</td></tr>");
  3346. }
  3347. }
  3348. }
  3349. } catch (e) { handleException(e, "market"); }
  3350. }());
  3351. break;
  3352.  
  3353. case "settings":
  3354. // Add sangu to the menu
  3355. (function() {
  3356. var settingsMenu = $("table.vis:first", content_value);
  3357. settingsMenu.append(
  3358. "<tr><td>&nbsp;</td></tr><tr><th><a href='"
  3359. + getUrlString("screen=settings&mode=sangu")
  3360. + "'>Sangu Package</a></th></tr>");
  3361.  
  3362. settingsMenu.append(
  3363. "<tr id='sanguImportRow'><td>"
  3364. + "<a href='#' id='sanguImport'>" + trans.sp.sp.settings.importSettings + "</a>"
  3365. + "</td></tr>"
  3366. + "<tr id='sanguExportRow'><td>"
  3367. + "<a href='#' id='sanguExport'>" + trans.sp.sp.settings.exportSettings + "</a>"
  3368. + "</td></tr>");
  3369.  
  3370. settingsMenu.after(
  3371. "<br>"
  3372. + "<a target='_blank' href='http://"+server_settings.sangu+"'>"
  3373. + "<div style='width: 100%; text-align: center; border: 1px solid black; background-color: yellow; padding: 10px 0 10px;'>"
  3374. + "Sangu Website"
  3375. + "</div>"
  3376. + "</a>");
  3377.  
  3378. /**
  3379. * Creates the textarea (and other UI elements) for displaying the user_data
  3380. * @param activate {string} either Import or Export
  3381. * @param deactivate {string} either Export or Import
  3382. * @param textAreaValue {string} the content to assign to the textarea
  3383. */
  3384. function importExportHandler(activate, deactivate, textAreaValue) {
  3385. var settingsContainer = $("#sanguSettingsTextArea");
  3386. $("#sangu"+activate+"Row").addClass("row_b");
  3387. $("#sangu"+deactivate+"Row").hide();
  3388.  
  3389. $("#sanguSettingsForm").hide();
  3390. if (settingsContainer.length === 0) {
  3391. //sanguConfigTitle is the h3 defined in inject.js
  3392. $("#sanguConfigTitle").parent().append(
  3393. trans.sp.sp.settings.importSettingsDesc + "<br><br>"
  3394. + "<textarea id='sanguSettingsTextArea' style='width: 100%; height: 500px'>"
  3395. + textAreaValue
  3396. + "</textarea>");
  3397. } else {
  3398. if (textAreaValue.length > 0) {
  3399. settingsContainer.val(textAreaValue);
  3400. }
  3401. }
  3402. }
  3403.  
  3404. $("#sanguExport").click(function() {
  3405. importExportHandler("Export", "Import", JSON.stringify(user_data, null, 4));
  3406. $("#sanguSettingsTextArea").select();
  3407. return false;
  3408. });
  3409.  
  3410. $("#sanguImport").click(function() {
  3411. var importSanguSettings = $("#importSanguSettings");
  3412. importExportHandler("Import", "Export", "");
  3413.  
  3414. if (importSanguSettings.length === 0) {
  3415. $("#sanguSettingsTextArea")
  3416. .after("<br><input type='button' id='importSanguSettings' value='" + trans.sp.sp.settings.importSettings + "'>");
  3417.  
  3418. $("#importSanguSettings").click(function() {
  3419. var overwriteCurrentSettings = true,
  3420. newUserData;
  3421.  
  3422. try {
  3423. newUserData = JSON.parse($("#sanguSettingsTextArea").val());
  3424.  
  3425. if (typeof newUserData.proStyle === 'undefined') {
  3426. overwriteCurrentSettings = confirm(trans.sp.sp.settings.importError + trans.sp.sp.settings.importErrorContinueAnyway);
  3427. }
  3428.  
  3429. if (overwriteCurrentSettings) {
  3430. user_data = $.extend({}, user_data, newUserData);
  3431. pers.set("sangusettings", JSON.stringify(user_data));
  3432. alert(trans.sp.sp.settings.importSettingsSuccess);
  3433. }
  3434.  
  3435. } catch (ex) {
  3436. alert(trans.sp.sp.settings.importError + "\n" + ex.message);
  3437. }
  3438. });
  3439. }
  3440. $("#sanguSettingsTextArea").focus();
  3441.  
  3442. return false;
  3443. });
  3444. })();
  3445.  
  3446. switch (current_page.mode) {
  3447. case "vacation":
  3448. var maxSitDays = server_settings.maxSitDays;
  3449. var daysTable = $("table.vis:eq(1)", content_value);
  3450. var days = $("td:last", daysTable).text();
  3451. days = maxSitDays - parseInt(days.substr(0, days.indexOf(" ")), 10);
  3452. if (days > 0) {
  3453. var tillTime = new Date();
  3454. tillTime.setDate(tillTime.getDate() + days);
  3455. daysTable.append("<tr><td>" + trans.sp.rest.sittingAttackTill + "</td><td>" + (tillTime.getDate() + "." + pad(tillTime.getMonth() + 1, 2) + "." + tillTime.getFullYear()) + "</td></tr>");
  3456. } else {
  3457. daysTable.find("td:last").css("background-color", user_data.colors.error);
  3458. }
  3459. break;
  3460.  
  3461. case "quickbar_edit":
  3462. if (user_data.scriptbar.editBoxCols != null && user_data.scriptbar.editBoxCols != false) {
  3463. // TODO: textareaIfy: This might be useful on other places aswell. Move to func/UI?
  3464. function textareaIfy(element) {
  3465. var textarea =
  3466. $('<textarea>')
  3467. .attr('cols', Math.round(user_data.scriptbar.editBoxCols / 9))
  3468. .attr('rows', user_data.scriptbar.editBoxRows)
  3469. .val($(element).val());
  3470.  
  3471. textarea.change(function () {
  3472. element.val($(this).val());
  3473. });
  3474.  
  3475. element.before(textarea);
  3476. $(element).hide();
  3477. }
  3478.  
  3479. var url = $("form :input[type='text']").css("width", user_data.scriptbar.editBoxCols).last();
  3480. textareaIfy(url);
  3481. }
  3482. break;
  3483. }
  3484.  
  3485. // SANGU SETTING EDITOR
  3486. if (location.href.indexOf('mode=sangu') > -1) {
  3487.  
  3488.  
  3489. // settings.editor: : delimited: "array:string" or "required:boolean" etc
  3490.  
  3491. function createArraySettingType(inputHandler, index, editor) {
  3492. var propertyValueType = editor.split("|")[0];
  3493.  
  3494. function deleter() {
  3495. inputHandler.getValue().splice(index, 1);
  3496. }
  3497.  
  3498. switch (propertyValueType) {
  3499. case "number":
  3500. return new FormInputHandler(inputHandler.formConfig, {
  3501. getter: function() {
  3502. return inputHandler.getValue()[index];
  3503. },
  3504. setter: function(value) {
  3505. value = parseInt(value, 10);
  3506. if (!isNaN(value)) {
  3507. inputHandler.getValue()[index] = value;
  3508. } else {
  3509. inputHandler.getValue()[index] = 0;
  3510. }
  3511. },
  3512. deleter: deleter,
  3513. editor: editor
  3514. });
  3515.  
  3516. case "text":
  3517. case "color":
  3518. return new FormInputHandler(inputHandler.formConfig, {
  3519. getter: function() {
  3520. return inputHandler.getValue()[index];
  3521. },
  3522. setter: function(value) {
  3523. inputHandler.getValue()[index] = value;
  3524. },
  3525. deleter: deleter,
  3526. editor: editor
  3527. });
  3528.  
  3529. case "float":
  3530. return new FormInputHandler(inputHandler.formConfig, {
  3531. getter: function() {
  3532. return inputHandler.getValue()[index];
  3533. },
  3534. setter: function(value) {
  3535. value = parseFloat(value.replace(",", "."));
  3536. if (!isNaN(value)) {
  3537. inputHandler.getValue()[index] = value;
  3538. } else {
  3539. inputHandler.getValue()[index] = 0;
  3540. }
  3541. },
  3542. deleter: deleter,
  3543. editor: editor
  3544. });
  3545. }
  3546.  
  3547. alert(propertyValueType + " not supported");
  3548. }
  3549.  
  3550. /**
  3551. * Factory for creating different representations of a property
  3552. * @type {string}
  3553. */
  3554. function createSettingType(inputHandler, editors, editorIndex, arrayOptions) {
  3555. var value = inputHandler.getValue(),
  3556. decorators,
  3557. inputType,
  3558. propName;
  3559.  
  3560. //array|addNew:number|delete|step=1000
  3561. //color=color+number=stack
  3562.  
  3563. //q("with -> " + editors + ". isArray: " + isArrayType);
  3564. //q(arrayOptions);
  3565.  
  3566. if (!arrayOptions.isArrayType) {
  3567. decorators = editors.split("|");
  3568. inputType = decorators[0];
  3569. if (inputType.indexOf("=") > -1) {
  3570. propName = inputType.split("=")[1];
  3571. inputType = inputType.split("=")[0];
  3572. }
  3573.  
  3574. //q("isArray: " + propName + "=> " + inputType);
  3575. //q(decorators);
  3576.  
  3577. switch (inputType) {
  3578. case "bool":
  3579. return {
  3580. build: function(id) {
  3581. //assert(typeof value === 'boolean', (typeof value) + ": not a boolean");
  3582. return "<input type='checkbox' id='"+id+"' "+(value ? " checked" : "")+" />";
  3583. },
  3584. bind: function(id) {
  3585. $("#" + id).click(function() {
  3586. inputHandler.setValue($(this).is(":checked"));
  3587. });
  3588. }
  3589. };
  3590. case "unit":
  3591. return {
  3592. build: function(id) {
  3593. var i,
  3594. html = "<select id='"+id+"'>";
  3595.  
  3596. for (i = 0; i < world_data.units.length; i++) {
  3597. html += "<option "+(value == world_data.units[i] ? " selected" : "")+">"+world_data.units[i]+"</option>";
  3598. }
  3599. html += "</select>";
  3600.  
  3601. return html;
  3602. },
  3603. bind: function(id) {
  3604. $("#" + id).click(function() {
  3605. inputHandler.setValue($(this).val());
  3606. });
  3607. }
  3608. };
  3609. case "text":
  3610. case "color":
  3611. case "number":
  3612. case "float":
  3613. return (function() {
  3614. var htmlString = "",
  3615. index,
  3616. inputBoxSize = 13,
  3617. extraInputAttributes = "",
  3618. extraHtml = "",
  3619. inputTypeAttribute = inputType === "float" ? "number" : inputType;
  3620.  
  3621. switch (inputType) {
  3622. case "text":
  3623. if (typeof value === 'string') {
  3624. value = value.toString().replace(/'/g, "&#39;");
  3625. }
  3626. inputBoxSize = 50;
  3627. break;
  3628. }
  3629. if (decorators.length > 1) {
  3630. (function() {
  3631. var keyValuePair;
  3632. for (index = 0; index < decorators.length; index++) {
  3633. keyValuePair = decorators[index].split("=");
  3634. switch (keyValuePair[0]) {
  3635. case "delete":
  3636. extraHtml += " &nbsp;<a href='#' id='{domId}_delete'><img src='graphic/delete.png' title='"+trans.sp.sp.settings.deleteTooltip+"' /></a>";
  3637. break;
  3638. case "step":
  3639. assert(inputType === "float" || inputType === "number", "step only works with numeric inputs");
  3640. assert(keyValuePair.length === 2, "expected input: step=value");
  3641. extraInputAttributes += " step='"+keyValuePair[1]+"'";
  3642. break;
  3643. case "width":
  3644. inputBoxSize = keyValuePair[1];
  3645. break;
  3646. }
  3647. }
  3648. })();
  3649. }
  3650.  
  3651. htmlString +=
  3652. "<input type='" + inputTypeAttribute + "' id='{domId}' size='" + inputBoxSize +"' "
  3653. + (typeof value !== 'undefined' ? " value='"+value+"'" : "")
  3654. + extraInputAttributes +" />"
  3655. + extraHtml;
  3656.  
  3657. return {
  3658. build: function(id) {
  3659. return htmlString.replace(/\{domId\}/g, id);
  3660. },
  3661. bind: function(id) {
  3662. $("#" + id).change(function() {
  3663. var newValue = $("#" + id).val();
  3664. inputHandler.setValue(newValue, editorIndex);
  3665. return false;
  3666. });
  3667.  
  3668. $("#" + id + "_delete").click(function() {
  3669. inputHandler.deleteValue();
  3670. location.reload(false);
  3671. });
  3672. }
  3673. };
  3674. })();
  3675. }
  3676.  
  3677. } else {
  3678. return (function() {
  3679. var typesArray = [],
  3680. arrayIndex,
  3681. canAddNew = false,
  3682. inlineDiv = false;
  3683.  
  3684. decorators = arrayOptions.decorators;
  3685.  
  3686. //q(editors);
  3687. //q(decorators);
  3688. //q("----");
  3689.  
  3690. if (decorators.length > 0) {
  3691. for (arrayIndex = 0; arrayIndex < decorators.length; arrayIndex++) {
  3692. switch (decorators[arrayIndex]) {
  3693. case "addNew":
  3694. canAddNew = true;
  3695. break;
  3696. case "inline":
  3697. inlineDiv = true;
  3698. break;
  3699. }
  3700. }
  3701. }
  3702.  
  3703. for (arrayIndex = 0; arrayIndex < value.length; arrayIndex++) {
  3704. (function() {
  3705. var fixedArrayIndex = arrayIndex;
  3706. //q("createArraySettingType for" + fixedArrayIndex + "=" +editors);
  3707. typesArray.push(createArraySettingType(inputHandler, fixedArrayIndex, editors));
  3708. })();
  3709. }
  3710.  
  3711. return {
  3712. build: function(id) {
  3713. var htmlString = "",
  3714. arrayIndex,
  3715. domId;
  3716.  
  3717. assert(typeof value === 'object', (typeof value) + ": not an object (array)");
  3718.  
  3719. for (arrayIndex = 0; arrayIndex < typesArray.length; arrayIndex++) {
  3720. domId = id + "_" + arrayIndex;
  3721.  
  3722. htmlString += "<div" + (inlineDiv ? " style='display: inline'> &nbsp;" : ">");
  3723. htmlString += typesArray[arrayIndex].build(domId);
  3724. htmlString += "</div>";
  3725. }
  3726.  
  3727. if (canAddNew) {
  3728. htmlString += "<a href='#' id='"+id+"_new'>" + trans.sp.sp.settings.addRecord + "</a>";
  3729. }
  3730.  
  3731. return htmlString;
  3732. },
  3733. bind: function(id) {
  3734. var domId,
  3735. arrayIndex;
  3736.  
  3737. if (canAddNew) {
  3738. $("#" + id + "_new").click(function() {
  3739. var domId = id + "_" + typesArray.length,
  3740. newType;
  3741.  
  3742. newType = createArraySettingType(inputHandler, typesArray.length, editors);
  3743. $(this).before("<div>" + newType.build(domId) + "</div>");
  3744. newType.bind(domId);
  3745. typesArray.push(newType);
  3746.  
  3747. $("#"+domId).focus();
  3748. return false;
  3749. });
  3750. }
  3751.  
  3752. if (typesArray.length === 0 && canAddNew) {
  3753. $("#" + id + "_new").click();
  3754. } else {
  3755. for (arrayIndex = 0; arrayIndex < typesArray.length; arrayIndex++) {
  3756. domId = id + "_" + arrayIndex;
  3757. typesArray[arrayIndex].bind(domId);
  3758. }
  3759. }
  3760. }
  3761. };
  3762. })();
  3763. }
  3764.  
  3765. assert(false, editors + " is not a valid editor");
  3766. return;
  3767. }
  3768.  
  3769. /**
  3770. * @constructor
  3771. */
  3772. function FormInputHandler(propertyFormConfig, propSettings, editorIndex) {
  3773. var arraySplit = propSettings.editor.split(":"),
  3774. editors,
  3775. arrayOptions = {isArrayType: arraySplit[0].indexOf('array') === 0},
  3776. strategy;
  3777.  
  3778. assert(typeof propSettings.getter === 'function', 'getter should be a function');
  3779. assert(typeof propSettings.setter === 'function', 'setter should be a function');
  3780.  
  3781. if (arrayOptions.isArrayType) {
  3782. editors = arraySplit[1].split("+");
  3783. } else {
  3784. editors = arraySplit[0].split("+");
  3785. }
  3786.  
  3787. //q(editors);
  3788.  
  3789. this.formConfig = propertyFormConfig;
  3790. if (typeof propertyFormConfig.save === 'undefined') {
  3791. this.setValue = propSettings.setter;
  3792. this.deleteValue = propSettings.deleter;
  3793. } else {
  3794. this.setValue = function(value, editorIndex) {
  3795. propSettings.setter(value, editorIndex);
  3796. propertyFormConfig.save();
  3797. };
  3798.  
  3799. this.deleteValue = function() {
  3800. propSettings.deleter();
  3801. propertyFormConfig.save();
  3802. };
  3803. }
  3804.  
  3805. this.getValue = propSettings.getter;
  3806. if (true) {
  3807. //q("createSettingType for " + editors[0] + " index " + editorIndex);
  3808. if (arrayOptions.isArrayType) {
  3809. arrayOptions.decorators = arraySplit[0].split("|");
  3810. arrayOptions.decorators.splice(0, 1);
  3811. }
  3812.  
  3813. strategy = createSettingType(this, editors[0], editorIndex, arrayOptions);
  3814. this.build = strategy.build;
  3815. this.bind = strategy.bind;
  3816. } else {
  3817. (function(inputHandler) {
  3818. var handlers = [],
  3819. index;
  3820.  
  3821. for (index = 0; index < editors.length; index++) {
  3822. handlers.push(new FormInputHandler(propertyFormConfig, propSettings, index));
  3823. }
  3824.  
  3825. inputHandler.build = function(id) {
  3826. var i, htmlString = "";
  3827. for (i = 0; i < handlers.length; i++) {
  3828. htmlString += handlers[i].build(id + '_col' + i);
  3829. htmlString += " &nbsp;";
  3830. }
  3831. return htmlString;
  3832. };
  3833.  
  3834. inputHandler.bind = function(id) {
  3835. var i;
  3836. for (i = 0; i < handlers.length; i++) {
  3837. handlers[i].bind(id + '_col' + i);
  3838. }
  3839. };
  3840. })(this);
  3841. }
  3842. }
  3843.  
  3844. function buildConfigForm(contentPage, propertyFormConfig) {
  3845. var config = propertyFormConfig.properties,
  3846. prop,
  3847. properties = [],
  3848. propIndex,
  3849. form = "",
  3850. formRow,
  3851. container;
  3852.  
  3853. // show only relevant properties
  3854. // has side-effects
  3855. for (prop in config) {
  3856. if (config.hasOwnProperty(prop)) {
  3857. if (typeof config[prop].show === "undefined" || config[prop].show) {
  3858. config[prop].ownName = prop;
  3859. if (typeof config[prop].type === 'undefined') {
  3860. // this is a variable <-> input form mapping
  3861. config[prop].type = "propertyEditor";
  3862. config[prop].propUI = new FormInputHandler(propertyFormConfig, config[prop].propUI);
  3863.  
  3864. } else {
  3865. // these are other visual indications
  3866. // ui is handled with if / else below
  3867. }
  3868.  
  3869. properties.push(config[prop]);
  3870. }
  3871. }
  3872. }
  3873.  
  3874. // build form
  3875. form = "<table class='vis' width='100%'>";
  3876. form += "<tr><th colspan='2'>" + propertyFormConfig.title + "</th>";
  3877. form += "</table>";
  3878. form = $(form);
  3879.  
  3880. container = $("<div class='propertyEditFormContainer' id='"+propertyFormConfig.id+"' style='display: none' />");
  3881. container.append(form).append("<br>");
  3882.  
  3883. contentPage.append(container);
  3884.  
  3885. for (propIndex = 0; propIndex < properties.length; propIndex++) {
  3886. var propUI = properties[propIndex];
  3887. if (propUI.type === 'propertyEditor') {
  3888. formRow = "<tr>";
  3889.  
  3890. // label
  3891. formRow += "<td width='25%'>";
  3892. if (typeof propUI.tooltip !== "undefined") {
  3893. formRow += "<img src='graphic/questionmark.png' title='"+propUI.tooltip+"' /> &nbsp; ";
  3894. }
  3895. formRow += propUI.label;
  3896. formRow += "</td>";
  3897.  
  3898. //editor
  3899. if(propUI.label == sangu_trans.mainTagger.otherButtons.hitKey) {
  3900. formRow += "<td width='75%'>ctrl + ";
  3901. } else {
  3902. formRow += "<td width='75%'>";
  3903. }
  3904. formRow += propUI.propUI.build(propertyFormConfig.id+"_"+propUI.ownName);
  3905. formRow += "</td>";
  3906.  
  3907. formRow += "</tr>";
  3908.  
  3909. form.append(formRow);
  3910.  
  3911. // bind the form to the js variable
  3912. if (typeof propUI.propUI.bind === 'function') {
  3913. propUI.propUI.bind(propertyFormConfig.id+"_"+propUI.ownName);
  3914. }
  3915. } else {
  3916. switch (propUI.type) {
  3917. case "subtitle":
  3918. form.append("<tr class='row_b'><td colspan='2'><b>"+propUI.label+"</b></td></tr>");
  3919. break;
  3920. }
  3921. }
  3922. }
  3923. }
  3924. /**
  3925. * Contains all translations for the property setting editors
  3926. */
  3927. var sangu_trans = (function() {
  3928. var sangu_trans = {};
  3929. sangu_trans.nl = {
  3930. main: {
  3931. title: "Hoofdgebouw",
  3932. villageNames: "Standaard dorpsnamen:",
  3933. villageNamesTooltip: "Voeg je veelgebruikte dorpsnamen toe om een dorp met 1 klik te hernoemen.",
  3934. villageNameClick: "Autoclick?",
  3935. villageNameClickTooltip: "Schakel deze feature uit indien je bijvoorbeeld nog een nummer aan een standaard dorpsnaam wil toevoegen.",
  3936. ajaxLoyalty: "Toestemming tonen?"
  3937. },
  3938. global: {
  3939. title: "Op alle pagina's",
  3940. tw_version: "Compatibiliteit met TW versie {version} afdwingen",
  3941. 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!",
  3942. resources: {
  3943. title: "Met kleuren aanduiden hoe vol de opslagplaats is",
  3944. activate: trans.sp.sp.settings.activate,
  3945. blinkWhenStorageFull: "Grondstoffen knipperen wanneer de opslagplaats vol is",
  3946. colors: "Kleurenschakering"
  3947. },
  3948. incomingsTitle: "Binnenkomende aanvallen/ondersteuning links",
  3949. incomingsEditLinks: "Linkdoelwit wijzigen",
  3950. incomingsEditLinksTooltip: "De binnenkomende aanval/ondersteuning link wijzigen zodat de eerste 1000 bevelen getoond worden.",
  3951. incomingsTrack: "Tijdchecker activeren",
  3952. incomingsIndicator: "Tijdchecker tekst",
  3953. incomingsIndicatorTooltip: "Gebruik {current} voor het huidig aantal binnenkomende aanvallen. "
  3954. + "{difference} voor het aantal nieuwe aanvallen. "
  3955. + "{saved} voor het laatst opgeslaan aantal aanvallen.",
  3956. incomingsIndicatorTooltip2: "Tijdchecker tooltip",
  3957. incomingsLastTimeCheckWarning: "Tijdchecker tooltip",
  3958. incomingsLastTimeCheckWarningTooltip: "Gebruik {elapsed} voor de verstreken tijd. Gebruik {time} voor de laatste tijdcheck.",
  3959. otherSettingsTitle: "Overige configuratie",
  3960. visualizeFriends: "Aangeven welke vrienden momenteel online zijn",
  3961. duplicateLogoffLink: "Voeg links onderaan een extra 'Afmelden' link toe.",
  3962. colorsTitle: "Sangu achtergrondkleuren",
  3963. colorsError: "Waarschuwingen",
  3964. colorsNeutral: "Neutrale indicaties",
  3965. colorsGood: "Positieve indicaties",
  3966. colorsSpecial: "Speciale indicaties",
  3967. jumperTitle: "Kaartspringer",
  3968. jumperAutoOpen: "Het inputveld om coördinaten in te geven direct openen"
  3969. },
  3970. incoming: {
  3971. title: "De standaard TW binnenkomende aanvallen tagger",
  3972. autoOpenTagger: "De tagger direct openen indien het bevel nog niet hernoemd is",
  3973. forceOpenTagger: "De tagger altijd openen",
  3974. renameInputTexbox: "De standaard hernoemde bevelnaam",
  3975. 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.",
  3976. invertSort: "De snelheid mogelijkheden sorteren",
  3977. invertSortTooltip: "Vink dit aan om de traagste eenheid bovenaan te plaatsen"
  3978. },
  3979. overviews: {
  3980. addFancyImagesToOverviewLinks: "Icons toevoegen aan de overzichtslinks",
  3981. command: {
  3982. title: "Overzichtsscherm: Troepenoverzicht",
  3983. titleOwnTroopsPage: "Pagina's 'Eigen' en 'In het dorp'",
  3984. middleMouseClickDeletesRow: "Actie bij <img src='graphic/command/attack.png'>"
  3985. + " aanklikken met de middelste muisknop: Aangevinkt=rij verwijderen. Uitgevinkt: rode rand rond de \"Opdracht\" cell.",
  3986. middleMouseClickDeletesRowTooltip: "Dit werkt enkel in Opera. Vink dit NIET AAN in Firefox of Chrome!! (De rode rand werkt ook niet in Firefox)",
  3987. titleDefensePage: "Pagina's 'Verdediging' en 'Ondersteuning'",
  3988. changeTroopsOverviewLink: "Link wijzigen om direct 'Eigen troepen' te openen",
  3989. filterMinPopulation: "De standaard ingevulde waarde om te filteren op populatie",
  3990. filterOnUnitTypeSeperator: "Eigen/In het dorp: Filteren op aantal eenheden",
  3991. filterMinDefaultType: "De eenheid om te filteren die standaard geselecteerd is",
  3992. filterMinDefault: "Het aantal eenheden om te filteren dat standaard ingevuld is",
  3993. filterMinDefaultTooltip: "Dit aantal wordt ingevuld wanneer de pagina opent. Bij het selecteren van een andere eenheid worden de waarden hieronder gebruikt.",
  3994. filterMinOther: "De standaard waarde voor de overige eenheden",
  3995. filterAutoSort: "De dorpenlijst automatisch sorteren na het ingeven van een doeldorp"
  3996. },
  3997. troopsRestack: {
  3998. title: "Alle pagina's: Stack BBCodes generatie",
  3999. to: "Stack een dorp tot hoeveel populatie",
  4000. requiredDifference: "Vereist verschil in huidige populatie in het dorp en de waarde hierboven",
  4001. fieldsDistanceFilterDefault: "Het standaard ingevuld aantal velden waarop gefilterd wordt",
  4002. filterReverse: "Aangevinkt: Rijen die voldoen aan de zoekopdracht tonen. Anders de rijen verbergen.",
  4003. filterReverseTooltip: "Dit kan op de pagina zelf nog aangepast worden",
  4004. defaultPopulationFilterAmount: "Het standaard ingevuld aantal voor de populatie filter",
  4005. removeRowsWithoutSupport: "Bij het berekenen van de totalen dorpen zonder ondersteuning direct verbergen",
  4006. autohideWithoutSupportAfterFilter: "Automatisch dorpen zonder overige ondersteuning wegfilteren na het toepassen van een filter",
  4007. autohideWithoutSupportAfterFilterTooltip: "Bij de aanvalsfilter worden de dorpen die niet onder aanval zijn sowieso verborgen.",
  4008. calculateDefTotalsAfterFilter: "Automatisch de totale ondersteuning per dorp berekenen na het toepassen van een filter",
  4009. calculateDefTotalsAfterFilterTooltip: "Voor sommige filters moeten de totalen sowieso toch eerst berekend worden."
  4010. },
  4011. commands: {
  4012. title: "Overzichtsscherm: Bevelen",
  4013. sumRow: "Een scheidingsrij tussen verschillende dorpen toevoegen",
  4014. filterFakeMaxPop: "Een bevel met minder dan deze populatie is een fake aanval (en wordt verborgen)",
  4015. requiredTroopAmount: "Bij de export naar BBCodes worden bevelen met minder dan deze populatie overgeslagen."
  4016. },
  4017. resources: {
  4018. title: "Overzichtsscherm: Productie",
  4019. requiredResDefault: "Het aantal grondstoffen dat standaard in het invoerveld ingevuld is",
  4020. requiredMerchants: "Het aantal handelaren dat standaard ingevuld is",
  4021. filterMerchants: "Ook filteren op aantal beschikbare handelaren",
  4022. filterRows: "Aanvinken om rijen te verbergen. Wanneer uitgevinkt wordt achtergrondkleur van de grondstoffen gewijzigd",
  4023. 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",
  4024. highlightColor: "De achtergrondkleur die gebruikt wordt om de grondstoffen aan te duiden die voldoen aan de filtercriteria"
  4025. },
  4026. buildings: {
  4027. title: "Overzichtsscherm: Gebouwen",
  4028. minMaxTitle: "Geef de laagst en hoogst aanvaardbare levels voor je gebouwen",
  4029. minLevel: "Min {building}",
  4030. maxLevel: "Max {building}"
  4031. },
  4032. incomings: {
  4033. title: "Overzichtsscherm: Aankomend",
  4034. attackIdTitle: "Groeperen op aanvalsid",
  4035. minValueTooltip: "De te tonen tekst wanneer het verschil in aanvalsid tussen de vorige binnenkomende aanval meer is dan het aangegeven verschil",
  4036. seperatorTitle: "Bij verschil &lt; {minValue}",
  4037. minValue: "Minimum verschil",
  4038. text: "Tekst",
  4039. attackIdHigherDescription: "Te tonen tekst bij groter verschil in aanvalsid"
  4040. }
  4041. },
  4042. place: {
  4043. title: "Plaats: Speciale troepen invul links",
  4044. titleCustom: "Plaats: Extra troepen invul links",
  4045. linkText: "Link tekst",
  4046. link: "Link: {name}",
  4047.  
  4048. scoutTitle: "Verkenner links",
  4049. scoutVillage: "Een dorp krijgt verkenner links als er meer verkenners zijn dan dit",
  4050. scoutPlaceLinks: "Links om zoveel verkenners in te vullen",
  4051.  
  4052. fakePlaceLinkTitle: "Fake troepen link",
  4053. fakePlaceExcludeTroops: "Type troepen te negeren bij selecteren",
  4054. fakePlaceExcludeTroopsTooltip: "Gebruik de namen: spear, sword, axe, archer, sword, spy, light, marcher, heavy, ram, catapult",
  4055.  
  4056. noblePlaceLinkTitle: "Edel links",
  4057. noblePlaceLinkFirstTitle: "Edel link met het meeste troepen",
  4058. noblePlaceLinkFirstNameTooltip: "Er blijven genoeg troepen thuis om voor de resterende edels nog ondersteuning te kunnen sturen. Maak leeg om deze link niet te tonen.",
  4059.  
  4060. noblePlaceLinkSupportTitle: "Edel link met minimale ondersteuning",
  4061. noblePlaceLinksForceShow: "Ook tonen wanneer er slechts 1 edel in het dorp is",
  4062. nobleSupportOffTitle: "Edel ondersteuning voor offensief dorp",
  4063. nobleSupportDefTitle: "Edel ondersteuning voor defensief dorp",
  4064. nobleSupportUnit: "Eenheid",
  4065. nobleSupportAmount: "Aantal eenheden",
  4066.  
  4067. noblePlaceLinkDivideTitle: "Edel link met gelijk verdeelde ondersteuning",
  4068. noblePlaceLinkDivideAddRam: "Rammen mee selecteren",
  4069.  
  4070. customPlaceLinksTitle: "Andere links",
  4071. customPlaceOneTimeTooltip: "Vul een getal in om zoveel te sturen. Vul een negatief getal om zoveel te laten staan.",
  4072. customPlaceSendAlong: "Meesturen tot",
  4073. customPlaceSendAlongTooltip: "Indien er na selectie van bovenstaande troepen minder dan zoveel troepen in het dorp zou overblijven, selecteer dan alle troepen"
  4074. },
  4075. profile: {
  4076. title: "Verfraaien van het profiel van spelers en stammen",
  4077. moveClaim: "Verplaats dorpsclaim zodat alle andere links op dezelfde plaats blijven staan",
  4078. mapLink: {
  4079. title: "Kaarteigenschappen van link naar TWMaps kaart generator",
  4080. fill: "Achtergrondkleur",
  4081. zoom: 'Inzoom niveau',
  4082. grid: 'Continentlijnen',
  4083. gridContinentNumbers: "Continent nummers",
  4084. playerColor: 'Spelerskleur',
  4085. tribeColor: 'Zijn stam kleur',
  4086. centreX: "Centreren op X coördinaat",
  4087. centreY: "Centreren op Y coördinaat",
  4088. ownColor: 'Eigen kleur',
  4089. markedOnly: "Alleen gemarkeerde",
  4090. yourTribeColor: "Eigen stam kleur",
  4091. bigMarkers: "Grotere aanduidingen"
  4092. },
  4093. popup: {
  4094. title: "Overnames popup",
  4095. width: "Breedte van de popup",
  4096. height: "Hoogte van de popup",
  4097. left: "Horizontale positie",
  4098. top: "Verticale positie"
  4099. }
  4100. },
  4101. mainTagger: {
  4102. title: "Tagger op dorpsoverzicht",
  4103. autoOpen: "De tagger automatisch openen bij binnenkomende aanvallen",
  4104. inputBoxWidth: "De breedte van de bevel hernoemings inputvelden",
  4105. defaultDescription: "De naam die standaard in het hernoemings inputveld geplaatst wordt",
  4106. defaultDescriptionTooltip: "Gebruik {xy} voor de coordinaten van het herkomst dorp",
  4107. autoOpenCommands: "De bevel hernoemings inputvelden direct tonen",
  4108. minutesDisplayDodgeTimeOnMap: "Aantal minuten dat de laatste dodgetijd op de kaart getoond wordt",
  4109. minutesDisplayDodgeTimeOnMapTooltip: "De laatste dodgetijd is de tijd van het laatste bevel, aangeduidt met gewijzigde achtergrondkleur na het herbenoemen van binnenkomende aanvallen.",
  4110. minutesWithoutAttacksDottedLine: "Elke zoveel minuten zonder een tussenliggende binnenkomende aanval aanduiden met een stippelijn (180 = 3 uur)",
  4111. colorSupport: "Binnenkomende ondersteuning een andere achtergrondkleur geven",
  4112. keepReservedWords: "Tekst die vervangen wordt door een eenheid icon behouden bij hernoemen binnenkomende aanval",
  4113. keepReservedWordsTooltip: "Bijvoorbeeld \"Verk.\" wordt vervangen door een verkenners icon",
  4114. otherButtons: {
  4115. title: "Andere hernoemings knoppen",
  4116. renameTo: "Hernoemen naar",
  4117. button: "Tekst knop",
  4118. hitKey: "Sneltoets"
  4119. }
  4120. },
  4121. confirm: {
  4122. title: "Bevel comfirmatie pagina",
  4123. addExtraOkButton: "Links bovenaan de pagina een extra OK knop toevoegen",
  4124. replaceNightBonus: "Nachtbonus melding verwerken in de pagina titel",
  4125. replaceTribeClaim: "Dorpsclaim melding verwerken in de pagina titel",
  4126. addCatapultImages: "Gebouws iconen tonen om snel het katapult doelwit te wijzigen"
  4127. },
  4128. villageInfo: {
  4129. title: "Extra links naar het troepenoverzicht",
  4130. title2: "Twee extra links naar het troepenoverzicht op elke dorpsinformatie pagina toevoegen",
  4131. icon: "Kies een icoon",
  4132. off_title: "Extra link voor aanvallen",
  4133. def_title: "Extra link voor verdedigen",
  4134. linkName: "De link die toegevoegd wordt",
  4135. group: "Binnen welk groep id openen (kies 0 voor alle groepen)",
  4136. 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.",
  4137. activateFilter: "Filter activeren",
  4138. filter: {
  4139. title: "Direct filteren",
  4140. unit: "Eenheid",
  4141. amount: "Minimale hoeveelheid"
  4142. },
  4143. sort: "Dorpenlijst direct sorteren",
  4144. changeSpeed: "Traagste eenheid snelheid wijzigen"
  4145. },
  4146. other: {
  4147. title: "Overige configuratie",
  4148. proStyle: "Pro Style?",
  4149. proStyleTooltip: "Met deze setting worden een heleboel kleinere features aan of uitgeschakeld",
  4150. timeDisplayTitle: "Hoe looptijden weergeven",
  4151. displayDays: "Dagen tonen wanneer de troepen langer dan 24 uur lopen?",
  4152. displayDaysTooltip: "Voorbeeld: toon \"1.18:01:36\" wanneer aangevinkt, zoniet wordt die looptijd als \"42:01:36\" weergegeven",
  4153. walkingTimeDisplay: "Te tonen tekst",
  4154. walkingTimeDisplayTooltip: "Gebruik {duration} voor het aantal uren en {arrival} voor de aankomstdatum",
  4155. calculateSnob: "Berekenen hoeveel edels direct kunnen geproduceerd worden",
  4156. showPlayerProfileOnVillage: "Het uitgebreide spelersprofiel tonen op een dorpsinformatie pagina",
  4157. farmLimitTitle: "Dorpstacks achtergrondkleuren",
  4158. farmLimitStackColors: "Kleurenschakering",
  4159. farmLimitAcceptableOverstack: "Acceptabele overstack voor elke kleurschakering",
  4160. farmLimitAcceptableOverstackTooltip: "Boerderijlimiet: {farmlimit}",
  4161. farmLimitUnlimitedStack: "Aantal populatie voor elke kleurschakering",
  4162. ajaxSeperateSupport: "Dorpsoverzicht: Visualiseer het verschil tussen eigen en ondersteunende troepen in het dorpsoverzicht",
  4163. canHideDiv: "Dorpsoverzicht: Een extra X icon toevoegen om een info kader volledig te verwijderen",
  4164. commandRenamer: "Bevelen automatisch hernoemen",
  4165. commandRenamerActive: "De verzonden troepen in de bevelnaam weergeven",
  4166. commandRenamerAddHaul: "De buit aan de bevelnaam toevoegen"
  4167. }
  4168. };
  4169.  
  4170. //sangu_trans.de = {};
  4171.  
  4172. /*sangu_trans.en = {
  4173. main: {
  4174. title: "Main building",
  4175. villageNames: "Village names:",
  4176. villageNamesTooltip: "Add village names to the village headquarters to quickly edit the village name to a preset name.",
  4177. villageNameClick: "Autoclick?",
  4178. 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",
  4179. ajaxLoyalty: "Show loyalty?",
  4180. ajaxLoyaltyTooltip: "Get the loyalty at the building construction/destruction page"
  4181. }
  4182. };*/
  4183.  
  4184. return sangu_trans[game_data.market];
  4185. }());
  4186. /**
  4187. * Configuration array containing the metadata for generating the different
  4188. * property editor UIs
  4189. */
  4190. var user_data_configs = (function() {
  4191. /**
  4192. * Debug bool
  4193. */
  4194. var showConfigs = true,
  4195. user_data_configs = [],
  4196. sangu_saver = function() {
  4197. pers.set('sangusettings', JSON.stringify(user_data));
  4198. trackEvent("ScriptUsage", "SettingEdit", "1");
  4199. };
  4200.  
  4201. if (showConfigs) {
  4202. user_data_configs.push({
  4203. id: "global",
  4204. title: sangu_trans.global.title,
  4205. save: sangu_saver,
  4206. properties: {
  4207. twVersion: {
  4208. label: sangu_trans.global.tw_version.replace("{version}", game_data.majorVersion),
  4209. tooltip: sangu_trans.global.tw_versionTooltip,
  4210. propUI: {
  4211. getter: function() { return pers.get("forceCompatibility") !== '' && pers.get("forceCompatibility") === 'true'; },
  4212. setter: function(value) { pers.set("forceCompatibility", value); },
  4213. editor: "bool"
  4214. }
  4215. },
  4216. resourcesTitle: {
  4217. type: "subtitle",
  4218. label: sangu_trans.global.resources.title
  4219. },
  4220. resourcesActivate: {
  4221. label: sangu_trans.global.resources.activate,
  4222. propUI: {
  4223. getter: function() { return user_data.global.resources.active; },
  4224. setter: function(value) { user_data.global.resources.active = value; },
  4225. editor: "bool"
  4226. }
  4227. },
  4228. resourceColors: {
  4229. label: sangu_trans.global.resources.colors,
  4230. propUI: {
  4231. getter: function() { return user_data.global.resources.backgroundColors; },
  4232. setter: function(value) { user_data.global.resources.backgroundColors = value; },
  4233. editor: "array|inline:color"
  4234. }
  4235. },
  4236. resourcesBlinkWhenFull: {
  4237. label: sangu_trans.global.resources.blinkWhenStorageFull,
  4238. propUI: {
  4239. getter: function() { return user_data.global.resources.blinkWhenStorageFull; },
  4240. setter: function(value) { user_data.global.resources.blinkWhenStorageFull = value; },
  4241. editor: "bool"
  4242. }
  4243. },
  4244. incomingsTitle: {
  4245. type: "subtitle",
  4246. label: sangu_trans.global.incomingsTitle
  4247. },
  4248. incomingsEditLinks: {
  4249. label: sangu_trans.global.incomingsEditLinks,
  4250. tooltip: sangu_trans.global.incomingsEditLinksTooltip,
  4251. propUI: {
  4252. getter: function() { return user_data.global.incomings.editLinks; },
  4253. setter: function(value) { user_data.global.incomings.editLinks = value; },
  4254. editor: "bool"
  4255. }
  4256. },
  4257. incomingsTrack: {
  4258. label: sangu_trans.global.incomingsTrack,
  4259. propUI: {
  4260. getter: function() { return user_data.global.incomings.track; },
  4261. setter: function(value) { user_data.global.incomings.track = value; },
  4262. editor: "bool"
  4263. }
  4264. },
  4265. incomingsIndicator: {
  4266. label: sangu_trans.global.incomingsIndicator,
  4267. tooltip: sangu_trans.global.incomingsIndicatorTooltip,
  4268. propUI: {
  4269. getter: function() { return user_data.global.incomings.indicator; },
  4270. setter: function(value) { user_data.global.incomings.indicator = value; },
  4271. editor: "text"
  4272. }
  4273. },
  4274. incomingsIndicatorTooltip2: {
  4275. label: sangu_trans.global.incomingsIndicatorTooltip2,
  4276. propUI: {
  4277. getter: function() { return user_data.global.incomings.indicatorTooltip; },
  4278. setter: function(value) { user_data.global.incomings.indicatorTooltip = value; },
  4279. editor: "text"
  4280. }
  4281. },
  4282. lastTimeCheckWarning: {
  4283. label: sangu_trans.global.incomingsLastTimeCheckWarning,
  4284. tooltip: sangu_trans.global.incomingsLastTimeCheckWarningTooltip,
  4285. propUI: {
  4286. getter: function() { return user_data.global.incomings.lastTimeCheckWarning; },
  4287. setter: function(value) { user_data.global.incomings.lastTimeCheckWarning = value; },
  4288. editor: "text"
  4289. }
  4290. },
  4291. jumperTitle: {
  4292. type: "subtitle",
  4293. label: sangu_trans.global.jumperTitle
  4294. },
  4295. jumperActivate: {
  4296. label: trans.sp.sp.settings.activate,
  4297. propUI: {
  4298. getter: function() { return user_data.jumper.enabled; },
  4299. setter: function(value) { user_data.jumper.enabled = value; },
  4300. editor: "bool"
  4301. }
  4302. },
  4303. jumperAutoOpen: {
  4304. label: sangu_trans.global.jumperAutoOpen,
  4305. propUI: {
  4306. getter: function() { return user_data.jumper.autoShowInputbox; },
  4307. setter: function(value) { user_data.jumper.autoShowInputbox = value; },
  4308. editor: "bool"
  4309. }
  4310. },
  4311. colorsTitle: {
  4312. type: "subtitle",
  4313. label: sangu_trans.global.colorsTitle
  4314. },
  4315. colorsError: {
  4316. label: sangu_trans.global.colorsError,
  4317. propUI: {
  4318. getter: function() { return user_data.colors.error; },
  4319. setter: function(value) { user_data.colors.error = value; },
  4320. editor: "color"
  4321. }
  4322. },
  4323. colorsGood: {
  4324. label: sangu_trans.global.colorsGood,
  4325. propUI: {
  4326. getter: function() { return user_data.colors.good; },
  4327. setter: function(value) { user_data.colors.good = value; },
  4328. editor: "color"
  4329. }
  4330. },
  4331. colorsNeutral: {
  4332. label: sangu_trans.global.colorsNeutral,
  4333. propUI: {
  4334. getter: function() { return user_data.colors.neutral; },
  4335. setter: function(value) { user_data.colors.neutral = value; },
  4336. editor: "color"
  4337. }
  4338. },
  4339. colorsSpecial: {
  4340. label: sangu_trans.global.colorsSpecial,
  4341. propUI: {
  4342. getter: function() { return user_data.colors.special; },
  4343. setter: function(value) { user_data.colors.special = value; },
  4344. editor: "color"
  4345. }
  4346. },
  4347. otherSettingsTitle: {
  4348. type: "subtitle",
  4349. label: sangu_trans.global.otherSettingsTitle
  4350. },
  4351. visualizeFriends: {
  4352. label: sangu_trans.global.visualizeFriends,
  4353. propUI: {
  4354. getter: function() { return user_data.global.visualizeFriends; },
  4355. setter: function(value) { user_data.global.visualizeFriends = value; },
  4356. editor: "bool"
  4357. }
  4358. },
  4359. duplicateLogoffLink: {
  4360. label: sangu_trans.global.duplicateLogoffLink,
  4361. propUI: {
  4362. getter: function() { return user_data.global.duplicateLogoffLink; },
  4363. setter: function(value) { user_data.global.duplicateLogoffLink = value; },
  4364. editor: "bool"
  4365. }
  4366. }
  4367. }
  4368. });
  4369. }
  4370.  
  4371. if (showConfigs) {
  4372. user_data_configs.push({
  4373. id: "main",
  4374. title: sangu_trans.main.title,
  4375. save: sangu_saver,
  4376. properties: {
  4377. villageNames: {
  4378. tooltip: sangu_trans.main.villageNamesTooltip,
  4379. label: sangu_trans.main.villageNames,
  4380. propUI: {
  4381. getter: function() { return user_data.main.villageNames; },
  4382. setter: function(value) { user_data.main.villageNames = value; },
  4383. editor: "array|addNew:text|delete"
  4384. }
  4385. },
  4386. villageNameClick: {
  4387. tooltip: sangu_trans.main.villageNameClickTooltip,
  4388. label: sangu_trans.main.villageNameClick,
  4389. propUI: {
  4390. getter: function() { return user_data.main.villageNameClick; },
  4391. setter: function(value) { user_data.main.villageNameClick = value; },
  4392. editor: "bool"
  4393. }
  4394. },
  4395. ajaxLoyalty: {
  4396. label: sangu_trans.main.ajaxLoyalty,
  4397. show: server_settings.ajaxAllowed,
  4398. propUI: {
  4399. getter: function() { return user_data.main.ajaxLoyalty; },
  4400. setter: function(value) { user_data.main.ajaxLoyalty = value; },
  4401. editor: "bool"
  4402. }
  4403. }
  4404. }
  4405. });
  4406. }
  4407.  
  4408. if (showConfigs) {
  4409. user_data_configs.push({
  4410. id: "incoming",
  4411. title: sangu_trans.incoming.title,
  4412. save: sangu_saver,
  4413. properties: {
  4414. autoOpenTagger: {
  4415. label: sangu_trans.incoming.autoOpenTagger,
  4416. propUI: {
  4417. getter: function() { return user_data.incoming.autoOpenTagger; },
  4418. setter: function(value) { user_data.incoming.autoOpenTagger = value; },
  4419. editor: "bool"
  4420. }
  4421. },
  4422. forceOpenTagger: {
  4423. label: sangu_trans.incoming.forceOpenTagger,
  4424. propUI: {
  4425. getter: function() { return user_data.incoming.forceOpenTagger; },
  4426. setter: function(value) { user_data.incoming.forceOpenTagger = value; },
  4427. editor: "bool"
  4428. }
  4429. },
  4430. renameInputTexbox: {
  4431. label: sangu_trans.incoming.renameInputTexbox,
  4432. tooltip: sangu_trans.incoming.renameInputTexboxTooltip,
  4433. propUI: {
  4434. getter: function() { return user_data.incoming.renameInputTexbox; },
  4435. setter: function(value) { user_data.incoming.renameInputTexbox = value; },
  4436. editor: "text"
  4437. }
  4438. },
  4439. invertSort: {
  4440. label: sangu_trans.incoming.invertSort,
  4441. tooltip: sangu_trans.incoming.invertSortTooltip,
  4442. propUI: {
  4443. getter: function() { return user_data.incoming.invertSort; },
  4444. setter: function(value) { user_data.incoming.invertSort = value; },
  4445. editor: "bool"
  4446. }
  4447. }
  4448. }
  4449. });
  4450. }
  4451.  
  4452. if (showConfigs) {
  4453. (function() {
  4454. var properties = {
  4455. activate: {
  4456. label: sangu_trans.global.resources.activate,
  4457. propUI: {
  4458. getter: function() { return user_data.mainTagger2.active; },
  4459. setter: function(value) { user_data.mainTagger2.active = value; },
  4460. editor: "bool"
  4461. }
  4462. },
  4463. autoOpen: {
  4464. label: sangu_trans.mainTagger.autoOpen,
  4465. propUI: {
  4466. getter: function() { return user_data.mainTagger2.autoOpen; },
  4467. setter: function(value) { user_data.mainTagger2.autoOpen = value; },
  4468. editor: "bool"
  4469. }
  4470. },
  4471. inputBoxWidth: {
  4472. label: sangu_trans.mainTagger.inputBoxWidth,
  4473. propUI: {
  4474. getter: function() { return user_data.mainTagger2.inputBoxWidth; },
  4475. setter: function(value) { user_data.mainTagger2.inputBoxWidth = value; },
  4476. editor: "number|step=5"
  4477. }
  4478. },
  4479. autoOpenCommands: {
  4480. label: sangu_trans.mainTagger.autoOpenCommands,
  4481. propUI: {
  4482. getter: function() { return user_data.mainTagger2.autoOpenCommands; },
  4483. setter: function(value) { user_data.mainTagger2.autoOpenCommands = value; },
  4484. editor: "bool"
  4485. }
  4486. },
  4487. minutesDisplayDodgeTimeOnMap: {
  4488. label: sangu_trans.mainTagger.minutesDisplayDodgeTimeOnMap,
  4489. tooltip: sangu_trans.mainTagger.minutesDisplayDodgeTimeOnMapTooltip,
  4490. propUI: {
  4491. getter: function() { return user_data.mainTagger2.minutesDisplayDodgeTimeOnMap; },
  4492. setter: function(value) { user_data.mainTagger2.minutesDisplayDodgeTimeOnMap = value; },
  4493. editor: "number"
  4494. }
  4495. },
  4496. minutesWithoutAttacksDottedLine: {
  4497. label: sangu_trans.mainTagger.minutesWithoutAttacksDottedLine,
  4498. propUI: {
  4499. getter: function() { return user_data.mainTagger2.minutesWithoutAttacksDottedLine; },
  4500. setter: function(value) { user_data.mainTagger2.minutesWithoutAttacksDottedLine = value; },
  4501. editor: "number|step=60"
  4502. }
  4503. },
  4504. colorSupport: {
  4505. label: sangu_trans.mainTagger.colorSupport,
  4506. propUI: {
  4507. getter: function() { return user_data.mainTagger2.colorSupport; },
  4508. setter: function(value) { user_data.mainTagger2.colorSupport = value; },
  4509. editor: "color"
  4510. }
  4511. },
  4512. defaultDescription: {
  4513. label: sangu_trans.mainTagger.defaultDescription,
  4514. tooltip: sangu_trans.mainTagger.defaultDescriptionTooltip,
  4515. propUI: {
  4516. getter: function() { return user_data.mainTagger2.defaultDescription; },
  4517. setter: function(value) { user_data.mainTagger2.defaultDescription = value; },
  4518. editor: "text"
  4519. }
  4520. },
  4521. keepReservedWords: {
  4522. label: sangu_trans.mainTagger.keepReservedWords,
  4523. tooltip: sangu_trans.mainTagger.keepReservedWordsTooltip,
  4524. propUI: {
  4525. getter: function() { return user_data.mainTagger2.keepReservedWords; },
  4526. setter: function(value) { user_data.mainTagger2.keepReservedWords = value; },
  4527. editor: "bool"
  4528. }
  4529. },
  4530. otherButtonsTitle: {
  4531. type: "subtitle",
  4532. label: sangu_trans.mainTagger.otherButtons.title
  4533. }
  4534. };
  4535.  
  4536. for (var i = 0; i < user_data.mainTagger2.otherDescs.length; i++) {
  4537. (function() {
  4538. var otherDescription = user_data.mainTagger2.otherDescs[i];
  4539.  
  4540. properties['otherButton'+i] = {
  4541. type: "subtitle",
  4542. label: sangu_trans.mainTagger.otherButtons.title + ": " + otherDescription.name
  4543. }
  4544.  
  4545. properties['otherButtonActive'+i] = {
  4546. label: sangu_trans.global.resources.activate,
  4547. propUI: {
  4548. getter: function() { return otherDescription.active; },
  4549. setter: function(value) { otherDescription.active = value; },
  4550. editor: "bool"
  4551. }
  4552. }
  4553.  
  4554. properties['otherButtonName'+i] = {
  4555. label: sangu_trans.mainTagger.otherButtons.button,
  4556. propUI: {
  4557. getter: function() { return otherDescription.name; },
  4558. setter: function(value) { otherDescription.name = value; },
  4559. editor: "text|width=10"
  4560. }
  4561. }
  4562.  
  4563. properties['otherButtonHitKey'+i] = {
  4564. label: sangu_trans.mainTagger.otherButtons.hitKey,
  4565. propUI: {
  4566. getter: function() { return otherDescription.hitKey; },
  4567. setter: function(value) { otherDescription.hitKey = value; },
  4568. editor: "text|width=4"
  4569. }
  4570. }
  4571.  
  4572. properties['otherButtonDesc'+i] = {
  4573. label: sangu_trans.mainTagger.otherButtons.renameTo,
  4574. propUI: {
  4575. getter: function() { return otherDescription.renameTo; },
  4576. setter: function(value) { otherDescription.renameTo = value; },
  4577. editor: "text|width=50"
  4578. }
  4579. }
  4580. }());
  4581. }
  4582.  
  4583.  
  4584. user_data_configs.push({
  4585. id: "mainTagger",
  4586. title: sangu_trans.mainTagger.title,
  4587. save: sangu_saver,
  4588. properties: properties
  4589. });
  4590. }());
  4591. }
  4592.  
  4593. if (showConfigs) {
  4594. user_data_configs.push({
  4595. id: "confirm",
  4596. title: sangu_trans.confirm.title,
  4597. save: sangu_saver,
  4598. properties: {
  4599. addExtraOkButton: {
  4600. label: sangu_trans.confirm.addExtraOkButton,
  4601. propUI: {
  4602. getter: function() { return user_data.confirm.addExtraOkButton; },
  4603. setter: function(value) { user_data.confirm.addExtraOkButton = value; },
  4604. editor: "bool"
  4605. }
  4606. },
  4607. replaceNightBonus: {
  4608. label: sangu_trans.confirm.replaceNightBonus,
  4609. show: world_config.nightbonus.active,
  4610. propUI: {
  4611. getter: function() { return user_data.confirm.replaceNightBonus; },
  4612. setter: function(value) { user_data.confirm.replaceNightBonus = value; },
  4613. editor: "bool"
  4614. }
  4615. },
  4616. replaceTribeClaim: {
  4617. label: sangu_trans.confirm.replaceTribeClaim,
  4618. propUI: {
  4619. getter: function() { return user_data.confirm.replaceTribeClaim; },
  4620. setter: function(value) { user_data.confirm.replaceTribeClaim = value; },
  4621. editor: "bool"
  4622. }
  4623. },
  4624. addCatapultImages: {
  4625. label: sangu_trans.confirm.addCatapultImages,
  4626. propUI: {
  4627. getter: function() { return user_data.confirm.addCatapultImages; },
  4628. setter: function(value) { user_data.confirm.addCatapultImages = value; },
  4629. editor: "bool"
  4630. }
  4631. }
  4632. }
  4633. });
  4634. }
  4635.  
  4636. if (showConfigs) {
  4637. user_data_configs.push({
  4638. id: "profile",
  4639. title: sangu_trans.profile.title,
  4640. save: sangu_saver,
  4641. properties: {
  4642. show: {
  4643. label: sangu_trans.global.resources.activate,
  4644. propUI: {
  4645. getter: function() { return user_data.profile.show; },
  4646. setter: function(value) { user_data.profile.show = value; },
  4647. editor: "bool"
  4648. }
  4649. },
  4650. moveClaim: {
  4651. label: sangu_trans.profile.moveClaim,
  4652. propUI: {
  4653. getter: function() { return user_data.profile.moveClaim; },
  4654. setter: function(value) { user_data.profile.moveClaim = value; },
  4655. editor: "bool"
  4656. }
  4657. },
  4658. mapLink: {
  4659. type: "subtitle",
  4660. label: sangu_trans.profile.mapLink.title
  4661. },
  4662. mapLinkShow: {
  4663. label: sangu_trans.global.resources.activate,
  4664. propUI: {
  4665. getter: function() { return user_data.profile.mapLink.show; },
  4666. setter: function(value) { user_data.profile.mapLink.show = value; },
  4667. editor: "bool"
  4668. }
  4669. },
  4670. mapLinkFill: {
  4671. label: sangu_trans.profile.mapLink.fill,
  4672. propUI: {
  4673. getter: function() { return user_data.profile.mapLink.fill; },
  4674. setter: function(value) { user_data.profile.mapLink.fill = value; },
  4675. editor: "color"
  4676. }
  4677. },
  4678. mapLinkZoom: {
  4679. label: sangu_trans.profile.mapLink.zoom,
  4680. propUI: {
  4681. getter: function() { return user_data.profile.mapLink.zoom; },
  4682. setter: function(value) { user_data.profile.mapLink.zoom = value; },
  4683. editor: "number|step=10"
  4684. }
  4685. },
  4686. mapLinkGrid: {
  4687. label: sangu_trans.profile.mapLink.grid,
  4688. propUI: {
  4689. getter: function() { return user_data.profile.mapLink.grid; },
  4690. setter: function(value) { user_data.profile.mapLink.grid = value; },
  4691. editor: "bool"
  4692. }
  4693. },
  4694. mapLinkGridContinentNumbers: {
  4695. label: sangu_trans.profile.mapLink.gridContinentNumbers,
  4696. propUI: {
  4697. getter: function() { return user_data.profile.mapLink.gridContinentNumbers; },
  4698. setter: function(value) { user_data.profile.mapLink.gridContinentNumbers = value; },
  4699. editor: "bool"
  4700. }
  4701. },
  4702. mapLinkPlayerColor: {
  4703. label: sangu_trans.profile.mapLink.playerColor,
  4704. propUI: {
  4705. getter: function() { return user_data.profile.mapLink.playerColor; },
  4706. setter: function(value) { user_data.profile.mapLink.playerColor = value; },
  4707. editor: "color"
  4708. }
  4709. },
  4710. mapLinkTribeColor: {
  4711. label: sangu_trans.profile.mapLink.tribeColor,
  4712. propUI: {
  4713. getter: function() { return user_data.profile.mapLink.tribeColor; },
  4714. setter: function(value) { user_data.profile.mapLink.tribeColor = value; },
  4715. editor: "color"
  4716. }
  4717. },
  4718. mapLinkCentreX: {
  4719. label: sangu_trans.profile.mapLink.centreX,
  4720. propUI: {
  4721. getter: function() { return user_data.profile.mapLink.centreX; },
  4722. setter: function(value) { user_data.profile.mapLink.centreX = value; },
  4723. editor: "number|step=10"
  4724. }
  4725. },
  4726. mapLinkCentreY: {
  4727. label: sangu_trans.profile.mapLink.centreY,
  4728. propUI: {
  4729. getter: function() { return user_data.profile.mapLink.centreY; },
  4730. setter: function(value) { user_data.profile.mapLink.centreY = value; },
  4731. editor: "number|step=10"
  4732. }
  4733. },
  4734. mapLinkOwnColor: {
  4735. label: sangu_trans.profile.mapLink.ownColor,
  4736. propUI: {
  4737. getter: function() { return user_data.profile.mapLink.ownColor; },
  4738. setter: function(value) { user_data.profile.mapLink.ownColor = value; },
  4739. editor: "color"
  4740. }
  4741. },
  4742. mapLinkMarkedOnly: {
  4743. label: sangu_trans.profile.mapLink.markedOnly,
  4744. propUI: {
  4745. getter: function() { return user_data.profile.mapLink.markedOnly; },
  4746. setter: function(value) { user_data.profile.mapLink.markedOnly = value; },
  4747. editor: "bool"
  4748. }
  4749. },
  4750. mapLinkBigMarkers: {
  4751. label: sangu_trans.profile.mapLink.bigMarkers,
  4752. propUI: {
  4753. getter: function() { return user_data.profile.mapLink.bigMarkers; },
  4754. setter: function(value) { user_data.profile.mapLink.bigMarkers = value; },
  4755. editor: "bool"
  4756. }
  4757. },
  4758. mapLinkYourTribeColor: {
  4759. label: sangu_trans.profile.mapLink.yourTribeColor,
  4760. propUI: {
  4761. getter: function() { return user_data.profile.mapLink.yourTribeColor; },
  4762. setter: function(value) { user_data.profile.mapLink.yourTribeColor = value; },
  4763. editor: "color"
  4764. }
  4765. },
  4766. popup: {
  4767. type: "subtitle",
  4768. label: sangu_trans.profile.popup.title
  4769. },
  4770. popupShow: {
  4771. label: sangu_trans.global.resources.activate,
  4772. propUI: {
  4773. getter: function() { return user_data.profile.popup.show; },
  4774. setter: function(value) { user_data.profile.popup.show = value; },
  4775. editor: "bool"
  4776. }
  4777. },
  4778. popupTop: {
  4779. label: sangu_trans.profile.popup.top,
  4780. propUI: {
  4781. getter: function() { return user_data.profile.popup.top; },
  4782. setter: function(value) { user_data.profile.popup.top = value; },
  4783. editor: "number|step=25"
  4784. }
  4785. },
  4786. popupLeft: {
  4787. label: sangu_trans.profile.popup.left,
  4788. propUI: {
  4789. getter: function() { return user_data.profile.popup.left; },
  4790. setter: function(value) { user_data.profile.popup.left = value; },
  4791. editor: "number|step=25"
  4792. }
  4793. },
  4794. popupWidth: {
  4795. label: sangu_trans.profile.popup.width,
  4796. propUI: {
  4797. getter: function() { return user_data.profile.popup.width; },
  4798. setter: function(value) { user_data.profile.popup.width = value; },
  4799. editor: "number|step=25"
  4800. }
  4801. },
  4802. popupHeight: {
  4803. label: sangu_trans.profile.popup.height,
  4804. propUI: {
  4805. getter: function() { return user_data.profile.popup.height; },
  4806. setter: function(value) { user_data.profile.popup.height = value; },
  4807. editor: "number|step=25"
  4808. }
  4809. }
  4810. }
  4811. });
  4812. }
  4813.  
  4814. if (showConfigs) {
  4815. user_data_configs.push({
  4816. id: "placeLinks",
  4817. title: sangu_trans.place.title,
  4818. save: sangu_saver,
  4819. properties: {
  4820. scoutTitle: {
  4821. type: "subtitle",
  4822. label: sangu_trans.place.scoutTitle
  4823. },
  4824. scoutPlaceLinksName: {
  4825. label: sangu_trans.place.linkText,
  4826. propUI: {
  4827. getter: function() { return user_data.place.attackLinks.scoutPlaceLinksName; },
  4828. setter: function(value) { user_data.place.attackLinks.scoutPlaceLinksName = value; },
  4829. editor: "text|width=23"
  4830. }
  4831. },
  4832. scoutVillage: {
  4833. label: sangu_trans.place.scoutVillage,
  4834. propUI: {
  4835. getter: function() { return user_data.place.attackLinks.scoutVillage; },
  4836. setter: function(value) { user_data.place.attackLinks.scoutVillage = value; },
  4837. editor: "number|step=10"
  4838. }
  4839. },
  4840. scoutPlaceLinks: {
  4841. label: sangu_trans.place.scoutPlaceLinks,
  4842. propUI: {
  4843. getter: function() { return user_data.place.attackLinks.scoutPlaceLinks; },
  4844. setter: function(value) { user_data.place.attackLinks.scoutPlaceLinks = value; },
  4845. editor: "array|addNew:number|step=10|delete"
  4846. }
  4847. },
  4848.  
  4849.  
  4850.  
  4851.  
  4852.  
  4853. fakePlaceLinkTitle: {
  4854. type: "subtitle",
  4855. label: sangu_trans.place.fakePlaceLinkTitle
  4856. },
  4857. fakePlaceLinkName: {
  4858. label: sangu_trans.place.linkText,
  4859. propUI: {
  4860. getter: function() { return user_data.place.attackLinks.fakePlaceLinkName; },
  4861. setter: function(value) { user_data.place.attackLinks.fakePlaceLinkName = value; },
  4862. editor: "text|width=23"
  4863. }
  4864. },
  4865. fakePlaceLink: {
  4866. label: sangu_trans.global.resources.activate,
  4867. propUI: {
  4868. getter: function() { return user_data.place.attackLinks.fakePlaceLink; },
  4869. setter: function(value) { user_data.place.attackLinks.fakePlaceLink = value; },
  4870. editor: "bool"
  4871. }
  4872. },
  4873. fakePlaceExcludeTroops: {
  4874. label: sangu_trans.place.fakePlaceExcludeTroops,
  4875. tooltip: sangu_trans.place.fakePlaceExcludeTroopsTooltip,
  4876. propUI: {
  4877. getter: function() { return user_data.place.attackLinks.fakePlaceExcludeTroops; },
  4878. setter: function(value) { user_data.place.attackLinks.fakePlaceExcludeTroops = value; },
  4879. editor: "array|addNew:text|delete|width=7"
  4880. }
  4881. },
  4882.  
  4883.  
  4884.  
  4885.  
  4886.  
  4887.  
  4888. noblePlaceLinkTitle: {
  4889. type: "subtitle",
  4890. label: sangu_trans.place.noblePlaceLinkTitle
  4891. },
  4892. noblePlaceLinkDivideTitle: {
  4893. type: "subtitle",
  4894. label: sangu_trans.place.noblePlaceLinkDivideTitle
  4895. },
  4896. noblePlaceLinkDivideName: {
  4897. label: sangu_trans.place.linkText,
  4898. propUI: {
  4899. getter: function() { return user_data.place.attackLinks.noblePlaceLinkDivideName; },
  4900. setter: function(value) { user_data.place.attackLinks.noblePlaceLinkDivideName = value; },
  4901. editor: "text|width=23"
  4902. }
  4903. },
  4904. noblePlaceLink: {
  4905. label: sangu_trans.global.resources.activate,
  4906. propUI: {
  4907. getter: function() { return user_data.place.attackLinks.noblePlaceLink; },
  4908. setter: function(value) { user_data.place.attackLinks.noblePlaceLink = value; },
  4909. editor: "bool"
  4910. }
  4911. },
  4912. noblePlaceLinkDivideAddRam: {
  4913. label: sangu_trans.place.noblePlaceLinkDivideAddRam,
  4914. propUI: {
  4915. getter: function() { return user_data.place.attackLinks.noblePlaceLinkDivideAddRam; },
  4916. setter: function(value) { user_data.place.attackLinks.noblePlaceLinkDivideAddRam = value; },
  4917. editor: "bool"
  4918. }
  4919. },
  4920. noblePlaceLinkFirstTitle: {
  4921. type: "subtitle",
  4922. label: sangu_trans.place.noblePlaceLinkFirstTitle
  4923. },
  4924. noblePlaceLinkFirstName: {
  4925. label: sangu_trans.place.linkText,
  4926. tooltip: sangu_trans.place.noblePlaceLinkFirstNameTooltip,
  4927. propUI: {
  4928. getter: function() { return user_data.place.attackLinks.noblePlaceLinkFirstName; },
  4929. setter: function(value) { user_data.place.attackLinks.noblePlaceLinkFirstName = value; },
  4930. editor: "text|width=23"
  4931. }
  4932. },
  4933. noblePlaceLinkSupportTitle: {
  4934. type: "subtitle",
  4935. label: sangu_trans.place.noblePlaceLinkSupportTitle
  4936. },
  4937. noblePlaceLinkSupportName: {
  4938. label: sangu_trans.place.linkText,
  4939. propUI: {
  4940. getter: function() { return user_data.place.attackLinks.noblePlaceLinkSupportName; },
  4941. setter: function(value) { user_data.place.attackLinks.noblePlaceLinkSupportName = value; },
  4942. editor: "text|width=23"
  4943. }
  4944. },
  4945. noblePlaceLinksForceShow: {
  4946. label: sangu_trans.place.noblePlaceLinksForceShow,
  4947. propUI: {
  4948. getter: function() { return user_data.place.attackLinks.noblePlaceLinksForceShow; },
  4949. setter: function(value) { user_data.place.attackLinks.noblePlaceLinksForceShow = value; },
  4950. editor: "bool"
  4951. }
  4952. },
  4953. nobleSupportOffTitle: {
  4954. type: "subtitle",
  4955. label: sangu_trans.place.nobleSupportOffTitle
  4956. },
  4957. nobleSupportOffUnit: {
  4958. label: sangu_trans.place.nobleSupportUnit,
  4959. propUI: {
  4960. getter: function() { return user_data.place.attackLinks.nobleSupport[0].unit; },
  4961. setter: function(value) { user_data.place.attackLinks.nobleSupport[0].unit = value; },
  4962. editor: "unit"
  4963. }
  4964. },
  4965. nobleSupportOffAmount: {
  4966. label: sangu_trans.place.nobleSupportAmount,
  4967. propUI: {
  4968. getter: function() { return user_data.place.attackLinks.nobleSupport[0].amount; },
  4969. setter: function(value) { user_data.place.attackLinks.nobleSupport[0].amount = value; },
  4970. editor: "number|step=50"
  4971. }
  4972. },
  4973. nobleSupportDefTitle: {
  4974. type: "subtitle",
  4975. label: sangu_trans.place.nobleSupportDefTitle
  4976. },
  4977. nobleSupportDefUnit: {
  4978. label: sangu_trans.place.nobleSupportUnit,
  4979. propUI: {
  4980. getter: function() { return user_data.place.attackLinks.nobleSupport[1].unit; },
  4981. setter: function(value) { user_data.place.attackLinks.nobleSupport[1].unit = value; },
  4982. editor: "unit"
  4983. }
  4984. },
  4985. nobleSupportDefAmount: {
  4986. label: sangu_trans.place.nobleSupportAmount,
  4987. propUI: {
  4988. getter: function() { return user_data.place.attackLinks.nobleSupport[1].amount; },
  4989. setter: function(value) { user_data.place.attackLinks.nobleSupport[1].amount = value; },
  4990. editor: "number|step=50"
  4991. }
  4992. }
  4993. }
  4994. });
  4995. }
  4996.  
  4997. if (showConfigs) {
  4998. (function() {
  4999. var i,
  5000. properties = {};
  5001.  
  5002. for (i = 0; i < user_data.place.customPlaceLinks.length; i++) {
  5003. (function() {
  5004. var unitTypeIndex,
  5005. customPlaceLink = user_data.place.customPlaceLinks[i],
  5006. oneTimeTooltip = i == 0 ? sangu_trans.place.customPlaceOneTimeTooltip : undefined,
  5007. oneTimeTooltipSendAlong = i == 0 ? sangu_trans.place.customPlaceSendAlongTooltip : undefined;
  5008.  
  5009. properties['customPlaceLink'+i+'Title'] = {
  5010. type: "subtitle",
  5011. label: sangu_trans.place.link.replace("{name}", customPlaceLink.name)
  5012. };
  5013.  
  5014. properties['customPlaceLink'+i+'Name'] = {
  5015. label: sangu_trans.place.linkText,
  5016. propUI: {
  5017. getter: function() { return customPlaceLink.name; },
  5018. setter: function(value) { customPlaceLink.name = value; },
  5019. editor: "text|width=23"
  5020. }
  5021. };
  5022.  
  5023. properties['customPlaceLink'+i+'Active'] = {
  5024. label: sangu_trans.global.resources.activate,
  5025. propUI: {
  5026. getter: function() { return customPlaceLink.active; },
  5027. setter: function(value) { customPlaceLink.active = value; },
  5028. editor: "bool"
  5029. }
  5030. };
  5031.  
  5032. for (unitTypeIndex = 0; unitTypeIndex < world_data.units.length; unitTypeIndex++) {
  5033. (function() {
  5034. var unit = world_data.units[unitTypeIndex],
  5035. reallyOneTimeTooltip = unitTypeIndex == 0 && oneTimeTooltip ? oneTimeTooltip : undefined;
  5036.  
  5037. properties['customPlaceLink'+i+unit] = {
  5038. label: "<img src='graphic/unit/unit_"+unit+".png'/>",
  5039. tooltip: reallyOneTimeTooltip,
  5040. propUI: {
  5041. getter: function() { return customPlaceLink[unit]; },
  5042. setter: function(value) { customPlaceLink[unit] = value; },
  5043. editor: "number|step=100"
  5044. }
  5045. };
  5046. })();
  5047. }
  5048.  
  5049. properties['customPlaceLink'+i+'SendAlong'] = {
  5050. label: sangu_trans.place.customPlaceSendAlong,
  5051. tooltip: oneTimeTooltipSendAlong,
  5052. propUI: {
  5053. getter: function() { return customPlaceLink.sendAlong; },
  5054. setter: function(value) { customPlaceLink.sendAlong = value; },
  5055. editor: "number|step=100"
  5056. }
  5057. };
  5058. })();
  5059. }
  5060.  
  5061. user_data_configs.push({
  5062. id: "placeLinksCustom",
  5063. title: sangu_trans.place.titleCustom,
  5064. save: sangu_saver,
  5065. properties: properties
  5066. });
  5067. }());
  5068. }
  5069.  
  5070. if (showConfigs) {
  5071. user_data_configs.push({
  5072. id: "overviewsTroops",
  5073. title: sangu_trans.overviews.command.title,
  5074. save: sangu_saver,
  5075. properties: {
  5076. changeTroopsOverviewLink: {
  5077. label: sangu_trans.overviews.command.changeTroopsOverviewLink,
  5078. propUI: {
  5079. getter: function() { return user_data.command.changeTroopsOverviewLink; },
  5080. setter: function(value) { user_data.command.changeTroopsOverviewLink = value; },
  5081. editor: "bool"
  5082. }
  5083. },
  5084. defaultPopulationFilterAmount: {
  5085. label: sangu_trans.overviews.troopsRestack.defaultPopulationFilterAmount,
  5086. propUI: {
  5087. getter: function() { return user_data.restack.defaultPopulationFilterAmount; },
  5088. setter: function(value) { user_data.restack.defaultPopulationFilterAmount = value; },
  5089. editor: "number|step=1000"
  5090. }
  5091. },
  5092.  
  5093. titleOwnTroopsPage: {
  5094. type: "subtitle",
  5095. label: sangu_trans.overviews.command.titleOwnTroopsPage
  5096. },
  5097. middleMouseClickDeletesRow: {
  5098. label: sangu_trans.overviews.command.middleMouseClickDeletesRow,
  5099. tooltip: sangu_trans.overviews.command.middleMouseClickDeletesRowTooltip,
  5100. propUI: {
  5101. getter: function() { return user_data.command.middleMouseClickDeletesRow2; },
  5102. setter: function(value) { user_data.command.middleMouseClickDeletesRow2 = value; },
  5103. editor: "bool"
  5104. }
  5105. },
  5106. filterAutoSort: {
  5107. label: sangu_trans.overviews.command.filterAutoSort,
  5108. propUI: {
  5109. getter: function() { return user_data.command.filterAutoSort; },
  5110. setter: function(value) { user_data.command.filterAutoSort = value; },
  5111. editor: "bool"
  5112. }
  5113. },
  5114.  
  5115.  
  5116. titleDefensePage: {
  5117. type: "subtitle",
  5118. label: sangu_trans.overviews.command.titleDefensePage
  5119. },
  5120. fieldsDistanceFilterDefault: {
  5121. label: sangu_trans.overviews.troopsRestack.fieldsDistanceFilterDefault,
  5122. propUI: {
  5123. getter: function() { return user_data.restack.fieldsDistanceFilterDefault; },
  5124. setter: function(value) { user_data.restack.fieldsDistanceFilterDefault = value; },
  5125. editor: "number"
  5126. }
  5127. },
  5128. filterReverse: {
  5129. label: sangu_trans.overviews.troopsRestack.filterReverse,
  5130. tooltip: sangu_trans.overviews.troopsRestack.filterReverseTooltip,
  5131. propUI: {
  5132. getter: function() { return user_data.restack.filterReverse; },
  5133. setter: function(value) { user_data.restack.filterReverse = value; },
  5134. editor: "bool"
  5135. }
  5136. },
  5137. filterMinPopulation: {
  5138. label: sangu_trans.overviews.command.filterMinPopulation,
  5139. propUI: {
  5140. getter: function() { return user_data.command.filterMinPopulation; },
  5141. setter: function(value) { user_data.command.filterMinPopulation = value; },
  5142. editor: "number|step=1000"
  5143. }
  5144. },
  5145. removeRowsWithoutSupport: {
  5146. label: sangu_trans.overviews.troopsRestack.removeRowsWithoutSupport,
  5147. propUI: {
  5148. getter: function() { return user_data.restack.removeRowsWithoutSupport; },
  5149. setter: function(value) { user_data.restack.removeRowsWithoutSupport = value; },
  5150. editor: "bool"
  5151. }
  5152. },
  5153. autohideWithoutSupportAfterFilter: {
  5154. label: sangu_trans.overviews.troopsRestack.autohideWithoutSupportAfterFilter,
  5155. tooltip: sangu_trans.overviews.troopsRestack.autohideWithoutSupportAfterFilterTooltip,
  5156. propUI: {
  5157. getter: function() { return user_data.restack.autohideWithoutSupportAfterFilter; },
  5158. setter: function(value) { user_data.restack.autohideWithoutSupportAfterFilter = value; },
  5159. editor: "bool"
  5160. }
  5161. },
  5162. calculateDefTotalsAfterFilter: {
  5163. label: sangu_trans.overviews.troopsRestack.calculateDefTotalsAfterFilter,
  5164. tooltip: sangu_trans.overviews.troopsRestack.calculateDefTotalsAfterFilterTooltip,
  5165. propUI: {
  5166. getter: function() { return user_data.restack.calculateDefTotalsAfterFilter; },
  5167. setter: function(value) { user_data.restack.calculateDefTotalsAfterFilter = value; },
  5168. editor: "bool"
  5169. }
  5170. },
  5171.  
  5172. commandTitle: {
  5173. type: "subtitle",
  5174. label: sangu_trans.overviews.command.filterOnUnitTypeSeperator
  5175. },
  5176. filterMinDefaultType: {
  5177. label: sangu_trans.overviews.command.filterMinDefaultType,
  5178. propUI: {
  5179. getter: function() { return user_data.command.filterMinDefaultType; },
  5180. setter: function(value) { user_data.command.filterMinDefaultType = value; },
  5181. editor: "unit"
  5182. }
  5183. },
  5184. filterMinDefault: {
  5185. label: sangu_trans.overviews.command.filterMinDefault,
  5186. tooltip: sangu_trans.overviews.command.filterMinDefaultTooltip,
  5187. propUI: {
  5188. getter: function() { return user_data.command.filterMinDefault; },
  5189. setter: function(value) { user_data.command.filterMinDefault = value; },
  5190. editor: "number|step=100"
  5191. }
  5192. },
  5193. filterMinSpear: {
  5194. label: "<img src='graphic/unit/unit_spear.png' />",
  5195. propUI: {
  5196. getter: function() { return user_data.command.filterMin.spear; },
  5197. setter: function(value) { user_data.command.filterMin.spear = value; },
  5198. editor: "number|step=500"
  5199. }
  5200. },
  5201. filterMinSword: {
  5202. label: "<img src='graphic/unit/unit_sword.png' />",
  5203. propUI: {
  5204. getter: function() { return user_data.command.filterMin.sword; },
  5205. setter: function(value) { user_data.command.filterMin.sword = value; },
  5206. editor: "number|step=500"
  5207. }
  5208. },
  5209. filterMinAxe: {
  5210. label: "<img src='graphic/unit/unit_axe.png' />",
  5211. propUI: {
  5212. getter: function() { return user_data.command.filterMin.axe; },
  5213. setter: function(value) { user_data.command.filterMin.axe = value; },
  5214. editor: "number|step=500"
  5215. }
  5216. },
  5217. filterMinArcher: {
  5218. label: "<img src='graphic/unit/unit_archer.png' />",
  5219. show: world_config.hasArchers,
  5220. propUI: {
  5221. getter: function() { return user_data.command.filterMin.archer; },
  5222. setter: function(value) { user_data.command.filterMin.archer = value; },
  5223. editor: "number|step=500"
  5224. }
  5225. },
  5226. filterMinSpy: {
  5227. label: "<img src='graphic/unit/unit_spy.png' />",
  5228. propUI: {
  5229. getter: function() { return user_data.command.filterMin.spy; },
  5230. setter: function(value) { user_data.command.filterMin.spy = value; },
  5231. editor: "number|step=100"
  5232. }
  5233. },
  5234. filterMinLight: {
  5235. label: "<img src='graphic/unit/unit_light.png' />",
  5236. propUI: {
  5237. getter: function() { return user_data.command.filterMin.light; },
  5238. setter: function(value) { user_data.command.filterMin.light = value; },
  5239. editor: "number|step=100"
  5240. }
  5241. },
  5242. filterMinMarcher: {
  5243. label: "<img src='graphic/unit/unit_marcher.png' />",
  5244. show: world_config.hasArchers,
  5245. propUI: {
  5246. getter: function() { return user_data.command.filterMin.marcher; },
  5247. setter: function(value) { user_data.command.filterMin.marcher = value; },
  5248. editor: "number|step=100"
  5249. }
  5250. },
  5251. filterMinHeavy: {
  5252. label: "<img src='graphic/unit/unit_heavy.png' />",
  5253. propUI: {
  5254. getter: function() { return user_data.command.filterMin.heavy; },
  5255. setter: function(value) { user_data.command.filterMin.heavy = value; },
  5256. editor: "number|step=100"
  5257. }
  5258. },
  5259. filterMinRam: {
  5260. label: "<img src='graphic/unit/unit_ram.png' />",
  5261. propUI: {
  5262. getter: function() { return user_data.command.filterMin.ram; },
  5263. setter: function(value) { user_data.command.filterMin.ram = value; },
  5264. editor: "number|step=10"
  5265. }
  5266. },
  5267. filterMinCatapult: {
  5268. label: "<img src='graphic/unit/unit_catapult.png' />",
  5269. propUI: {
  5270. getter: function() { return user_data.command.filterMin.catapult; },
  5271. setter: function(value) { user_data.command.filterMin.catapult = value; },
  5272. editor: "number|step=10"
  5273. }
  5274. },
  5275. filterMinSnob: {
  5276. label: "<img src='graphic/unit/unit_snob.png' />",
  5277. propUI: {
  5278. getter: function() { return user_data.command.filterMin.snob; },
  5279. setter: function(value) { user_data.command.filterMin.snob = value; },
  5280. editor: "number"
  5281. }
  5282. },
  5283. filterMinOther: {
  5284. label: sangu_trans.overviews.command.filterMinOther,
  5285. propUI: {
  5286. getter: function() { return user_data.command.filterMinOther; },
  5287. setter: function(value) { user_data.command.filterMinOther = value; },
  5288. editor: "number|step=500"
  5289. }
  5290. },
  5291. restackTitle: {
  5292. type: "subtitle",
  5293. label: sangu_trans.overviews.troopsRestack.title
  5294. },
  5295. troopsRestackTo: {
  5296. label: sangu_trans.overviews.troopsRestack.to,
  5297. propUI: {
  5298. getter: function() { return user_data.restack.to; },
  5299. setter: function(value) { user_data.restack.to = value; },
  5300. editor: "number|step=1000"
  5301. }
  5302. },
  5303. requiredDifference: {
  5304. label: sangu_trans.overviews.troopsRestack.requiredDifference,
  5305. propUI: {
  5306. getter: function() { return user_data.restack.requiredDifference; },
  5307. setter: function(value) { user_data.restack.requiredDifference = value; },
  5308. editor: "number|step=500"
  5309. }
  5310. }
  5311. }
  5312. });
  5313. }
  5314.  
  5315. if (showConfigs) {
  5316. user_data_configs.push({
  5317. id: "overviewsCommands",
  5318. title: sangu_trans.overviews.commands.title,
  5319. save: sangu_saver,
  5320. properties: {
  5321. sumRow: {
  5322. label: sangu_trans.overviews.commands.sumRow,
  5323. propUI: {
  5324. getter: function() { return user_data.command.sumRow; },
  5325. setter: function(value) { user_data.command.sumRow = value; },
  5326. editor: "bool"
  5327. }
  5328. },
  5329. filterFakeMaxPop: {
  5330. label: sangu_trans.overviews.commands.filterFakeMaxPop,
  5331. propUI: {
  5332. getter: function() { return user_data.command.filterFakeMaxPop; },
  5333. setter: function(value) { user_data.command.filterFakeMaxPop = value; },
  5334. editor: "number|step=100"
  5335. }
  5336. },
  5337. requiredTroopAmount: {
  5338. label: sangu_trans.overviews.commands.requiredTroopAmount,
  5339. propUI: {
  5340. getter: function() { return user_data.command.bbCodeExport.requiredTroopAmount; },
  5341. setter: function(value) { user_data.command.bbCodeExport.requiredTroopAmount = value; },
  5342. editor: "number|step=100"
  5343. }
  5344. }
  5345. }
  5346. });
  5347. }
  5348.  
  5349. if (showConfigs) {
  5350. user_data_configs.push({
  5351. id: "overviewsResources",
  5352. title: sangu_trans.overviews.resources.title,
  5353. save: sangu_saver,
  5354. properties: {
  5355. requiredResDefault: {
  5356. label: sangu_trans.overviews.resources.requiredResDefault,
  5357. propUI: {
  5358. getter: function() { return user_data.resources.requiredResDefault; },
  5359. setter: function(value) { user_data.resources.requiredResDefault = value; },
  5360. editor: "number|step=10000"
  5361. }
  5362. },
  5363. requiredMerchants: {
  5364. label: sangu_trans.overviews.resources.requiredMerchants,
  5365. propUI: {
  5366. getter: function() { return user_data.resources.requiredMerchants; },
  5367. setter: function(value) { user_data.resources.requiredMerchants = value; },
  5368. editor: "number|step=10"
  5369. }
  5370. },
  5371. filterMerchants: {
  5372. label: sangu_trans.overviews.resources.filterMerchants,
  5373. propUI: {
  5374. getter: function() { return user_data.resources.filterMerchants; },
  5375. setter: function(value) { user_data.resources.filterMerchants = value; },
  5376. editor: "bool"
  5377. }
  5378. },
  5379. highlightColor: {
  5380. label: sangu_trans.overviews.resources.highlightColor,
  5381. propUI: {
  5382. getter: function() { return user_data.resources.highlightColor; },
  5383. setter: function(value) { user_data.resources.highlightColor = value; },
  5384. editor: "color"
  5385. }
  5386. },
  5387. filterRows: {
  5388. label: sangu_trans.overviews.resources.filterRows,
  5389. propUI: {
  5390. getter: function() { return user_data.resources.filterRows; },
  5391. setter: function(value) { user_data.resources.filterRows = value; },
  5392. editor: "bool"
  5393. }
  5394. },
  5395. bbcodeMinimumDiff: {
  5396. label: sangu_trans.overviews.resources.bbcodeMinimumDiff,
  5397. propUI: {
  5398. getter: function() { return user_data.resources.bbcodeMinimumDiff; },
  5399. setter: function(value) { user_data.resources.bbcodeMinimumDiff = value; },
  5400. editor: "number|step=2000"
  5401. }
  5402. }
  5403. }
  5404. });
  5405. }
  5406.  
  5407. if (showConfigs) {
  5408. // Buildingsoverview:
  5409. (function() {
  5410. var properties = {},
  5411. i;
  5412.  
  5413. for (i = 0; i < world_data.buildings.length; i++) {
  5414. (function() {
  5415. var captured_index = i,
  5416. building_name = world_data.buildings[captured_index],
  5417. buildingPrettyfier = function(building) { return "<img src='graphic/buildings/"+building+".png'>"; };
  5418.  
  5419. properties[building_name+'_min'] = {
  5420. label: sangu_trans.overviews.buildings.minLevel.replace("{building}", buildingPrettyfier(building_name)),
  5421. propUI: {
  5422. getter: function() { return user_data.buildings[building_name][0]; },
  5423. setter: function(value) { user_data.buildings[building_name][0] = value; },
  5424. editor: "number"
  5425. }
  5426. };
  5427.  
  5428. properties[building_name+'_max'] = {
  5429. label: sangu_trans.overviews.buildings.maxLevel.replace("{building}", buildingPrettyfier(building_name)),
  5430. propUI: {
  5431. getter: function() { return user_data.buildings[building_name][1]; },
  5432. setter: function(value) { user_data.buildings[building_name][1] = value; },
  5433. editor: "number"
  5434. }
  5435. };
  5436. })();
  5437. }
  5438.  
  5439. user_data_configs.push({
  5440. id: "overviewsBuildings",
  5441. title: sangu_trans.overviews.buildings.title,
  5442. save: sangu_saver,
  5443. properties: properties
  5444. });
  5445. }());
  5446. }
  5447.  
  5448. if (showConfigs) {
  5449. // Incomingsoverview:
  5450. (function() {
  5451. var properties = {},
  5452. i;
  5453.  
  5454. properties.attackIdTitle = {
  5455. type: "subtitle",
  5456. label: sangu_trans.overviews.incomings.attackIdTitle
  5457. };
  5458.  
  5459. for (i = 0; i < user_data.incomings.attackIdDescriptions.length; i++) {
  5460. (function() {
  5461. var captured_index = i;
  5462.  
  5463. properties['incomings_attackIdDesc'+captured_index+'_title'] = {
  5464. type: "subtitle",
  5465. label: sangu_trans.overviews.incomings.seperatorTitle.replace("{minValue}", user_data.incomings.attackIdDescriptions[captured_index].minValue)
  5466. };
  5467.  
  5468. properties['incomings_attackIdDesc'+captured_index+'_minValue'] = {
  5469. label: sangu_trans.overviews.incomings.minValue,
  5470. tooltip: captured_index == 0 ? sangu_trans.overviews.incomings.minValueTooltip : undefined,
  5471. propUI: {
  5472. getter: function() { return user_data.incomings.attackIdDescriptions[captured_index].minValue; },
  5473. setter: function(value) { user_data.incomings.attackIdDescriptions[captured_index].minValue = value; },
  5474. editor: "number"
  5475. }
  5476. };
  5477.  
  5478. properties['incomings_attackIdDesc'+captured_index+'_text'] = {
  5479. label: sangu_trans.overviews.incomings.text,
  5480. propUI: {
  5481. getter: function() { return user_data.incomings.attackIdDescriptions[captured_index].text; },
  5482. setter: function(value) { user_data.incomings.attackIdDescriptions[captured_index].text = value; },
  5483. editor: "text"
  5484. }
  5485. };
  5486. })();
  5487. }
  5488.  
  5489. properties['incomings_attackIdDescMaxText'] = {
  5490. label: sangu_trans.overviews.incomings.attackIdHigherDescription,
  5491. propUI: {
  5492. getter: function() { return user_data.incomings.attackIdHigherDescription; },
  5493. setter: function(value) { user_data.incomings.attackIdHigherDescription = value; },
  5494. editor: "text"
  5495. }
  5496. };
  5497.  
  5498. user_data_configs.push({
  5499. id: "overviewsIncomings",
  5500. title: sangu_trans.overviews.incomings.title,
  5501. save: sangu_saver,
  5502. properties: properties
  5503. });
  5504. }());
  5505. }
  5506.  
  5507. if (showConfigs) {
  5508. user_data_configs.push({
  5509. id: "other",
  5510. title: sangu_trans.other.title,
  5511. save: sangu_saver,
  5512. properties: {
  5513. fancyImages: {
  5514. label: sangu_trans.overviews.addFancyImagesToOverviewLinks,
  5515. propUI: {
  5516. getter: function() { return user_data.overviews.addFancyImagesToOverviewLinks; },
  5517. setter: function(value) { user_data.overviews.addFancyImagesToOverviewLinks = value; },
  5518. editor: "bool"
  5519. }
  5520. },
  5521. proStyle: {
  5522. tooltip: sangu_trans.other.proStyleTooltip,
  5523. label: sangu_trans.other.proStyle,
  5524. propUI: {
  5525. getter: function() { return user_data.proStyle; },
  5526. setter: function(value) { user_data.proStyle = value; },
  5527. editor: "bool"
  5528. }
  5529. },
  5530. calculateSnob: {
  5531. label: sangu_trans.other.calculateSnob,
  5532. show: !world_config.coins,
  5533. propUI: {
  5534. getter: function() { return user_data.other.calculateSnob; },
  5535. setter: function(value) { user_data.other.calculateSnob = value; },
  5536. editor: "bool"
  5537. }
  5538. },
  5539. showPlayerProfileOnVillage: {
  5540. label: sangu_trans.other.showPlayerProfileOnVillage,
  5541. propUI: {
  5542. getter: function() { return user_data.showPlayerProfileOnVillage; },
  5543. setter: function(value) { user_data.showPlayerProfileOnVillage = value; },
  5544. editor: "bool"
  5545. }
  5546. },
  5547. overviewAjaxSeperateSupport: {
  5548. label: sangu_trans.other.ajaxSeperateSupport,
  5549. show: server_settings.ajaxAllowed,
  5550. propUI: {
  5551. getter: function() { return user_data.overview.ajaxSeperateSupport; },
  5552. setter: function(value) { user_data.overview.ajaxSeperateSupport = value; },
  5553. editor: "bool"
  5554. }
  5555. },
  5556. canHideDiv: {
  5557. label: sangu_trans.other.canHideDiv,
  5558. propUI: {
  5559. getter: function() { return user_data.overview.canHideDiv; },
  5560. setter: function(value) { user_data.overview.canHideDiv = value; },
  5561. editor: "bool"
  5562. }
  5563. },
  5564. timeDisplayTitle: {
  5565. type: "subtitle",
  5566. label: sangu_trans.other.timeDisplayTitle
  5567. },
  5568. walkingTimeDisplay: {
  5569. label: sangu_trans.other.walkingTimeDisplay,
  5570. tooltip: sangu_trans.other.walkingTimeDisplayTooltip,
  5571. propUI: {
  5572. getter: function() { return user_data.walkingTimeDisplay; },
  5573. setter: function(value) { user_data.walkingTimeDisplay = value; },
  5574. editor: "text"
  5575. }
  5576. },
  5577. displayDays: {
  5578. label: sangu_trans.other.displayDays,
  5579. tooltip: sangu_trans.other.displayDaysTooltip,
  5580. propUI: {
  5581. getter: function() { return user_data.displayDays; },
  5582. setter: function(value) { user_data.displayDays = value; },
  5583. editor: "bool"
  5584. }
  5585. },
  5586. commandRenamerTitle: {
  5587. type: "subtitle",
  5588. label: sangu_trans.other.commandRenamer
  5589. },
  5590. commandRenamerActive: {
  5591. label: sangu_trans.other.commandRenamerActive,
  5592. propUI: {
  5593. getter: function() { return user_data.attackAutoRename.active; },
  5594. setter: function(value) { user_data.attackAutoRename.active = value; },
  5595. editor: "bool"
  5596. }
  5597. },
  5598. commandRenamerAddHaul: {
  5599. label: sangu_trans.other.commandRenamerAddHaul,
  5600. propUI: {
  5601. getter: function() { return user_data.attackAutoRename.addHaul; },
  5602. setter: function(value) { user_data.attackAutoRename.addHaul = value; },
  5603. editor: "bool"
  5604. }
  5605. },
  5606. farmLimitTitle: {
  5607. type: "subtitle",
  5608. label: sangu_trans.other.farmLimitTitle
  5609. },
  5610. farmLimitColors: {
  5611. label: sangu_trans.other.farmLimitStackColors,
  5612. propUI: {
  5613. getter: function(propIndex) {
  5614. return user_data.farmLimit.stackColors;
  5615. },
  5616. setter: function(value, propIndex) { user_data.farmLimit.stackColors = value; },
  5617. editor: "array|addNew:color|delete"
  5618. }
  5619. },
  5620. farmLimitAcceptableOverstack: {
  5621. label: sangu_trans.other.farmLimitAcceptableOverstack,
  5622. tooltip: sangu_trans.other.farmLimitAcceptableOverstackTooltip.replace("{farmlimit}", 30 * world_config.farmLimit),
  5623. show: world_config.farmLimit,
  5624. propUI: {
  5625. getter: function() { return user_data.farmLimit.acceptableOverstack; },
  5626. setter: function(value) { user_data.farmLimit.acceptableOverstack = value; },
  5627. editor: "array|addNew:float|delete|step=0.01"
  5628. }
  5629. },
  5630. farmLimitUnlimitedStack: {
  5631. label: sangu_trans.other.farmLimitUnlimitedStack,
  5632. show: !world_config.farmLimit,
  5633. propUI: {
  5634. getter: function() { return user_data.farmLimit.unlimitedStack; },
  5635. setter: function(value) { user_data.farmLimit.unlimitedStack = value; },
  5636. editor: "array|addNew:number|delete|step=1000"
  5637. }
  5638. }
  5639. }
  5640. });
  5641. }
  5642.  
  5643.  
  5644.  
  5645.  
  5646. if (showConfigs) {
  5647. // Extra links on village info to troop overview
  5648. (function() {
  5649. var properties = {},
  5650. i;
  5651.  
  5652. function addSetting(properties, index, offDef, propName, label, editor, tooltip) {
  5653. properties['infoPage_extra_link'+index+'_'+offDef+propName] = {
  5654. label: label,
  5655. tooltip: tooltip,
  5656. propUI: {
  5657. getter: function() { return user_data.villageInfo4[index][offDef][propName]; },
  5658. setter: function(value) { user_data.villageInfo4[index][offDef][propName] = value; },
  5659. editor: editor
  5660. }
  5661. };
  5662. }
  5663.  
  5664. // hehe
  5665. function addSetting2(properties, index, offDef, propName, label, editor, tooltip) {
  5666. properties['infoPage_extra_link'+index+'_'+offDef+propName] = {
  5667. label: label,
  5668. tooltip: tooltip,
  5669. propUI: {
  5670. getter: function() { return user_data.villageInfo4[index][offDef].filter[propName]; },
  5671. setter: function(value) { user_data.villageInfo4[index][offDef].filter[propName] = value; },
  5672. editor: editor
  5673. }
  5674. };
  5675. }
  5676.  
  5677. function add2Links(captured_index, offDef) {
  5678. addSetting(properties, captured_index, offDef+"_link", "name", sangu_trans.villageInfo.linkName, "text");
  5679. addSetting(properties, captured_index, offDef+"_link", "icon", sangu_trans.villageInfo.icon, "text");
  5680. addSetting(properties, captured_index, offDef+"_link", "sort", sangu_trans.villageInfo.sort, "bool");
  5681. addSetting(properties, captured_index, offDef+"_link", "changeSpeed", sangu_trans.villageInfo.changeSpeed, "unit");
  5682. addSetting(properties, captured_index, offDef+"_link", "group", sangu_trans.villageInfo.group, "number", sangu_trans.villageInfo.groupTitle);
  5683.  
  5684. properties['incomings_attackIdDesc'+captured_index+offDef+'_FilterTitle'] = {
  5685. type: "subtitle",
  5686. label: sangu_trans.villageInfo.filter.title
  5687. };
  5688.  
  5689. addSetting2(properties, captured_index, offDef+"_link", "active", sangu_trans.villageInfo.filter.title, "bool");
  5690. addSetting2(properties, captured_index, offDef+"_link", "unit", sangu_trans.villageInfo.filter.unit, "unit");
  5691. addSetting2(properties, captured_index, offDef+"_link", "amount", sangu_trans.villageInfo.filter.amount, "number|step=100");
  5692. }
  5693.  
  5694. for (i = 0; i < user_data.villageInfo4.length; i++) {
  5695. (function() {
  5696. var captured_index = i;
  5697.  
  5698. properties['incomings_attackIdDesc'+captured_index+'_title'] = {
  5699. type: "subtitle",
  5700. label: sangu_trans.villageInfo.title2 + " " + (captured_index + 1)
  5701. };
  5702.  
  5703. properties['infoPage_extra_link'+captured_index+'_activate'] = {
  5704. label: sangu_trans.global.resources.activate,
  5705. propUI: {
  5706. getter: function() { return user_data.villageInfo4[captured_index].active; },
  5707. setter: function(value) { user_data.villageInfo4[captured_index].active = value; },
  5708. editor: "bool"
  5709. }
  5710. };
  5711.  
  5712. properties['incomings_attackIdDesc'+captured_index+"off"+'_title'] = {
  5713. type: "subtitle",
  5714. label: sangu_trans.villageInfo.off_title
  5715. };
  5716. add2Links(captured_index, "off");
  5717.  
  5718. properties['incomings_attackIdDesc'+captured_index+"def"+'_title'] = {
  5719. type: "subtitle",
  5720. label: sangu_trans.villageInfo.def_title
  5721. };
  5722. add2Links(captured_index, "def");
  5723.  
  5724. })();
  5725. }
  5726.  
  5727. user_data_configs.push({
  5728. id: "villageInfoLinks",
  5729. title: sangu_trans.villageInfo.title,
  5730. save: sangu_saver,
  5731. properties: properties
  5732. });
  5733. }());
  5734. }
  5735.  
  5736. return user_data_configs;
  5737. }());
  5738. (function() {
  5739. // contentPage is the place we will add the settings menu to
  5740. var contentPage = $("table:first td:last", content_value).attr("width", "99%"),
  5741. sanguTitle = "<h3 id='sanguConfigTitle'>" + trans.sp.sp.configuration.replace("{version}", sangu_version) + "</h3>";
  5742.  
  5743. function gimmeTheMoney() {
  5744. function createButton(paypalCode, euroAmount, tooltip) {
  5745. return '<div align="center">'
  5746. + '<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">'
  5747. + '<input type="hidden" name="cmd" value="_s-xclick">'
  5748. + '<input type="hidden" name="hosted_button_id" value="' + paypalCode + '">'
  5749. + '<input type="image" src="https://www.paypalobjects.com/nl_NL/BE/i/btn/btn_donate_SM.gif" border="0" name="submit" title="'+tooltip+'">'
  5750. + '<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">'
  5751. + '<br>' + trans.sp.sp.donate.buttonAmount.replace("{amount}", euroAmount)
  5752. + '</form></div>';
  5753. }
  5754.  
  5755. var html = "<h3>Contributors</h3>";
  5756. html += "Hebben aan het Sangu Package meegewerkt: <br><b>";
  5757. html += "De Goede Fee, Tjeerdo, cgrain, Hardcode93";
  5758. html += "</b>";
  5759.  
  5760. html += "<h3>"+trans.sp.sp.donate.title+"</h3>";
  5761. html += trans.sp.sp.donate.whyWouldI;
  5762. html += "<br>" + trans.sp.sp.donate.books
  5763. .replace("{abegin}", "<a target='_blank' href='http://www.amazon.com/wishlist/1RFQ21NSF4PAI/ref=cm_wl_prev_ret?_encoding=UTF8&reveal='>")
  5764. .replace("{aend}", "</a>");
  5765.  
  5766. html += "<br><br>"
  5767. + "<table width='100%'><tr>"
  5768. + "<td>" + createButton("FA9MAMFAYKANL", 5, trans.sp.sp.donate.beer) + "</td>"
  5769. + "<td>" + createButton("R9RX6XBCV6T4G", 10, trans.sp.sp.donate.food) + "</td>"
  5770. + "<td>" + createButton("ELG8Y2GLSXAVA", 20, trans.sp.sp.donate.yaye) + "</td>"
  5771. + "</tr>"
  5772. + "</table>";
  5773.  
  5774. return html;
  5775. }
  5776.  
  5777. // Reset sangu settings links
  5778. var resetForm = "<a href='#' id='resetSettings'>&raquo; " + trans.sp.sp.settings.reset + "</a>";
  5779. resetForm += "<br>";
  5780. resetForm += "<a href='#' id='resetAllSettings'>&raquo; " + trans.sp.sp.settings.resetAll + "</a>";
  5781.  
  5782. // skeleton injection
  5783. contentPage.html(sanguTitle + "<div id='sanguSettingsForm'>" + resetForm + gimmeTheMoney() + "</div>");
  5784.  
  5785. gimmeTheMoney();
  5786. $("#sanguSettingsForm").append("<br><br>");
  5787.  
  5788. $("#resetSettings").click(function() {
  5789. if (confirm(trans.sp.sp.settings.reset)) {
  5790. pers.set('sangusettings', '');
  5791. location.reload(false);
  5792. }
  5793. return false;
  5794. });
  5795.  
  5796. $("#resetAllSettings").click(function() {
  5797. if (confirm(trans.sp.sp.settings.resetAll)) {
  5798. pers.clear();
  5799. location.reload(false);
  5800. }
  5801. return false;
  5802. });
  5803.  
  5804. (function() {
  5805. var sanguSettingsForm,
  5806. configIterator,
  5807. settingFormTogglerHtml,
  5808. settingsFormsOpenFromPersistence,
  5809. adornButton = function(button) { $(button).css("background-color", user_data.colors.error); };
  5810.  
  5811. sanguSettingsForm = $("#sanguSettingsForm");
  5812.  
  5813. settingFormTogglerHtml = "<h3>" + trans.sp.sp.settings.configuration + "</h3>";
  5814. settingFormTogglerHtml +=
  5815. "<table class='vis' width='100%'><tr class='row_a'><th>"
  5816. + trans.sp.sp.settings.configurationFormTogglerTooltip
  5817. + "</th></tr><tr class='row_b'><td>";
  5818. for (configIterator = 0; configIterator < user_data_configs.length; configIterator++) {
  5819. settingFormTogglerHtml +=
  5820. "<input type='button' value=\""
  5821. + user_data_configs[configIterator].title
  5822. + "\" id='"+user_data_configs[configIterator].id
  5823. + "_button' class='editFormToggler' /> &nbsp;";
  5824. }
  5825. settingFormTogglerHtml += "</td></tr></table><br>";
  5826. sanguSettingsForm.append(settingFormTogglerHtml);
  5827. $(".editFormToggler", sanguSettingsForm).click(function() {
  5828. var openForms = "",
  5829. linkedDiv = $("#" + this.id.replace("_button", ""));
  5830.  
  5831. if (linkedDiv.is(":visible")) {
  5832. linkedDiv.hide();
  5833. $(this).css("background-color", "");
  5834. } else {
  5835. linkedDiv.fadeIn();
  5836. adornButton(this);
  5837. }
  5838.  
  5839. $(".propertyEditFormContainer", sanguSettingsForm).each(function() {
  5840. if ($(this).is(":visible")) {
  5841. openForms += this.id + "|";
  5842. }
  5843. });
  5844. pers.set("settingsFormsOpen", openForms);
  5845. });
  5846.  
  5847. // build the property handler editting form
  5848. for (configIterator = 0; configIterator < user_data_configs.length; configIterator++) {
  5849. buildConfigForm(sanguSettingsForm, user_data_configs[configIterator]);
  5850. }
  5851.  
  5852. settingsFormsOpenFromPersistence = pers.get("settingsFormsOpen");
  5853. $(".propertyEditFormContainer", sanguSettingsForm).each(function() {
  5854. if (settingsFormsOpenFromPersistence.indexOf(this.id+"|") > -1) {
  5855. adornButton($("#" + this.id + "_button"));
  5856. $(this).show();
  5857. }
  5858. });
  5859.  
  5860. $('input[id*="mainTagger_otherButtonHitKey"]').on('keydown', function(e){
  5861. e.preventDefault();
  5862. e.stopPropagation();
  5863. var TagNumber = $(this).attr("id").match(/\d+/);
  5864. $(this).val('');
  5865. $(this).val(keyCodeMap[e.which].toUpperCase());
  5866. user_data.mainTagger2.otherDescs[TagNumber]["hitKey"] = $(this).val();
  5867. pers.set('sangusettings', JSON.stringify(user_data));
  5868. trackEvent("ScriptUsage", "SettingEdit", "1");
  5869. })
  5870.  
  5871. })();
  5872.  
  5873. // notable contributors
  5874. (function() {
  5875. var notableHtml = "<u>" + trans.sp.sp.donate.notable + "</u>";
  5876. notableHtml += "<br><br><b>sakeb</b>: Nogmaals bedankt voor 'JavaScript: The Good Parts'! :)";
  5877. notableHtml += "<br><b>Daniel Ivanov</b>";
  5878. notableHtml += "<br><br>";
  5879.  
  5880. $("#sanguSettingsForm").append(notableHtml);
  5881. })();
  5882. })();
  5883. }
  5884. break;
  5885.  
  5886. case "place":
  5887. /**
  5888. * {spVillage} The current village
  5889. */
  5890. var vilHome = getVillageFromCoords(game_data.village.coord);
  5891. if ($("#attack_name").size() > 0) {
  5892. // RALLYPOINT CONFIRM
  5893. (function() {
  5894. //console.time("confirm");
  5895. try {
  5896. // reorder the page
  5897. if (user_data.proStyle) {
  5898. $("table:first", content_value).css("width", 500);
  5899.  
  5900. // Merge nightbonus & tribe claim statements (for OK button placement)
  5901. if (user_data.proStyle && (user_data.confirm.replaceTribeClaim || user_data.confirm.replaceNightBonus)) {
  5902. var header = $("h2:first", content_value);
  5903. var claim = $("h3.error:visible");
  5904. if (claim.size() != 0) {
  5905. claim.each(function() {
  5906. var $this = $(this);
  5907. $this.hide();
  5908. header.addClass("error").text(header.text() + " - " + $this.text());
  5909. });
  5910. }
  5911. }
  5912. }
  5913.  
  5914. // extra attack button (always on the same place)
  5915. if (user_data.confirm.addExtraOkButton) {
  5916. $("h2:first", content_value).prepend("<input type=submit style='font-size: 10pt' id=focusPlaceHolder value='" + $("#troop_confirm_go").val() + "'><br>");
  5917. $("#focusPlaceHolder").click(function () {
  5918. $(this).attr("disabled", "disabled");
  5919. $("#troop_confirm_go").click();
  5920. });
  5921. }
  5922.  
  5923. // Catapult building images
  5924. if (user_data.confirm.addCatapultImages && $("#save_default_attack_building").length == 1) {
  5925. var dropdown = $("select[name='building']");
  5926. var buildingImages = "";
  5927.  
  5928. dropdown.find("option").each(function(index, value) {
  5929. buildingImages += "<img class='catapultSwitcher' title='" + trans.sp.command.catapultImageTitle + "' building='" + $(value).val() +"' src='https://www.tribalwars.vodka/graphic/buildings/" + $(value).val() + ".png'> ";
  5930. });
  5931.  
  5932. dropdown.parent().parent().before("<tr><td colspan=4>"+buildingImages+"</td></tr>");
  5933. $("img.catapultSwitcher").click(function() {
  5934. dropdown.val($(this).attr("building"));
  5935. });
  5936. }
  5937.  
  5938. var valueCells = $("table.vis:first td:odd", content_value);
  5939. var targetVillage = valueCells.first().text();
  5940.  
  5941. // remember last attack
  5942. // saved at the confirmation page so that we can't save
  5943. // invalid coordinates
  5944. var village = getVillageFromCoords(targetVillage);
  5945. if (village.isValid) {
  5946. pers.set("lastVil", village.coord);
  5947. }
  5948.  
  5949. var isAttack = $("input[name='attack']").val() == "true";
  5950. var isBarbarian = valueCells.eq(1).has("a").length === 0;
  5951. var player = (isBarbarian ? '' : valueCells.eq(1).text());
  5952.  
  5953. var unitsSent = {};
  5954. $.each(world_data.units, function (i, val) {
  5955. unitsSent[val] = parseInt($("input[name='" + val + "']", content_value).val(), 10);
  5956. });
  5957.  
  5958. // compare runtime with dodgetime
  5959. var unitsCalc = calcTroops(unitsSent);
  5960. var dodgeCookie = pers.getCookie("sanguDodge" + getQueryStringParam("village"));
  5961. if (dodgeCookie) {
  5962. dodgeCookie = dodgeCookie.split("~");
  5963. var durationCell = $("table.vis:first td:contains('" + trans.tw.command.walkingTimeTitle + "')", content_value).next();
  5964. var attackRunTime = getTimeFromTW(durationCell.text());
  5965. var dodgeTime = getTimeFromTW(dodgeCookie[1]);
  5966.  
  5967. var runtimeIsOk = attackRunTime.totalSecs >= dodgeTime.totalSecs;
  5968. var diffSecs = (attackRunTime.totalSecs - dodgeTime.totalSecs);
  5969.  
  5970. var dodgeCellText = "<table border=0 cellpadding=0 cellspacing=0 width='1%'><tr>";
  5971. dodgeCellText += "<td width='25%' align=center>" + durationCell.text() + "</td>";
  5972. dodgeCellText += "<td width='50%' align=center><b>" + (runtimeIsOk ? "&gt;&gt;&gt;" : "&lt;&lt;&lt;") + "</b></td>";
  5973. dodgeCellText += "<td width='25%' align=center nowrap>" + dodgeCookie[1] + "&nbsp;";
  5974. if (diffSecs > 0) {
  5975. dodgeCellText += trans.sp.command.dodgeMinuteReturn.replace("{minutes}", prettyDate(diffSecs * 2000, true)); // 2000 = Method expects milliseconds and distance is walked 2 times!
  5976. }
  5977. dodgeCellText += "</td>";
  5978.  
  5979. dodgeCellText += "</tr></table>";
  5980. durationCell.html(dodgeCellText);
  5981.  
  5982. if (!runtimeIsOk) {
  5983. 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);
  5984. }
  5985.  
  5986. if (dodgeCookie[0] != "unit_" + unitsCalc.getSlowest()) {
  5987. $("h2:first", content_value).css("background-color", user_data.colors.error);
  5988. }
  5989. } else {
  5990. // If a dodgecookie is in use, nightbonus etc isn't relevant
  5991. unitsCalc.colorIfNotRightAttackType($("h2:first", content_value), isAttack);
  5992. var arrivalTime = getDateFromTodayTomorrowTW($.trim($("#date_arrival").text()));
  5993. if (user_data.proStyle && user_data.confirm.replaceNightBonus && isDateInNightBonus(arrivalTime)) {
  5994. $("#date_arrival").css("background-color", user_data.colors.error).css("font-weight", "bold");
  5995. }
  5996. }
  5997.  
  5998. if (user_data.attackAutoRename.active) {
  5999. // rename attack command
  6000. // cookie reading code in place.js
  6001. var villageCoord = $("input[name='x']", content_value).val() + '|' + $("input[name='y']", content_value).val();
  6002. var sent = buildAttackString(villageCoord, unitsSent, player, !isAttack);
  6003. document.title = game_data.village.coord + " -> " + sent;
  6004.  
  6005. var twInitialCommandName = (isAttack ? trans.tw.command.attackOn : trans.tw.command.supportFor) + targetVillage;
  6006. pers.setSession("attRen_" + game_data.village.id + '_' + twInitialCommandName, sent);
  6007. }
  6008. } catch (e) { handleException(e, "place-confirm"); }
  6009. //console.timeEnd("confirm");
  6010. }());
  6011. }
  6012. // RALLYPOINT UNITS THERE
  6013. else if (current_page.mode === 'units' && location.href.indexOf('try=back') == -1) {
  6014. (function() {
  6015. //console.time("units_back");
  6016. try {
  6017. var units_awayTable = $("#units_away").width("100%");
  6018. if (units_awayTable.size() != 0) {
  6019. // Troops in other villages
  6020. $("tr:first", units_awayTable).append(
  6021. "<th>" + trans.sp.place.distance + "</th>"
  6022. + "<th>" + trans.sp.place.backOn + "</th>");
  6023.  
  6024. units_awayTable.find("tr:gt(0):even").each(function() {
  6025. var row = $(this),
  6026. villageCoord = getVillageFromCoords(row.find("td:eq(1)").text());
  6027.  
  6028. if (!villageCoord.isValid) {
  6029. row.append("<th>&nbsp;</th><th>&nbsp;</th>");
  6030. } else {
  6031. var slowestUnit = null;
  6032. var slowestUnitName = null;
  6033. $.each(world_data.units, function (i, val) {
  6034. var amount = $("td:eq(" + (i + 2) + "), th:eq(" + (i + 1) + ")", row).text();
  6035. if (amount != '0') {
  6036. if (slowestUnit == null || slowestUnit < world_data.unitsSpeed['unit_' + val]) {
  6037. slowestUnitName = val;
  6038. slowestUnit = world_data.unitsSpeed['unit_' + val];
  6039. }
  6040. }
  6041. });
  6042.  
  6043. var fields = getDistance(vilHome.x, villageCoord.x, vilHome.y, villageCoord.y, slowestUnitName);
  6044. var extraColumns = "<td align=right>" + parseInt(fields.fields, 10) + "</td>";
  6045. extraColumns += "<td>" + twDateFormat(fields.arrivalTime) + "</td>";
  6046.  
  6047. row.append(extraColumns);
  6048. }
  6049. });
  6050. }
  6051.  
  6052. // Calculate distance and walkingtime to the villages
  6053. var unitsTable = $("form table:first");
  6054. $("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>');
  6055. unitsTable.find("tr:gt(0)").each(function () {
  6056. var pop = 0;
  6057. var row = $(this);
  6058. var slowestUnit = null;
  6059. var slowestUnitName = null;
  6060.  
  6061. $.each(world_data.units, function (i, val) {
  6062. var amount = parseInt($("td:eq(" + (i + 1) + "), th:eq(" + (i + 1) + ")", row).text(), 10);
  6063. if (amount !== 0) {
  6064. pop += amount * world_data.unitsPositionSize[i];
  6065.  
  6066. if (slowestUnit == null || slowestUnit < world_data.unitsSpeed['unit_' + val]) {
  6067. slowestUnitName = val;
  6068. slowestUnit = world_data.unitsSpeed['unit_' + val];
  6069. }
  6070. }
  6071. });
  6072.  
  6073. var villageCoord = getVillageFromCoords(row.find("td:first").text());
  6074. var color = getStackColor(pop);
  6075.  
  6076. if (color !== "") {
  6077. $(this).append("<td align=right style='background-color: " + color + "'>" + formatNumber(pop) + "</td><td colspan=2>&nbsp;</td>");
  6078. } else {
  6079. var extraColumns = '<td align=right>' + formatNumber(pop) + '</td>';
  6080. if (!villageCoord.isValid) {
  6081. extraColumns += "<td colspan=2 align=right>&nbsp;</td>";
  6082. } else {
  6083. //q(vilHome.x + ':' + slowestUnitName);
  6084. var dist = getDistance(vilHome.x, villageCoord.x, vilHome.y, villageCoord.y, slowestUnitName),
  6085. fields = parseInt(dist.fields, 10);
  6086.  
  6087. extraColumns += "<td align=right>" + fields + "</td><td>" + twDateFormat(dist.arrivalTime) + "</td>";
  6088. $("td:first", this).append("&nbsp; <b>" + trans.sp.all.fieldsSuffix.replace("{0}", fields) + "</b>");
  6089. $(this).addClass("toSort").attr("fields", fields);
  6090. }
  6091. $(this).append(extraColumns);
  6092. }
  6093. });
  6094.  
  6095. var checkboxAmount = $("input[type='checkbox']", unitsTable);
  6096. if (checkboxAmount.size() == 1) {
  6097. // village has just been taken over? auto check checkbox
  6098. checkboxAmount.attr("checked", true);
  6099. }
  6100.  
  6101. // Sort on distance
  6102. unitsTable.find("tr.toSort").sortElements(function (a, b) {
  6103. return parseInt($(a).attr("fields"), 10) < parseInt($(b).attr("fields"), 10) ? 1 : -1;
  6104. });
  6105.  
  6106. // are there incomings on the supporting villages?
  6107. if (server_settings.ajaxAllowed) {
  6108. unitsTable.find("tr.toSort").each(function() {
  6109. var row = $(this);
  6110. var villageUrl = $("a:first", this).attr("href");
  6111. ajax(villageUrl, function (villageDetails) {
  6112. var villageOwner = $("table.vis:first tr:eq(4) a", villageDetails);
  6113. if (villageOwner.text() != game_data.player.name) {
  6114. $("td:first a", row).after(" [" + villageOwner.outerHTML() + "]");
  6115. } else {
  6116. var incomingTable = $("table th:contains('" + trans.tw.overview.incomingTroops + "')", villageDetails);
  6117. if (incomingTable.size() > 0) {
  6118. incomingTable = incomingTable.parent().parent();
  6119. var incomingRows = $("tr:has(img[src*='attack'])", incomingTable);
  6120. if (incomingRows.size() > 0) {
  6121. var firstAttack = incomingRows.eq(0);
  6122. var timeLeft = $("td:eq(2)", firstAttack).text();
  6123. var arrivalDate = $("td:eq(1)", firstAttack).text();
  6124.  
  6125. var lastAttack = incomingRows.last();
  6126. var timeLeftLast = $("td:eq(2)", lastAttack).text();
  6127. var arrivalDateLast = $("td:eq(1)", lastAttack).text();
  6128.  
  6129. var amount = incomingRows.size();
  6130.  
  6131. var attacksDesc;
  6132. if (amount == 1) {
  6133. attacksDesc = trans.sp.place.onlyAttack
  6134. .replace("{timeLeftFirst}", timeLeft)
  6135. .replace("{arrivalDateFirst}", arrivalDate);
  6136. } else {
  6137. attacksDesc = trans.sp.place.multipleAttack
  6138. .replace("{timeLeftFirst}", timeLeft)
  6139. .replace("{arrivalDateFirst}", arrivalDate)
  6140. .replace("{timeLeftLast}", timeLeftLast)
  6141. .replace("{arrivalDateLast}", arrivalDateLast)
  6142. .replace("{amount}", amount);
  6143. }
  6144.  
  6145. $("td:first input", row).after("&nbsp; <img src='graphic/command/attack.png' title='" + attacksDesc + "'>");
  6146. }
  6147. }
  6148. }
  6149. });
  6150. });
  6151. }
  6152. } catch (e) { handleException(e, "place-units_back"); }
  6153. //console.timeEnd("units_back");
  6154. }());
  6155. }
  6156. // RALLY POINT (DEFAULT)
  6157. else {
  6158. (function() {
  6159. //console.time("place-place");
  6160. try {
  6161. // Auto rename attacks
  6162. if (user_data.attackAutoRename.active) {
  6163. // Less than ideal solution:
  6164. // Does not work properly when sending many attacks (ie snobtrain)
  6165. // In confirm.js the cookies are saved
  6166.  
  6167. var hasAttackRenamingCookieNeedle = pers.getWorldKey('attRen_' + game_data.village.id + '_');
  6168. for (var i = 0; i < sessionStorage.length; i++) {
  6169. var key = sessionStorage.key(i);
  6170. if (key.indexOf(hasAttackRenamingCookieNeedle) == 0) {
  6171. var twInitialCommandName = key.substr(hasAttackRenamingCookieNeedle.length);
  6172. //q("found:" + hasAttackRenamingCookieNeedle + " -> " + twInitialCommandName);
  6173.  
  6174. // ' is an invalid village name character so we don't need to escape
  6175. var commandLabel = $('.quickedit-label:contains("' + twInitialCommandName + '")');
  6176. if (commandLabel.length > 0 && server_settings.ajaxAllowed) {
  6177. var sanguCommandName = sessionStorage.getItem(key);
  6178.  
  6179. // Open the rename command form:
  6180. commandLabel.parent().next().click();
  6181.  
  6182. // Fill in new command name and click rename button
  6183. var commandWrapper = commandLabel.parent().parent().parent(),
  6184. commandForm = commandWrapper.find(".quickedit-edit");
  6185.  
  6186. commandForm.find("input:first").val(sanguCommandName);
  6187. commandForm.find("input:last").click();
  6188.  
  6189. pers.removeSessionItem(key);
  6190.  
  6191. if (commandLabel.closest("table").find("tr").length > 2) {
  6192. commandLabel.closest("td").addClass("selected");
  6193. }
  6194. }
  6195. }
  6196. }
  6197. }
  6198.  
  6199. $("#inputx,#inputy").focus(function() {
  6200. $(this).select();
  6201. });
  6202.  
  6203. // fill in coordinates? (links from troops overview page)
  6204. if (server_settings.autoFillCoordinatesAllowed && window.location.search.indexOf("&sanguX=") != -1) {
  6205. var match = window.location.search.match(/sanguX=(\d+)&sanguY=(\d+)/);
  6206. if (typeof match[1] !== "undefined") {
  6207. $("#inputx").val(match[1]);
  6208. $("#inputy").val(match[2]);
  6209. }
  6210. }
  6211.  
  6212. // Spice up rally point:
  6213. var speedCookie = spSpeedCookie();
  6214.  
  6215. (function() {
  6216. try {
  6217.  
  6218. // Show current selected speed + ability to change active speed
  6219. $(".unit_link img", content_value).each(function() {
  6220. $(this).attr("title", trans.sp.place.changeSpeedImageTooltips.replace("{originalTitle}", $(this).attr("title")));
  6221. });
  6222.  
  6223. $("#command-data-form a img").click(function () {
  6224. var unit = this.src;
  6225. unit = unit.substr(unit.lastIndexOf('/') + 1);
  6226. unit = unit.substr(0, unit.lastIndexOf('.'));
  6227. speedCookie = spSpeedCookie(unit);
  6228. $("#command-data-form a img").css("border", "0px").filter("img[src*='" + unit + "']").css("border", "3px red solid");
  6229.  
  6230. // lastvil
  6231. var coord = getVillageFromCoords(pers.get("lastVil"));
  6232. if (coord.isValid) {
  6233. var dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, speedCookie);
  6234. $("#lastVilTime")[0].innerHTML = dist.html;
  6235. }
  6236.  
  6237. // targetVillage
  6238. coord = getVillageFromCoords(spTargetVillageCookie());
  6239. if (coord.isValid) {
  6240. dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, speedCookie);
  6241. $("#targetVilTime")[0].innerHTML = dist.html;
  6242. }
  6243.  
  6244. }).filter("img[src*='" + speedCookie + "']").css("border", "3px red solid");
  6245.  
  6246. } catch (e) { handleException(e, "place-activespeed"); }
  6247. }());
  6248. (function() {
  6249. try {
  6250. // sangupackage last village
  6251. var cookie = pers.get("lastVil"),
  6252. coord = getVillageFromCoords(cookie),
  6253. dist;
  6254.  
  6255. if (coord.isValid) {
  6256. dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, speedCookie);
  6257. var htmlStr = printCoord(coord, "&raquo; " + trans.sp.all.last + ": " + coord.x + "|" + coord.y);
  6258. htmlStr += " &nbsp; <span id=lastVilTime>" + dist.html + "</span>";
  6259. $("#command-data-form").append(htmlStr);
  6260. }
  6261.  
  6262. // Add target village
  6263. var targetVillage = getVillageFromCoords(spTargetVillageCookie());
  6264. if (targetVillage.isValid) {
  6265. dist = getDistance(targetVillage.x, vilHome.x, targetVillage.y, vilHome.y, speedCookie);
  6266. $("#command-data-form").append("<br>" + printCoord(targetVillage, "&raquo; " + trans.sp.all.target + ": " + targetVillage.x + "|" + targetVillage.y) + " &nbsp;<span id=targetVilTime>" + dist.html + "</span>");
  6267. }
  6268. } catch (e) { handleException(e, "place-lastandtargetvillage"); }
  6269. }());
  6270. (function() {
  6271. try {
  6272. // Read troops available
  6273. var units = [];
  6274. units.total = 0;
  6275. $("#command-data-form .unitsInput").each(function () {
  6276. var amount = $(this).next().text().substr(1);
  6277. units[this.name] = parseInt(amount.replace(")", ""), 10);
  6278. units.total += units[this.name] * world_data.unitsSize['unit_'+this.name];
  6279. });
  6280.  
  6281. // Add extra links next to "All troops"
  6282. function createRallyPointScript(linksContainer, unitLoop, name, min, checkFunction, tag) {
  6283. send = {};
  6284. $.each(unitLoop, function (i, v) {
  6285. if (units[v] >= min) {
  6286. send[v] = checkFunction(units[v], v, tag);
  6287. }
  6288. });
  6289. linksContainer.append("&nbsp; &nbsp;<a href='#' onclick='" + fillRallyPoint(send) + "; return false'>" + name + "</a>");
  6290. }
  6291.  
  6292. var villageType = calcTroops(units);
  6293. var linksContainer = $('#selectAllUnits').parent().attr("colspan", 4);
  6294.  
  6295. // add fake attack
  6296. var minFake = 0;
  6297. if (world_config.hasMinFakeLimit) {
  6298. minFake = getBuildingPoints();
  6299. minFake *= world_config.minFake;
  6300. if (units.ram > 0) {
  6301. minFake -= world_data.unitsSize['unit_ram'];
  6302. }
  6303. }
  6304.  
  6305. if (user_data.place.attackLinks.fakePlaceLink && units['total'] >= minFake) {
  6306. createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.fakePlaceLinkName, 0, function (amount, v, tag) {
  6307. if ((v == 'ram' || v == 'catapult') && !tag.rammed && amount > 0) {
  6308. tag.rammed = true;
  6309. return 1;
  6310. }
  6311.  
  6312. if (v == 'snob' || tag.toSend <= 0 || amount == 0) {
  6313. return 0;
  6314. }
  6315.  
  6316. if (user_data.place.attackLinks.fakePlaceExcludeTroops.indexOf(v) > -1) {
  6317. return 0;
  6318. }
  6319.  
  6320. var farmSize = world_data.unitsSize['unit_' + v];
  6321. if (amount * farmSize > tag.toSend) {
  6322. amount = Math.ceil(tag.toSend / farmSize);
  6323. }
  6324. tag.toSend -= amount * farmSize;
  6325. if (v == 'sword' && amount > 0) {
  6326. tag.toSend++;
  6327. amount--;
  6328. }
  6329.  
  6330. return amount;
  6331. }, { toSend: minFake, rammed: false });
  6332. }
  6333.  
  6334. if (units['total'] > 0)
  6335. $.each(user_data.place.customPlaceLinks, function (i, v) {
  6336. if (v.active && villageType.isMatch(v.type)) {
  6337. // villageType: off, def, all
  6338. if (v.required == undefined || units[v.required[0]] >= v.required[1]) {
  6339. // requires certain amount of troops
  6340. if (v.totalPop == undefined) {
  6341. // work with absolute numbers
  6342. createRallyPointScript(linksContainer, world_data.units, v.name, 0, function (amount, unitVal, tag) {
  6343. //q(v + ' - SEND:' + tag[v] + '; amount=' + amount + ';');
  6344. var send = tag[unitVal];
  6345. if (send != undefined && amount > 0) {
  6346. //q("send: " + send + " // amount: " + amount + " // unitVal: " + unitVal);
  6347. if (send < 0) {
  6348. send = amount + send;
  6349. if (send < 0) {
  6350. send = 1;
  6351. }
  6352. }
  6353. if ((amount - send) * world_data.unitsSize['unit_' + unitVal] < tag.sendAlong) {
  6354. send = amount;
  6355. }
  6356. if (send > 0 && !tag.ignoreNobles) {
  6357. $.each(user_data.place.attackLinks.nobleSupport, function (i, val) {
  6358. if (unitVal == val.unit && villageType.isMatch(val.villageType)) {
  6359. send -= Math.ceil(units.snob * val.amount);
  6360. }
  6361. });
  6362. }
  6363. //if (unitVal == 'light') q(send);
  6364.  
  6365. if (send > amount) {
  6366. return amount;
  6367. }
  6368. if (send > 0) {
  6369. return send;
  6370. }
  6371. }
  6372. return 0;
  6373. }, v);
  6374.  
  6375. } else { // do automatic calculation which division of troops to select
  6376. ////{ active: true, type: 'def', name: 'HelftZc', totalPop: 10000, divideOver: ['spear', 'heavy'] },
  6377. // TODO this doesn't yet work, does it?
  6378. // Probably not active...
  6379. var totalPop = 0;
  6380. $.each(v.divideOver, function (i, val) { totalPop += units[val] * world_data.unitsSize['unit_' + val]; });
  6381.  
  6382. createRallyPointScript(linksContainer, world_data.units, v.name, 0, function (amount, unitVal, tag) {
  6383. if ($.inArray(unitVal, tag.divideOver) == -1) {
  6384. return 0;
  6385. }
  6386. if (totalPop < tag.totalPop) {
  6387. return amount;
  6388. }
  6389.  
  6390. var currentUnitPercentage = (amount * world_data.unitsSize['unit_' + unitVal]) / totalPop;
  6391. return Math.floor(amount * currentUnitPercentage);
  6392. }, v);
  6393. }
  6394. }
  6395. }
  6396. });
  6397.  
  6398. if (units.spy >= user_data.place.attackLinks.scoutVillage && user_data.place.attackLinks.scoutPlaceLinks != null && user_data.place.attackLinks.scoutPlaceLinks.length > 0) {
  6399. $.each(user_data.place.attackLinks.scoutPlaceLinks, function (i, v) {
  6400. if (units.spy >= v) {
  6401. createRallyPointScript(linksContainer, ["spy"], user_data.place.attackLinks.scoutPlaceLinksName.replace("{amount}", v), 0, function (amount, v, tag) {
  6402. return tag;
  6403. }, v);
  6404. }
  6405. });
  6406. }
  6407.  
  6408. if (units.snob > 0 && user_data.place.attackLinks.noblePlaceLink) {
  6409. if (user_data.place.attackLinks.noblePlaceLinkFirstName) {
  6410. createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.noblePlaceLinkFirstName, 0, function (amount, v, tag) {
  6411. if (v == 'snob') {
  6412. return 1;
  6413. }
  6414. if (tag > 0) {
  6415. var returned = null;
  6416. $.each(user_data.place.attackLinks.nobleSupport, function (i, val) {
  6417. if (v == val.unit && villageType.isMatch(val.villageType)) {
  6418. returned = amount - Math.ceil((tag - 1) * val.amount);
  6419. }
  6420. });
  6421. if (returned != null) {
  6422. return returned;
  6423. }
  6424. }
  6425. return amount;
  6426. }, units.snob);
  6427. }
  6428.  
  6429. if (user_data.place.attackLinks.noblePlaceLinkSupportName && (units.snob > 1 || user_data.place.attackLinks.noblePlaceLinksForceShow)) {
  6430. createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.noblePlaceLinkSupportName, 0, function (amount, v, tag) {
  6431. if (v == 'snob') {
  6432. return 1;
  6433. }
  6434. var returned = 0;
  6435. $.each(user_data.place.attackLinks.nobleSupport, function (i, val) {
  6436. if (v == val.unit && villageType.isMatch(val.villageType)) {
  6437. returned = Math.ceil(1 * val.amount);
  6438. }
  6439. });
  6440. return returned;
  6441. });
  6442. }
  6443.  
  6444. if (units.snob > 0 && user_data.place.attackLinks.noblePlaceLinkDivideName) {
  6445. createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.noblePlaceLinkDivideName, 0, function (amount, v, tag) {
  6446. if (v == 'snob') {
  6447. return 1;
  6448. }
  6449. if (v == 'catapult') {
  6450. return 0;
  6451. }
  6452. if (v == 'ram' && !user_data.place.attackLinks.noblePlaceLinkDivideAddRam) {
  6453. return 0;
  6454. }
  6455. return Math.floor(amount / units.snob);
  6456. });
  6457. }
  6458. }
  6459. } catch (e) { handleException(e, "place-extratrooplinks"); }
  6460. }());
  6461.  
  6462. } catch (e) { handleException(e, "place-place"); }
  6463. //console.timeEnd("place-place");
  6464. }());
  6465. }
  6466. break;
  6467.  
  6468. case "overview_villages":
  6469. break;
  6470. }
  6471.  
  6472. // USERPROFIEL++ // INFO_ ALLY/PLAYER
  6473. if ((current_page.screen === 'info_ally' || current_page.screen === 'info_player' || current_page.screen === 'info_village')
  6474. || (current_page.screen === "ally" && current_page.mode === "profile")) {
  6475.  
  6476. (function() {
  6477. try {
  6478. var tables = $('table.vis', content_value),
  6479. villageInfoTable = tables.first(),
  6480. commandsTable = villageInfoTable.next('table'),
  6481. profile = user_data.profile,
  6482. i;
  6483.  
  6484. if (game_data.features.Premium.active && location.href.indexOf('screen=info_village') > -1) {
  6485. // extra links on the village overview page
  6486. var createFilterLink = function(baseLink, settings) {
  6487. var link = baseLink + "&group=" + settings.group + "&sort=" + settings.sort + "&changeSpeed=" + settings.changeSpeed;
  6488.  
  6489. if (settings.filter.active) {
  6490. link += "&unit=" + settings.filter.unit + "&amount=" + settings.filter.amount;
  6491. }
  6492.  
  6493. var fancyIcon = settings.icon ? "<img src='" + settings.icon + "'>" : "";
  6494. return "<a href='" + link + "'>" + fancyIcon + settings.name + "</a>";
  6495. };
  6496.  
  6497. for (i = 0; i < user_data.villageInfo4.length; i++) {
  6498. var currentPairInfo = user_data.villageInfo4[i];
  6499. if (currentPairInfo.active) {
  6500. var id = villageInfoTable.find("td:eq(2)").text(),
  6501. link = getUrlString(
  6502. "&screen=overview_villages&type=own_home&mode=units&page=-1&targetvillage="
  6503. + id.substr(id.lastIndexOf("=") + 1));
  6504.  
  6505. commandsTable.find("tbody:first").append(
  6506. "<tr><td>" + createFilterLink(link, currentPairInfo.off_link) + "</td>"
  6507. + "<td>" + createFilterLink(link, currentPairInfo.def_link) + "</td><tr>");
  6508. }
  6509. }
  6510. }
  6511.  
  6512. if (user_data.profile.show && (location.href.indexOf('screen=info_village') == -1 || user_data.showPlayerProfileOnVillage)) {
  6513. var screen;
  6514. var mapProfile = user_data.profile.mapLink;
  6515. var isVillage = false;
  6516. if (current_page.screen !== 'info_ally' && current_page.screen !== "ally") {
  6517. // player and village info page
  6518. // Extra links and info in table at the left top
  6519. screen = "player";
  6520. if (user_data.proStyle) {
  6521. $("td:first", content_value).closest('table').hasClass('modemenu')
  6522. ? $(content_value).find('table:has("#villages_list") td:first').css("width", "40%").next().css("width", "60%")
  6523. : $("td:first", content_value).css("width", "40%").next().css("width", "60%");
  6524. }
  6525.  
  6526. if (current_page.screen === 'info_player') {
  6527. // player info page
  6528. id = commandsTable.find("a[href*='screen=mail']").attr("href");
  6529.  
  6530. if (id == undefined) {
  6531. id = game_data.player.id;
  6532. } else {
  6533. id = id.substr(id.indexOf("&player=") + 8);
  6534. //alert(id);
  6535. if (id.indexOf("&") > -1) {
  6536. id = id.substr(0, id.indexOf("&"));
  6537. }
  6538. }
  6539. } else {
  6540. // village info page
  6541. isVillage = true;
  6542. commandsTable = $("table.vis:first", content_value);
  6543. id = commandsTable.find("tr:eq(3) a");
  6544. //assert(id.size() == 1, "player id not found on info_village page");
  6545. if (id.size() > 0) {
  6546. id = id.attr("href").match(/id=(\d+)/)[1];
  6547. assert(!!id, "player id href is not set");
  6548. } else {
  6549. id = 0;
  6550. }
  6551. }
  6552.  
  6553. // Direct link to TW Stats map
  6554. if (id > 0 && profile.mapLink.show) {
  6555. var link = "https://" + game_data.market + ".twstats.com/" + game_data.world + "/index.php?page=map";
  6556. var tribeId = commandsTable.prev('table').find("td:eq(8) a");
  6557. //assert(tribeId.size() == 1, "tribe id not found"); // Not everyone is in a tribe
  6558. if (tribeId.size() == 1) {
  6559. tribeId = tribeId.attr("href").match(/id=(\d+)/)[1];
  6560. assert(!isNaN(tribeId), "tribe id is not a number");
  6561. } else tribeId = 0;
  6562.  
  6563. if (mapProfile.tribeColor != null) {
  6564. link += "&tribe_0_id=" + tribeId + "&tribe_0_colour=" + mapProfile.tribeColor.substr(1);
  6565. }
  6566. if (mapProfile.yourTribeColor != null && game_data.player.ally_id != tribeId && game_data.player.ally_id > 0) {
  6567. link += "&tribe_1_id=" + game_data.player.ally_id + "&tribe_1_colour=" + mapProfile.yourTribeColor.substr(1);
  6568. }
  6569. link += "&player_0_id=" + id + "&player_0_colour=" + mapProfile.playerColor.substr(1);
  6570. link += "&grid=" + (mapProfile.grid ? 1 : 0) + "&fill=" + mapProfile.fill.substr(1) + "&zoom=" + mapProfile.zoom + "&centrex=" + mapProfile.centreX + "&centrey=" + mapProfile.centreY;
  6571. if (mapProfile.markedOnly) {
  6572. link += "&nocache=1";
  6573. }
  6574. if (mapProfile.bigMarkers) {
  6575. link += "&bm=1";
  6576. }
  6577. if (mapProfile.gridContinentNumbers) {
  6578. link += "&kn=1";
  6579. }
  6580. if (mapProfile.ownColor != null && game_data.player.id != id) {
  6581. link += "&player_1_id=" + game_data.player.id + "&player_1_colour=" + mapProfile.ownColor.substr(1);
  6582. }
  6583. commandsTable.find("tr:last").after("<tr><td colspan=2><a href='" + link + "' target='_blank'>&raquo; " + trans.sp.profile.twStatsMap + "</a> " + trans.sp.profile.externalPage + "</td></tr>");
  6584. }
  6585.  
  6586. if (!isVillage) {
  6587. // Amount of villages
  6588. if (user_data.proStyle) {
  6589. // always show villagename on one line
  6590. var colWidth = $("table:eq(2) th", content_value);
  6591. colWidth.first().css("width", "98%");
  6592. colWidth.eq(1).css("width", "1%");
  6593. colWidth.eq(2).css("width", "1%");
  6594. }
  6595.  
  6596. var amountOfVillages = tables.eq(2).find("th:first").text();
  6597. amountOfVillages = amountOfVillages.substr(amountOfVillages.indexOf("(") + 1);
  6598. amountOfVillages = amountOfVillages.substr(0, amountOfVillages.length - 1);
  6599. commandsTable.prev('table').find("tr:eq(2)").after("<tr><td>" + trans.sp.profile.villages + "</td><td>" + formatNumber(amountOfVillages) + "</td></tr>");
  6600. }
  6601. } else {
  6602. screen = "tribe";
  6603. if (current_page.screen === 'info_ally') {
  6604. commandsTable = tables.eq(0);
  6605. }
  6606. id = commandsTable.find("a");
  6607. id = id.last().attr("href").match(/&id=(\d+)/)[1];
  6608.  
  6609. var link = "https://" + game_data.market + ".twstats.com/" + game_data.world + "/index.php?page=map";
  6610. link += "&tribe_0_id=" + id + "&tribe_0_colour=" + mapProfile.tribeColor.substr(1);
  6611. link += "&centrex=" + mapProfile.centreX + "&centrey=" + mapProfile.centreY;
  6612. if (mapProfile.yourTribeColor != null && game_data.player.ally_id != id) {
  6613. link += "&tribe_1_id=" + game_data.player.ally_id + "&tribe_1_colour=" + mapProfile.yourTribeColor.substr(1);
  6614. }
  6615. link += "&grid=" + (mapProfile.grid ? 1 : 0) + "&fill=" + mapProfile.fill.substr(1) + "&zoom=" + mapProfile.zoom
  6616. if (mapProfile.markedOnly) {
  6617. link += "&nocache=1";
  6618. }
  6619. if (mapProfile.bigMarkers) {
  6620. link += "&bm=1";
  6621. }
  6622. if (mapProfile.gridContinentNumbers) {
  6623. link += "&kn=1";
  6624. }
  6625. if (mapProfile.ownColor != null) {
  6626. link += "&player_0_id=" + game_data.player.id + "&player_0_colour=" + mapProfile.ownColor.substr(1);
  6627. }
  6628. commandsTable.find("tr:last").before("<tr><td colspan=2><a href='" + link + "' target='_blank'>&raquo; " + trans.sp.profile.twStatsMap + "</a> " + trans.sp.profile.externalPage + "</td></tr>");
  6629. }
  6630.  
  6631. // Build graphs
  6632. if (id > 0) {
  6633. var html = "";
  6634.  
  6635. // TWMap graphs
  6636. var twMapGraphs;
  6637. if (screen == "tribe") {
  6638. twMapGraphs = [["tribe", trans.sp.profile.graphTWMap], ["p_tribe", trans.sp.profile.graphPoints], ["oda_tribe", trans.sp.profile.graphODA], ["odd_tribe", trans.sp.profile.graphODD]];
  6639. } else {
  6640. 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]];
  6641. }
  6642. for (var i = 0; i < twMapGraphs.length; i++) {
  6643. var graphDetails = screen == "tribe" ? profile.twMapTribeGraph[twMapGraphs[i][0]] : profile.twMapPlayerGraph[twMapGraphs[i][0]];
  6644. if (graphDetails[0]) {
  6645. 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]);
  6646. }
  6647. }
  6648.  
  6649. // TWStats graphs
  6650. 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]];
  6651. if (screen == "tribe") {
  6652. graphs.push(["members", trans.sp.profile.graphMembers]);
  6653. }
  6654. var toShow = screen == "tribe" ? profile.tribeGraph : profile.playerGraph;
  6655. for (var i = 0; i < graphs.length; i++) {
  6656. if (toShow[i][1]) {
  6657. var graphType = toShow[i][1] == 'big' ? 'ss' : '';
  6658. 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);
  6659. }
  6660. }
  6661.  
  6662. // Show graphs
  6663. if (html.length > 0) {
  6664. var pictureTable;
  6665. if (screen == 'player' || (isVillage && user_data.showPlayerProfileOnVillage)) {
  6666. pictureTable = $(content_value).find('table:has("th:first:contains(Profiel)")'); // TODO: untranslated resource Profiel
  6667. if (isVillage || pictureTable.html() == null) {
  6668. // With no info nor personal text
  6669. pictureTable = $("<table class='vis' width='100%'><tr><th colspan='2'>" + trans.tw.profile.title + "</th></tr></table>");
  6670. $("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);
  6671. } else if (pictureTable.find("th").text() != trans.tw.profile.title) {
  6672. // TODO: There is a ; after the IF, is that the intention???
  6673. if (pictureTable.find("th:first").text() == trans.tw.profile.awardsWon);
  6674. pictureTable = pictureTable.parent();
  6675.  
  6676. // If there is only the node "Personal info"
  6677. var temp = $("<table class='vis' width='100%'><tr><th colspan='2'>" + trans.tw.profile.title + "</th></tr></table>");
  6678. pictureTable.prepend(temp);
  6679. pictureTable = temp;
  6680. }
  6681.  
  6682. if (pictureTable.find("td[colspan=2]").size() > 0) {
  6683. pictureTable.find("tr:last").before("<tr><td colspan=2>" + html + "</td></tr>");
  6684. } else {
  6685. pictureTable.find("tr:last").after("<tr><td colspan=2>" + html + "</td></tr>");
  6686. }
  6687. } else {
  6688. commandsTable.after("<table class=vis width='100%'><tr><th>" + trans.tw.profile.title + "</th></tr><tr><td>" + html + "</td></tr></table>");
  6689. }
  6690. }
  6691. }
  6692.  
  6693. // Conquers (intern)
  6694. if (id > 0 && profile.popup.show) {
  6695. 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=';
  6696. var conquers = "<tr><td colspan=2><a href=\"\" id='conquers'>&raquo; " + trans.sp.profile.conquers + "</a> " + trans.sp.profile.internalPage + "</td></tr>";
  6697. if (screen == 'tribe') {
  6698. commandsTable.find("tr:last").before(conquers);
  6699. } else {
  6700. commandsTable.find("tr:last").after(conquers);
  6701. }
  6702. var popupWidth = profile.popup.width;
  6703. var popupHeight = profile.popup.height;
  6704. commandsTable.after('<div class="messagepop pop" id="popup" style="display: none"><iframe src=' + twLink + ' width=' + popupWidth + ' height=' + popupHeight + '></div>');
  6705. $("#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" });
  6706.  
  6707. $(function () {
  6708. $("#conquers").on('click', function (event) {
  6709. if ($(this).hasClass('selected')) {
  6710. $("#conquers").removeClass("selected");
  6711. } else {
  6712. $(this).addClass("selected");
  6713. }
  6714. $("#popup").toggle();
  6715. return false;
  6716. });
  6717.  
  6718. $("#popup").on('click', function () {
  6719. $("#popup").hide();
  6720. $("#conquers").removeClass("selected");
  6721. return false;
  6722. });
  6723. });
  6724. }
  6725. }
  6726.  
  6727. if (current_page.screen === 'info_village' && user_data.proStyle && profile.moveClaim) {
  6728. // move claim to a position that does not interfere with more important links (2-click behavior)
  6729. if ($("td:eq(8)", commandsTable).text() == trans.tw.profile.claimedBy) {
  6730. commandsTable.append($("tr:eq(5),tr:eq(6)", commandsTable));
  6731. }
  6732. }
  6733. } catch (e) { handleException(e, "info_villageplayertribe"); }
  6734. }());
  6735. }
  6736. if (current_page.screen === 'info_village') {
  6737. //Written by hardcode
  6738. (function() {
  6739. var show = true;
  6740. var head = $(".vis:contains('Aankomend')", content_value).find("tr:first");
  6741. var text = $("th:contains('Aankomst:')", content_value).html('Aankomend: <img src="https://www.tribalwars.vodka/graphic/minus.png" style=" float: right;">');
  6742.  
  6743. head.on("click", function () {
  6744. if(show === true) {
  6745. $(".no_ignored_command").hide();
  6746. text.html('Verborgen: <img src="https://www.tribalwars.vodka/graphic/plus.png" style=" float: right;">');
  6747. show = false;
  6748. }else{
  6749. $(".no_ignored_command").show();
  6750. text.html('Aankomend: <img src="https://www.tribalwars.vodka/graphic/minus.png" style=" float: right;">');
  6751. show = true;
  6752. }
  6753. });
  6754. }());
  6755. }
  6756.  
  6757. // ALL OVERVIEW PAGES
  6758. if (current_page.screen === 'overview_villages') {
  6759. var overviewTable;
  6760. //tableHandler.overviewTable
  6761.  
  6762. var tableHandler;
  6763. (function (tableHandler) {
  6764. function init(id, options) {
  6765. tableHandler.overviewTableName = id;
  6766. tableHandler.overviewTable = $("#" + id);
  6767. tableHandler.settings = {
  6768. hasBottomTotalRow: false
  6769.  
  6770. };
  6771. tableHandler.settings = $.extend({}, tableHandler.settings, options || {});
  6772.  
  6773. // do stuff on page load
  6774. ajaxLoadNextPageSetup();
  6775. }
  6776. tableHandler.init = init;
  6777.  
  6778. function getReplacedVillageRows(page) {
  6779. var overviewTable = typeof page === 'undefined' ? tableHandler.overviewTable : $("#"+tableHandler.overviewTableName, page);
  6780. if (typeof tableHandler.settings.rowReplacer === "function") {
  6781. var newTable = "";
  6782. var villageRows = selectVillageRows(overviewTable);
  6783. villageRows.each(function () {
  6784. var row = $(this);
  6785. newTable += tableHandler.settings.rowReplacer(row);
  6786. });
  6787. return newTable;
  6788. } else {
  6789. return selectVillageRows(overviewTable);
  6790. }
  6791. }
  6792. tableHandler.getReplacedVillageRows = getReplacedVillageRows;
  6793.  
  6794. function selectVillageRows(page) {
  6795. //q(tableHandler.overviewTableName);
  6796. //q("grrrr:"+page.find("tr").not(":first").length);
  6797. var villageRows = page.find("tr").not(":first");
  6798. if (tableHandler.settings.hasBottomTotalRow) {
  6799. villageRows = villageRows.not(":last");
  6800. }
  6801. //q(villageRows);
  6802. return villageRows;
  6803. }
  6804.  
  6805. function ajaxLoadNextPageSetup() {
  6806. if (server_settings.ajaxAllowed) {
  6807. var nextPageLink = $("#paged_view_content a.paged-nav-item").first();
  6808. if (nextPageLink.length !== 0) {
  6809. // find all pages we can still add to the current table
  6810. var currentPageLabel = nextPageLink.parent().find("strong");
  6811. var nextPageLinks = [];
  6812. currentPageLabel = currentPageLabel.next();
  6813. while (currentPageLabel.text().match(/\d/)) {
  6814. nextPageLinks.push(currentPageLabel);
  6815. currentPageLabel = currentPageLabel.next();
  6816. }
  6817.  
  6818. if (nextPageLinks.length > 0) {
  6819. nextPageLink.parent().append("&nbsp; <a href=# id=loadNextPage>"+trans.sp.overviews.loadNextPage+"</a>");
  6820.  
  6821. $("#loadNextPage").click(function() {
  6822. // Get next page or remove link
  6823. var nextPageUrl = nextPageLinks[0];
  6824. if (nextPageLinks.length == 1) {
  6825. $(this).replaceWith("<strong>"+trans.sp.overviews.loadNextPage+"</strong>");
  6826. }
  6827. nextPageLinks.shift();
  6828.  
  6829. // Fetch and insert next page
  6830. ajax(nextPageUrl.attr("href"), function (page) {
  6831. var nextPageRows = getReplacedVillageRows($(page));
  6832. if (tableHandler.settings.hasBottomTotalRow) {
  6833. tableHandler.overviewTable.find("tr:last").before(nextPageRows);
  6834. } else {
  6835. tableHandler.overviewTable.append(nextPageRows);
  6836. }
  6837.  
  6838. nextPageUrl.replaceWith("<strong>"+nextPageUrl.text()+"</strong>");
  6839. });
  6840. });
  6841. }
  6842. }
  6843. }
  6844. }
  6845. })(tableHandler || (tableHandler = {}));
  6846.  
  6847. // PRODUCTION OVERVIEW
  6848. if (location.href.indexOf('mode=prod') > -1) {
  6849. (function() {
  6850. //console.time("overview-prod");
  6851. try {
  6852. overviewTable = $("#production_table");
  6853. tableHandler.init("production_table");
  6854.  
  6855. // Filter full storage rooms
  6856. var resTable = $("#production_table");
  6857. var menu = "<table class='vis' width='100%'>";
  6858. menu += "<tr><th width='99%'>";
  6859. menu += " <input type=checkbox id=resFilter " + (user_data.resources.filterRows ? "checked" : "") + "> " + trans.sp.prodOverview.filter + " ";
  6860. menu += "&nbsp;<input type=button id=resStorageFull value='" + trans.sp.prodOverview.filterFullGS + "' title=''>&nbsp; &nbsp; ";
  6861. menu += "<select id=resAmountType><option value=1>" + trans.sp.all.more + "</option>";
  6862. menu += "<option value=-1>" + trans.sp.all.less + "</option></select>";
  6863. menu += "<input type=text id=resAmount size=6 value=" + user_data.resources.requiredResDefault + ">";
  6864. 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>";
  6865. menu += " " + trans.sp.all.withText + " <input type=checkbox id=resMerchant " + (user_data.resources.filterMerchants ? "checked" : "") + " title='" + trans.sp.prodOverview.merchantTooltip + "'>";
  6866. menu += "<input type=text id=resMerchantAmount size=2 value=" + user_data.resources.requiredMerchants + " title='" + trans.sp.prodOverview.merchantAmountTooltip + "'> " + trans.sp.all.merchants + " ";
  6867.  
  6868. menu += "</th><th width='1%' nowrap>";
  6869. menu += "<input type=button id=resBBCode value='" + trans.sp.prodOverview.bbCodes + "'> "
  6870. + "<input type=checkbox id=resBBCodeImages> " + trans.sp.prodOverview.bbCodesInfo + "&nbsp; ";
  6871. menu += "</th></tr></table>";
  6872. resTable.before(menu);
  6873.  
  6874. $("#resFilter").change(function () {
  6875. var isCheck = $(this).is(":checked");
  6876. $("#resFilter").attr("title", isCheck ? trans.sp.prodOverview.filterTooltip : trans.sp.prodOverview.filterTooltipReverse);
  6877. $("#resStorageFull").attr("title", isCheck ? trans.sp.prodOverview.filterFullGSTooltip : trans.sp.prodOverview.filterFullGSTooltipReverse);
  6878. $(".resFilter").each(function (index, value) {
  6879. if (index == 3) {
  6880. $(value).attr("title", isCheck ? trans.sp.prodOverview.filterAllTooltip : trans.sp.prodOverview.filterAllTooltipReverse);
  6881. } else {
  6882. $(value).attr("title", isCheck ? trans.sp.prodOverview.filter1Tooltip.replace("{0}", $(value).attr("value")) : trans.sp.prodOverview.filter1TooltipReverse.replace("{0}", $(value).attr("value")));
  6883. }
  6884. });
  6885. });
  6886.  
  6887. $("#resFilter").change();
  6888.  
  6889. $("#resStorageFull").click(function () {
  6890. trackClickEvent("FilterFullRes");
  6891. filterRes('full', $("#resFilter").is(":checked"));
  6892. });
  6893.  
  6894. $("#resBBCode").click(function () {
  6895. trackClickEvent("BBCodeOutput");
  6896. var bbs = filterRes("bbcode", false),
  6897. reverse = $("#resAmountType").val() == "-1",
  6898. bbCodesTitle = reverse ? trans.sp.prodOverview.tooLittleText : trans.sp.prodOverview.tooMuchText;
  6899.  
  6900. bbCodesTitle = bbCodesTitle
  6901. .replace("{diff}", parseInt(user_data.resources.bbcodeMinimumDiff / 1000, 10))
  6902. .replace("{min}", parseInt(parseInt($("#resAmount").val(), 10) / 1000, 10));
  6903.  
  6904. if ($("#textsArea").size() == 0) {
  6905. $(this).parent().parent().parent().append("<tr><td colspan=2 id=textsArea></td></tr>");
  6906. } else {
  6907. $("#textsArea").html("");
  6908. }
  6909.  
  6910. $("#textsArea").append("<b>" + bbCodesTitle + "</b>" + trans.sp.prodOverview.bbCodeExtraInfo + "<br><textarea id=bbcodeArea cols=50 rows=10 wrap=off>");
  6911. $("#bbcodeArea").val(bbs);
  6912.  
  6913. $("#textsArea").append("<br><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>");
  6914. $("#closeTextsArea").click(function() {
  6915. $("#textsArea").parent().remove();
  6916. });
  6917. });
  6918.  
  6919. function filterRes(resourceIndex, hideRows) {
  6920. var resCode = [trans.tw.all.wood, trans.tw.all.stone, trans.tw.all.iron];
  6921. var bbcodes = '';
  6922. var goners = $();
  6923. var stayers = $();
  6924. var filterMerchants = $("#resMerchant").is(":checked");
  6925. var filterMerchantsAmount = parseInt($("#resMerchantAmount").val(), 10);
  6926. var minAmount = parseInt($("#resAmount").val(), 10);
  6927. var reverse = $("#resAmountType").val() == "-1";
  6928. var bbCodeImages = $("#resBBCodeImages").is(":checked");
  6929. var minDif = user_data.resources.bbcodeMinimumDiff;
  6930. var bbCodesTitle;
  6931.  
  6932. if (reverse) {
  6933. bbcodes = trans.sp.prodOverview.tooLittle + "\n";
  6934. bbCodesTitle = trans.sp.prodOverview.tooLittleText;
  6935. } else {
  6936. bbcodes = trans.sp.prodOverview.tooMuch + "\n";
  6937. bbCodesTitle = trans.sp.prodOverview.tooMuchText;
  6938. }
  6939. bbCodesTitle = bbCodesTitle.replace("{min}", minDif).replace("{diff}", minAmount);
  6940.  
  6941. function doResource(resCell, resArray, resIndex, reverse, minAmount) {
  6942. var resAmount = parseInt(resArray[resIndex], 10);
  6943. if ((!reverse && resAmount > minAmount) || (reverse && resAmount < minAmount)) {
  6944. $("span[title]:eq(" + resIndex + ")", resCell).css("font-weight", "bold")
  6945. return false;
  6946. }
  6947. return true;
  6948. }
  6949.  
  6950. var hasNotes = $("th:first", resTable).text().indexOf(trans.tw.overview.village) == -1;
  6951. resTable.find("tr:gt(0)").each(function () {
  6952. var isOk = true;
  6953. var resCell;
  6954. if (hasNotes) {
  6955. resCell = $(this).find("td:eq(3)");
  6956. } else {
  6957. resCell = $(this).find("td:eq(2)");
  6958. }
  6959. var resources = $.trim(resCell.text()).replace(/\./gi, "").split(" ");
  6960.  
  6961. if (resourceIndex == 'bbcode') {
  6962. // All resources
  6963. var villageBBCode = '';
  6964. for (var i = 0; i < 3; i++) {
  6965. if ((!reverse && resources[i] - minDif > minAmount) || (reverse && parseInt(resources[i], 10) + parseInt(minDif, 10) < minAmount)) {
  6966. if (bbCodeImages) {
  6967. villageBBCode += "[img]https://www.tribalwars.nl/graphic/" + world_data.resources[i] + ".png[/img] ";
  6968. } else {
  6969. villageBBCode += resCode[i] + " ";
  6970. }
  6971. villageBBCode += parseInt(Math.abs(resources[i] - minAmount) / 1000, 10) + "k ";
  6972. }
  6973. }
  6974. if (villageBBCode.length > 0) {
  6975. var villageCell = $("td:eq(" + (hasNotes ? "1" : "0") + ") span:eq(1)", this);
  6976. bbcodes += "[village]" + getVillageFromCoords(villageCell.text()).coord + "[/village] " + villageBBCode + "\n";
  6977. }
  6978. } else if (resourceIndex == 'full') {
  6979. // full storage rooms
  6980. if ($(".warn", this).size() > 0) {
  6981. resCell.css("background-color", user_data.resources.highlightColor);
  6982. isOk = false;
  6983. }
  6984.  
  6985. } else {
  6986. // One specific resource
  6987. $("span[title]", resCell).css("font-weight", "normal");
  6988.  
  6989. if (resourceIndex == "-1") {
  6990. isOk = isOk && !(!doResource(resCell, resources, 0, reverse, minAmount)
  6991. | !doResource(resCell, resources, 1, reverse, minAmount)
  6992. | !doResource(resCell, resources, 2, reverse, minAmount));
  6993. } else {
  6994. isOk = isOk && doResource(resCell, resources, resourceIndex, reverse, minAmount);
  6995. }
  6996.  
  6997. if (!isOk) {
  6998. resCell.css("background-color", user_data.resources.highlightColor);
  6999. } else {
  7000. resCell.css("background-color", "");
  7001. }
  7002.  
  7003. if (filterMerchants) {
  7004. resCell = $(this).find("td:eq(4)");
  7005. if (hasNotes) {
  7006. resCell = resCell.next();
  7007. }
  7008. var merchants = resCell.text();
  7009. merchants = merchants.substr(0, merchants.indexOf("/"));
  7010. if (merchants < filterMerchantsAmount) {
  7011. resCell.css("background-color", user_data.colors.error);
  7012. } else {
  7013. resCell.css("background-color", "");
  7014. }
  7015. }
  7016. }
  7017.  
  7018. if (hideRows && isOk) {
  7019. goners = goners.add($(this));
  7020.  
  7021. // Village rename script will not rename villages if the hidden rename inputfield is on a hidden row
  7022. // --> People were using our script to filter the village list and then use a mass village renamer which also renamed the hidden village rows
  7023. $("input:first", $(this)).val("");
  7024.  
  7025. }
  7026. else if (!$(this).is(":visible")) {
  7027. stayers = stayers.add($(this));
  7028. }
  7029. });
  7030. if (hideRows) {
  7031. goners.remove();
  7032. var amountOfVillagesCell = $("tr:first th", resTable).eq(hasNotes ? 1 : 0);
  7033. amountOfVillagesCell.text(amountOfVillagesCell.text().replace(/\d+/, $("tr", resTable).size() - 1));
  7034. } else {
  7035. stayers.show();
  7036. goners.hide();
  7037. }
  7038.  
  7039. return bbcodes;
  7040. }
  7041.  
  7042. $(".resFilter").click(function () {
  7043. trackClickEvent("FilterResource");
  7044. filterRes($(this).attr("resIndex"), $("#resFilter").is(":checked"));
  7045. });
  7046. } catch (e) { handleException(e, "overview-prod"); }
  7047. //console.timeEnd("overview-prod");
  7048. }());
  7049. }
  7050. // TROOPS OVERVIEW
  7051. else if (location.href.indexOf('mode=units') > -1
  7052. && (location.href.indexOf('type=own_home') > -1 || location.href.indexOf('type=there') > -1)) {
  7053. (function() {
  7054. //console.time("overview-thereownhome");
  7055. try {
  7056. var villageCounter = 0;
  7057. var rowSize = world_data.units.length + 1;
  7058. if (world_config.hasMilitia) {
  7059. rowSize++;
  7060. }
  7061.  
  7062. var overviewMenuRowFilter = "tr:gt(0)",
  7063. /**
  7064. * Page speed can be overruled by the querystring
  7065. */
  7066. currentPageSpeed = spSpeedCookie(),
  7067. /**
  7068. * {village} object from target cookie (or by url querystring set)
  7069. */
  7070. target;
  7071.  
  7072. /**
  7073. * Do initial filter? (based on querystring)
  7074. */
  7075. var doFilter = false,
  7076. unitIndex = world_data.units.indexOf(user_data.command.filterMinDefaultType),
  7077. unitAmount = user_data.command.filterMinDefault,
  7078. sort = false,
  7079. changeSpeed = false,
  7080. i;
  7081. var search = window.location.search.substring(1).split("&");
  7082. for (i = 0; i < search.length; i++) {
  7083. var item = search[i].split("=");
  7084. switch (item[0]) {
  7085. case 'unit':
  7086. doFilter = true;
  7087. unitIndex = world_data.units.indexOf(item[1]);
  7088. break;
  7089. case 'amount':
  7090. doFilter = true;
  7091. unitAmount = parseInt(item[1], 10);
  7092. break;
  7093. case 'changeSpeed':
  7094. changeSpeed = item[1];
  7095. if (changeSpeed != false) {
  7096. //spSpeedCookie(changeSpeed);
  7097. currentPageSpeed = changeSpeed;
  7098. }
  7099. break;
  7100.  
  7101. case 'targetvillage':
  7102. var newTargetVillage = getVillageFromCoords(item[1]);
  7103. spTargetVillageCookie(newTargetVillage.coord);
  7104. break;
  7105.  
  7106. case 'sort':
  7107. sort = item[1] == "true";
  7108. break;
  7109. }
  7110. }
  7111.  
  7112. // Sangu package menu is also built in reinitialize_table
  7113. /**
  7114. * Creates a select box with all unit types in this world
  7115. * @param {string} id the DOM ID
  7116. * @param {string} select the currently selected unit
  7117. */
  7118. function makeUnitBox(id, select) {
  7119. var box = "<select id=" + id + ">";
  7120. $.each(world_data.units, function (i, v) {
  7121. box += "<option value=" + i + (v == select ? " selected" : "") + ">" + trans.tw.units.names[v] + "</option>";
  7122. });
  7123. box += "</select>";
  7124. return box;
  7125. }
  7126.  
  7127. var menu = "<table width='100%' class='vis'>";
  7128. menu += "<tr>";
  7129. menu += "<th nowrap width='1%'>";
  7130. menu += "<input type=text size=5 id=filterAxeValue value='" + user_data.command.filterMinDefault + "'>";
  7131. menu += makeUnitBox("filterAxeType", user_data.command.filterMinDefaultType);
  7132. menu += "<input type=button id=filterAxe value='" + trans.sp.troopOverview.filterTroops + "'";
  7133. menu += " title='" + trans.sp.troopOverview.filterTroopsTooltip + "'> ";
  7134.  
  7135. menu += "</th><th nowrap width='1%'>";
  7136.  
  7137. menu += "<select id=filterPopValueType><option value=1>" + trans.sp.all.more + "</option>";
  7138. menu += "<option value=-1>" + trans.sp.all.less + "</option></select>";
  7139. menu += "<input type=text size=5 id=filterPopValue value='" + user_data.command.filterMinPopulation + "'>";
  7140. menu += "<input type=button id=filterPop value='" + trans.sp.troopOverview.filterPopulation + "' title='" + trans.sp.troopOverview.filterPopulationTooltip + "'> ";
  7141.  
  7142. menu += "</th><th nowrap width='1%'>";
  7143. menu += "<input type=text size=5 id=filterWalkingTimeValue>";
  7144. menu += "<input type=button id=filterWalkingTime value='" + trans.sp.troopOverview.filterWalkingTime + "' title='" + trans.sp.troopOverview.filterWalkingTimeTooltip + "'> ";
  7145.  
  7146. menu += "</th><th width='95%'>";
  7147.  
  7148. menu += "<input type=button id=snobFilter value='" + trans.sp.troopOverview.filterNoble + "' title='" + trans.sp.troopOverview.filterNobleTooltip + "'> &nbsp; ";
  7149. menu += "<input type=button id=attackFilter value='" + trans.sp.troopOverview.filterUnderAttack + "' title='" + trans.sp.troopOverview.filterUnderAttackTooltip + "'> &nbsp; ";
  7150.  
  7151. menu += "</th><th width='1%'>";
  7152.  
  7153. menu += "<input type=button id=calculateStack value='" + trans.sp.troopOverview.calcStack + "' title='" + trans.sp.troopOverview.calcStackTooltip + "'>";
  7154. menu += "</th>";
  7155.  
  7156. menu += "</tr></table>";
  7157.  
  7158. // second row
  7159. menu += "<table><tr><th width='1%' nowrap>";
  7160. menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": ";
  7161.  
  7162. menu += "</th><th width='1%' nowrap>";
  7163. menu += "<input type=text size=12 id=defFilterTextValue value=''>";
  7164. menu += "<input type=button id=defFilterText value='" + trans.sp.commands.freeTextFilter + "'>";
  7165.  
  7166. menu += "</th><th width='97%' nowrap>";
  7167. menu += "<input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>";
  7168.  
  7169. menu += "</th>";
  7170.  
  7171. if (location.href.indexOf('type=there') > -1) {
  7172. menu += "<th width='1%'><input type=button id=defRestack value='" + trans.sp.troopOverview.restack + "'></th>";
  7173. }
  7174. menu += "<th nowrap width='1%' style='padding-right: 8px; padding-top: 3px;'>";
  7175.  
  7176. menu += "<input type=checkbox id=sortIt title='" + trans.sp.troopOverview.sortTooltip + "'"
  7177. + (user_data.command.filterAutoSort ? " checked" : "") + "> "
  7178. + trans.sp.troopOverview.sort;
  7179.  
  7180. menu += "</th></tr>";
  7181. menu += "</table>";
  7182.  
  7183. // Sangu filter menu
  7184. var sanguMenu = menu;
  7185.  
  7186. // Overview table menu
  7187. menu = "<tr id=units_table_header>";
  7188. menu += "<th>" + trans.sp.troopOverview.village + "</th>";
  7189. menu += "<th>" + trans.sp.troopOverview.nightBonus + "</th>";
  7190. $.each(world_data.units, function (i, v) {
  7191. 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>";
  7192. });
  7193. if (world_config.hasMilitia) {
  7194. menu += "<th><img src='/graphic/unit/unit_militia.png' title='" + trans.tw.units.militia + "' alt='' id=militia /></th>";
  7195. }
  7196. menu += "<th>" + trans.sp.troopOverview.commandTitle + "</th>";
  7197.  
  7198.  
  7199. target = getVillageFromCoords(spTargetVillageCookie());
  7200. menu += "<th nowrap>" + trans.sp.all.targetEx
  7201. + " <input type=text id=targetVillage name=targetVillage size=8 value='"
  7202. + (target.isValid ? target.coord : "") + "'>"
  7203. + "<input type=button class='btn' id=targetVillageButton value='"
  7204. + trans.sp.troopOverview.setTargetVillageButton + "'></th>";
  7205. menu += "</tr>";
  7206.  
  7207.  
  7208.  
  7209.  
  7210.  
  7211.  
  7212. // function to replace the village rows
  7213. tableHandler.init("units_table", {
  7214. rowReplacer: function (row) {
  7215. //q($(row).html());
  7216. var mod = "row_a";
  7217. var newRow = "";
  7218. var finalRow = "";
  7219. var addThisRow = true;
  7220. var cells = $("td:gt(0)", row);
  7221. var units = {};
  7222. var villageCell = $("td:first", row);
  7223. var villageId = $("span.quickedit-vn", villageCell).attr("data-id");
  7224.  
  7225. cells.each(function (index, element) {
  7226. if (doFilter && index - 1 == unitIndex && parseInt(this.innerHTML, 10) < unitAmount) {
  7227. //q("index:" + index + ' == '+ unitIndex + " : " + row.html() + ' * 1 < ' + unitAmount);
  7228. addThisRow = false;
  7229. return false;
  7230. }
  7231. else if (index == rowSize) {
  7232. //q(index + "==" + rowSize);
  7233. newRow += "<td>";
  7234. newRow += "<img src='/graphic/dots/red.png' title='" + trans.sp.troopOverview.removeVillage + "' style='margin-bottom: 2px' /> ";
  7235. //newRow += "<img src='https://www.tribalwars.vodka/graphic/delete_small.png' style='margin-bottom: 3px; position: relative' title='" + trans.sp.troopOverview.removeVillage + "' /> ";
  7236. newRow += "<a href='" + $("a", element).attr('href').replace("mode=units", "") + "&sanguX=0&sanguY=0' class='attackLinks'>";
  7237. newRow += "<img src='/graphic/command/attack.png' title='" + trans.sp.troopOverview.toThePlace + "' style='margin-bottom: 1px' />";
  7238. // Works only with leftclick onclick='this.src=\"/graphic/command/return.png\";'
  7239. newRow += "</a>";
  7240. newRow += "</td>";
  7241. } else {
  7242. //q("units:" + world_data.units[index - 1]);
  7243. var cellDisplay = this.innerHTML;
  7244. if (cellDisplay === "0") {
  7245. cellDisplay = "&nbsp;";
  7246. }
  7247. else if (cellDisplay.indexOf('="has_tooltip"') > -1) {
  7248. cellDisplay = cellDisplay.replace('="has_tooltip"', '="has_tooltip" title="'+trans.sp.troopOverview.cheapNobles+'"');
  7249. }
  7250.  
  7251. newRow += "<td>" + cellDisplay + "</td>";
  7252. if (index > 0) {
  7253. units[world_data.units[index - 1]] = parseInt(element.innerHTML, 10);
  7254. }
  7255. // innerHTML can contain a + sign for the nobles: "+" indicates nobles can be rebuild cheaply
  7256. // The snobs are not important here
  7257. }
  7258. });
  7259.  
  7260. if (addThisRow) {
  7261. var villageType = calcTroops(units);
  7262. if (doFilter) {
  7263. mod = villageCounter % 2 == 0 ? "row_a" : "row_b";
  7264. } else {
  7265. mod = !villageType.isDef ? "row_a" : "row_b";
  7266. }
  7267.  
  7268. var coord = getVillageFromCoords(villageCell.text());
  7269.  
  7270. //finalRow += "<tbody>";
  7271. finalRow += "<tr arrival='0' data-coord-x='" + coord.x + "' data-coord-y='" + coord.y + "' "
  7272. + " class='row_marker " + mod + (game_data.village.id == villageId ? " selected" : "") + "'>";
  7273. finalRow += "<td>" + villageCell.html() + "</td>";
  7274. finalRow += newRow;
  7275. finalRow += "<td></td></tr>";
  7276. //finalRow += "</tbody>";
  7277.  
  7278. villageCounter++;
  7279.  
  7280. return finalRow;
  7281. }
  7282. return "";
  7283. }
  7284. });
  7285.  
  7286. var newTable = tableHandler.getReplacedVillageRows();
  7287. $("#units_table")
  7288. .html("<table width='100%' class='vis' id='units_table' target='false'>" + menu + newTable + "</table>")
  7289. .before(sanguMenu);
  7290.  
  7291.  
  7292. // Tooltips
  7293. $("#defReverseFilter").change( function () {
  7294. var isChecked = $(this).is(":checked");
  7295. var defTrans = trans.sp.troopOverview;
  7296.  
  7297. $("#defFilterContinent").attr("title", isChecked ? defTrans.continentFilterTooltip : defTrans.continentFilterTooltipReverse);
  7298. $("#defFilterText").attr("title", defTrans.freeTextFilterTooltip.replace("{filterType}", isChecked ? defTrans.freeTextFilterTooltipFilterTypeWith : defTrans.freeTextFilterTooltipFilterTypeWithout));
  7299. });
  7300. $("#defReverseFilter").change();
  7301.  
  7302.  
  7303. // Initial focus on target inputbox
  7304. $('#targetVillage').click(function () {
  7305. $(this).focus().select();
  7306. });
  7307.  
  7308.  
  7309.  
  7310. // "Attacks per page" -> change to # villages in the list
  7311. var pageSize = $("input[name='page_size']");
  7312. var villageAmountCell = $("#units_table tr:first th:first");
  7313. //assert(villageAmountCell.length === 1, "village cell Dorp (xxx) niet gevonden");
  7314. villageAmountCell.text(villageAmountCell.text() + " (0)");
  7315. function setVillageCount(amount) {
  7316. pageSize.val(amount);
  7317. villageAmountCell.text(villageAmountCell.text().replace(/\d+/, amount));
  7318. }
  7319.  
  7320. pageSize.parent().prev().text(trans.sp.overviews.totalVillages);
  7321. setVillageCount(villageCounter);
  7322.  
  7323. // Recalculate arrival times as the target village changes
  7324. $("#targetVillageButton").click(function () {
  7325. trackClickEvent("TargetVillageSet");
  7326. var targetMatch = getVillageFromCoords($('#targetVillage').val(), true);
  7327. $("#units_table").attr("target", targetMatch.isValid);
  7328. if (!targetMatch.isValid) {
  7329. spTargetVillageCookie("");
  7330. alert(trans.sp.troopOverview.setTargetVillageButtonAlert);
  7331. $("#targetVillage").focus();
  7332.  
  7333. } else {
  7334. $(".attackLinks", tableHandler.overviewTable).each(function() {
  7335. // add target coordinates to attack image href which are read in place
  7336. var hrefWithVillageCoords = $(this).attr("href");
  7337. hrefWithVillageCoords = hrefWithVillageCoords.replace(/sanguX=(\d+)&sanguY=(\d+)/, "sanguX="+targetMatch.x+"&sanguY="+targetMatch.y);
  7338. $(this).attr("href", hrefWithVillageCoords);
  7339. });
  7340.  
  7341. spTargetVillageCookie(targetMatch.coord);
  7342. $("#units_table").find(overviewMenuRowFilter).each(function () {
  7343. var unitRow = $(this),
  7344. dist = getDistance(targetMatch.x, unitRow.attr("data-coord-x"), targetMatch.y, unitRow.attr("data-coord-y"), currentPageSpeed);
  7345.  
  7346. $("td:last", unitRow).html(dist.html);
  7347. $(this).attr("arrival", dist.travelTime);
  7348. if (dist.isNightBonus) {
  7349. $("td:eq(1)", unitRow).css("background-color", user_data.colors.error);
  7350. } else {
  7351. $("td:eq(1)", unitRow).css("background-color", '');
  7352. }
  7353. });
  7354.  
  7355. if ($("#sortIt").is(":checked")) {
  7356. $("#units_table").find(overviewMenuRowFilter).sortElements(function (a, b) {
  7357. return parseInt($(a).attr("arrival"), 10) > parseInt($(b).attr("arrival"), 10) ? 1 : -1;
  7358. });
  7359. }
  7360. }
  7361. });
  7362.  
  7363. // sort can be set with the querystring
  7364. if (sort) {
  7365. $("#targetVillageButton").click();
  7366. }
  7367.  
  7368. // delete a table row
  7369. $("#units_table").mouseup(function (e) {
  7370. if (e.target.nodeName === 'IMG') {
  7371. if (e.target.title == trans.sp.troopOverview.removeVillage) {
  7372. setVillageCount(parseInt(pageSize.val(), 10) - 1);
  7373. $(e.target).parent().parent().remove();
  7374. }
  7375. }
  7376. });
  7377.  
  7378. // remove row or add border to command cell when middle mouse click (open in new tab)
  7379. $(tableHandler.overviewTable).on("mousedown",".attackLinks", function(e) {
  7380. if (e.which == 2) {
  7381. var cell = $(e.target).parent().parent();
  7382. if (user_data.command.middleMouseClickDeletesRow2) {
  7383. cell.parent().remove();
  7384. } else {
  7385. cell.css("border", (parseInt(cell.css("border-width").substr(0, 1), 10) + 1) + "px red solid");
  7386. }
  7387. }
  7388. });
  7389.  
  7390. // Change active speed by clicking on a unit icon
  7391. // ATTN: border style duplicated in trans.troopOverview.help
  7392. $('#' + currentPageSpeed).parent().css("border", "2px green dotted");
  7393. $('#' + spSpeedCookie()).parent().css("border", "3px red solid");
  7394. $("#units_table_header").click(function (e) {
  7395. if (e.target.nodeName === 'IMG' && e.target.id !== "militia") {
  7396. currentPageSpeed = e.target.id;
  7397. $("img", this).parent().css("border", "0px");
  7398. $('#' + currentPageSpeed).parent().css("border", "2px green dotted");
  7399. $('#' + spSpeedCookie()).parent().css("border", "3px red solid");
  7400. $("#targetVillageButton").click();
  7401. }
  7402. });
  7403.  
  7404. $("#units_table_header").dblclick(function (e) {
  7405. if (e.target.nodeName === 'IMG' && e.target.id !== "militia") {
  7406. currentPageSpeed = e.target.id;
  7407. spSpeedCookie(e.target.id);
  7408. $("img", this).parent().css("border", "0px");
  7409. $('#' + currentPageSpeed).parent().css("border", "2px green dotted");
  7410. $('#' + spSpeedCookie()).parent().css("border", "3px red solid");
  7411. $("#targetVillageButton").click();
  7412. }
  7413. });
  7414. function filterVillageRows(filterStrategy, options) {
  7415. // return true to hidethe row; false keep row visible (without reverse filter checkbox)
  7416. options = options || {
  7417. allowFilter: true
  7418. };
  7419. var reverseFilter = options.allowFilter && $("#defReverseFilter").is(":checked"),
  7420. goners = $(),
  7421. villageCounter = 0;
  7422.  
  7423. $("#units_table").find(overviewMenuRowFilter).each(function () {
  7424. var self = $(this);
  7425. if (!reverseFilter != !filterStrategy(self)) {
  7426. goners = goners.add(self);
  7427. $("input:eq(1)", self).val("");
  7428. } else {
  7429. villageCounter++;
  7430. }
  7431. });
  7432. goners.remove();
  7433.  
  7434. // Show totals
  7435. setVillageCount(villageCounter);
  7436. }
  7437.  
  7438. // CONTINENT FILTER
  7439. $("#defFilterContinent").click(function () {
  7440. trackClickEvent("FilterContinent");
  7441. var continent = parseInt($("#defFilterContinentText").val(), 10);
  7442. if (!isNaN(continent)) {
  7443. filterVillageRows(function (row) {
  7444. var village = getVillageFromCoords(row.find("td:first").text());
  7445. if (!village.isValid ) {
  7446. return true;
  7447. }
  7448. return village.continent() != continent;
  7449. });
  7450. }
  7451. });
  7452.  
  7453. // TEXT FILTER
  7454. $("#defFilterText").click(function () {
  7455. trackClickEvent("FilterText");
  7456. var compareTo = $("#defFilterTextValue").val().toLowerCase();
  7457. if (compareTo.length > 0) {
  7458. filterVillageRows(function (row) {
  7459. return row.text().toLowerCase().indexOf(compareTo) == -1;
  7460. });
  7461. }
  7462. });
  7463.  
  7464. // WALKINGTIME FILTER
  7465. $("#filterWalkingTime").click(function () {
  7466. var minWalkingTime = parseInt($("#filterWalkingTimeValue").val(), 10) * 60;
  7467.  
  7468. if (!isNaN(minWalkingTime)) {
  7469. trackClickEvent("WalkingTime");
  7470. filterVillageRows(
  7471. function (row) {
  7472. return parseInt(row.attr("arrival"), 10) < minWalkingTime;
  7473. },
  7474. {
  7475. allowFilter: false
  7476. }
  7477. );
  7478. } else {
  7479. alert(trans.sp.troopOverview.filterWalkingTimeTooltip);
  7480. }
  7481. });
  7482.  
  7483.  
  7484.  
  7485.  
  7486.  
  7487.  
  7488. // Filter rows with less than x axemen (or another unit)
  7489. $("#filterAxe").click(function () {
  7490. trackClickEvent("FilterUnitAmount");
  7491. var villageCounter = 0;
  7492. var goners = $();
  7493. var minAxeValue = parseInt($("#filterAxeValue").val(), 10);
  7494. var unit = parseInt($('#filterAxeType').val(), 10);
  7495. $("#units_table").find(overviewMenuRowFilter).each(function () {
  7496. var val = $("td:eq(" + (unit + 2) + ")", this).html();
  7497. if (val == '&nbsp;' || parseInt(val, 10) < minAxeValue) {
  7498. goners = goners.add($(this));
  7499. $("input:first", $(this)).val("");
  7500. }
  7501. else
  7502. villageCounter++;
  7503. });
  7504. goners.remove();
  7505. setVillageCount(villageCounter);
  7506. });
  7507. // change by default selected unit the filter will be active for
  7508. $("#filterAxeType").change(function () {
  7509. var unit = world_data.units[$(this).val()];
  7510. if (typeof user_data.command.filterMin[unit] !== 'undefined') {
  7511. $("#filterAxeValue").val(user_data.command.filterMin[unit]);
  7512. } else {
  7513. $("#filterAxeValue").val(user_data.command.filterMinOther);
  7514. }
  7515. });
  7516.  
  7517.  
  7518.  
  7519. // Filter rows without snobs/nobles
  7520. $("#snobFilter").click(function () {
  7521. trackClickEvent("FilterSnob");
  7522. var villageCounter = 0;
  7523. var goners = $();
  7524. $("#units_table").find(overviewMenuRowFilter).each(function () {
  7525. if ($.trim($("td:eq(" + (world_data.unitsPositionSize.length + 1) + ")", this).text()) === '') {
  7526. goners = goners.add($(this));
  7527. $("input:first", $(this)).val("");
  7528. } else
  7529. villageCounter++;
  7530. });
  7531. goners.remove();
  7532. setVillageCount(villageCounter);
  7533. });
  7534.  
  7535. // hide rows not under attack
  7536. $("#attackFilter").click(function () {
  7537. trackClickEvent("FilterUnderAttack");
  7538. var villageCounter = 0;
  7539. var goners = $();
  7540. $("#units_table").find(overviewMenuRowFilter).each(function () {
  7541. //q("'" + $(this).html() + "'");
  7542. //q("---------------------------------------------------");
  7543. if ($('td:first:not(:has(img[title=\'' + trans.tw.command.attack + '\']))', this).size() != 0) {
  7544. goners = goners.add($(this));
  7545. $("input:first", $(this)).val("");
  7546. } else {
  7547. villageCounter++;
  7548. }
  7549. });
  7550. goners.remove();
  7551. setVillageCount(villageCounter);
  7552. });
  7553.  
  7554. // filter rows with less then x population
  7555. $("#filterPop").click(function () {
  7556. trackClickEvent("FilterFarm");
  7557. $("#calculateStack").click();
  7558. var villageCounter = 0;
  7559. var goners = $();
  7560. var min = parseInt($("#filterPopValue").val(), 10);
  7561. var reverseFilter = $("#filterPopValueType").val() == "-1";
  7562. $("#units_table").find(overviewMenuRowFilter).each(function () {
  7563. var line = $(this);
  7564. $("td:eq(1)", this).each(function () {
  7565. var amount = parseInt($(this).text().replace('.', ''), 10);
  7566. if ((!reverseFilter && amount < min) || (reverseFilter && amount > min)) {
  7567. goners = goners.add(line);
  7568. $("input:first", line).val("");
  7569. }
  7570. else villageCounter++;
  7571. });
  7572. });
  7573. goners.remove();
  7574. setVillageCount(villageCounter);
  7575. });
  7576. // One time help display
  7577. (function() {
  7578. if ($("#targetVillageButton").length === 0) {
  7579. // group without villages
  7580. return;
  7581. }
  7582.  
  7583. var position = $("#targetVillageButton").position(),
  7584. options = {
  7585. left: position.left - 300,
  7586. top: position.top + 35
  7587. },
  7588. content = {
  7589. title: trans.sp.troopOverview.helpTitle,
  7590. body: trans.sp.troopOverview.help.replace("{unitIcon}", "<img src='graphic/unit/unit_ram.png'>, <img src='graphic/unit/unit_spear.png'>, ...")
  7591. };
  7592.  
  7593. createFixedTooltip("troopOverviewTooltip", content, options);
  7594. }());
  7595.  
  7596. // Calculate stack
  7597. $("#calculateStack").click(function () {
  7598. trackClickEvent("CalculateStack");
  7599. if (!this.disabled) {
  7600. this.disabled = true;
  7601. $("#units_table").find(overviewMenuRowFilter).each(function () {
  7602. var total = 0;
  7603. $("td:gt(1)", this).each(function (i) {
  7604. if (!($.trim(this.innerHTML) == '' || this.innerHTML == '&nbsp;' || i >= world_data.unitsPositionSize.length)) {
  7605. total += this.innerHTML * world_data.unitsPositionSize[i];
  7606. }
  7607. });
  7608. $("td:eq(1)", this).text(formatNumber(total)).css("background-color", getStackColor(total));
  7609. });
  7610. }
  7611. });
  7612. // Calculate Restack BB codes
  7613. if (location.href.indexOf('type=there') > -1) {
  7614. $("#defRestack").click(function () {
  7615. trackClickEvent("BBCodeOutput");
  7616. $("#calculateStack").click();
  7617.  
  7618. var request = "";
  7619. $("#units_table").find(overviewMenuRowFilter).each(function () {
  7620. var total = parseInt($("td:eq(1)", $(this)).text().replace(/\./, ''), 10);
  7621. if (user_data.restack.to - total > user_data.restack.requiredDifference) {
  7622. var villageDesc = $(this).find("td:first span[data-text]").text(),
  7623. villageCoord = getVillageFromCoords(villageDesc);
  7624.  
  7625. request += "[village]" + villageCoord.coord + "[/village] (" + parseInt((user_data.restack.to - total) / 1000, 10) + "k)\n";
  7626. }
  7627. });
  7628.  
  7629. if ($("#textsArea").size() == 0) {
  7630. $(this).parent().parent().parent().append("<tr><td id=textsArea colspan=5></td></tr>");
  7631. } else {
  7632. $("#textsArea").html("");
  7633. }
  7634.  
  7635. var title = trans.sp.troopOverview.restackTitle
  7636. .replace("{to}", parseInt(user_data.restack.to / 1000, 10))
  7637. .replace("{requiredDiff}", parseInt(user_data.restack.requiredDifference / 1000, 10));
  7638. $("#textsArea").append(title + "<br><textarea cols=35 rows=10 id=defRestackArea>" + request + "</textarea>");
  7639.  
  7640. $("#textsArea").append("<br><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>");
  7641. $("#closeTextsArea").click(function() {
  7642. $("#textsArea").parent().remove();
  7643. });
  7644. });
  7645. }
  7646.  
  7647. } catch (e) { handleException(e, "overview-thereownhome"); }
  7648. //console.timeEnd("overview-thereownhome");
  7649. }());
  7650. }
  7651. // BUILDINGS OVERVIEW
  7652. else if (location.href.indexOf('mode=buildings') > -1) {
  7653. (function() {
  7654. //console.time("overview-buildings");
  7655. try {
  7656. // Highlight everything not conform
  7657. overviewTable = $("#buildings_table");
  7658. tableHandler.init("buildings_table");
  7659.  
  7660. var menu = "<table class='vis' width='100%'>";
  7661. menu += "<tr><th>";
  7662. menu += "<input type=checkbox id=buildingOpti> " + trans.sp.buildOverview.optimistic + " ";
  7663. menu += "<input type=button id=buildingHighlight value='" + trans.sp.buildOverview.mark + "'>";
  7664. menu += "<input type=button id=buildingFilter value='" + trans.sp.buildOverview.filter + "'>";
  7665. menu += "</th></tr></table>";
  7666. overviewTable.before(menu);
  7667.  
  7668. function filterBuildings(cellAction, hideRows) {
  7669. var buildings = [];
  7670. overviewTable.find("tr:first img").each(function (i, v) {
  7671. buildings[i] = this.src.substr(this.src.lastIndexOf('/') + 1);
  7672. buildings[i] = buildings[i].substr(0, buildings[i].indexOf('.'));
  7673. });
  7674.  
  7675. var goners = $();
  7676. var opti = $("#buildingOpti").is(":checked");
  7677. overviewTable.find("tr:gt(0)").each(function () {
  7678. var isOk = true;
  7679. $(this).find("td:gt(3)").each(function (i, v) {
  7680. var range = user_data.buildings[buildings[i]];
  7681. if (range != undefined) {
  7682. var text = parseInt($(this).text(), 10);
  7683. if (text < range[0]) {
  7684. $(this).css("background-color", user_data.colors.error);
  7685. isOk = false;
  7686. } else if (text > range[1] && !opti) {
  7687. $(this).css("background-color", user_data.colors.good);
  7688. isOk = false;
  7689. } else
  7690. $(this).css("background-color", "");
  7691. }
  7692. });
  7693. if (hideRows && isOk) {
  7694. goners = goners.add($(this));
  7695. $("input:first", $(this)).val("");
  7696. }
  7697. });
  7698. goners.remove();
  7699. }
  7700.  
  7701. $("#buildingHighlight").click(function () {
  7702. trackClickEvent("TableHighlight");
  7703. filterBuildings(function (cell, isOk) {
  7704. cell.css("background-color", isOk ? "" : user_data.colors.neutral);
  7705. }, false);
  7706. });
  7707.  
  7708. $("#buildingFilter").click(function () {
  7709. trackClickEvent("TableRemove");
  7710. filterBuildings(function (cell, isOk) {
  7711. cell.css("background-color", isOk ? "" : user_data.colors.neutral);
  7712. }, true);
  7713. });
  7714. } catch (e) { handleException(e, "overview-buildings"); }
  7715. //console.timeEnd("overview-buildings");
  7716. }());
  7717. }
  7718. // TECHS OVERVIEW // SMEDERIJ OVERVIEW // SMITHY OVERVIEW
  7719. else if (location.href.indexOf('mode=tech') > -1) {
  7720. (function() {
  7721. //console.time("overview-techs");
  7722. try {
  7723. overviewTable = $("#techs_table");
  7724. tableHandler.init("techs_table");
  7725.  
  7726. // Highlight everything not conform usersettings
  7727. if (world_config.smithyLevels) {
  7728. var menu = "<table class='vis' width='100%'>";
  7729. menu += "<tr><th>";
  7730. menu += "<select id='groupType'>";
  7731. $.each(user_data.smithy, function (i, v) {
  7732. menu += "<option value=" + i + ">" + v[0] + "</option>";
  7733. });
  7734. menu += "</select>";
  7735. menu += "<input type=checkbox id=buildingOpti> " + trans.sp.smithOverview.optimistic + " ";
  7736. menu += "<input type=button id=smithyHighlight value='" + trans.sp.smithOverview.mark + "'>";
  7737. menu += "<input type=button id=smithyFilter value='" + trans.sp.smithOverview.filter + "'>";
  7738. menu += "</th></tr></table>";
  7739. $("#techs_table").before(menu);
  7740.  
  7741. function filterTechs(cellAction, hideRows) {
  7742. var goners = $();
  7743. var opti = $("#buildingOpti").is(":checked");
  7744. var def = user_data.smithy[$("#groupType").val()][1];
  7745. $("#techs_table").find("tr:gt(0)").each(function () {
  7746. var isOk = true;
  7747. $(this).find("td:gt(2)").each(function (i, v) {
  7748. var range = def[world_data.units[i]];
  7749. if (i < world_data.units.length && range != undefined) {
  7750. var text = parseInt($(this).text(), 10);
  7751. if (text == '') {
  7752. text = 0;
  7753. }
  7754. if (text < range[0]) {
  7755. $(this).css("background-color", user_data.colors.error);
  7756. isOk = false;
  7757. }
  7758. else if (text > range[1] && !opti) {
  7759. $(this).css("background-color", user_data.colors.good);
  7760. isOk = false;
  7761. } else {
  7762. $(this).css("background-color", "");
  7763. }
  7764. }
  7765. });
  7766. if (hideRows && isOk) {
  7767. goners = goners.add($(this));
  7768. $("input:first", $(this)).val("");
  7769. }
  7770. });
  7771. goners.remove();
  7772. }
  7773.  
  7774. $("#smithyHighlight").click(function () {
  7775. trackClickEvent("TableHighlight");
  7776. filterTechs(function (cell, isOk) {
  7777. cell.css("background-color", isOk ? "" : user_data.colors.neutral);
  7778. }, false);
  7779. });
  7780.  
  7781. $("#smithyFilter").click(function () {
  7782. trackClickEvent("TableRemove");
  7783. filterTechs(function (cell, isOk) {
  7784. cell.css("background-color", isOk ? "" : user_data.colors.neutral);
  7785. }, true);
  7786. });
  7787. }
  7788. } catch (e) { handleException(e, "overview-techs"); }
  7789. //console.timeEnd("overview-techs");
  7790. }());
  7791. }
  7792. // GROUPS OVERVIEW
  7793. else if (location.href.indexOf('mode=groups') > -1) {
  7794. (function() {
  7795. //console.time("overview-groups");
  7796. try {
  7797. overviewTable = $("#group_assign_table");
  7798. tableHandler.init("group_assign_table", {
  7799. hasBottomTotalRow: true
  7800. });
  7801.  
  7802. // TODO: edit groups: make div floatable and remember position
  7803. var menu = "";
  7804. menu += "<table class=vis width='100%'><tr><th>";
  7805.  
  7806. menu += trans.sp.defOverview.village + " <input type=text size=5 id=defFilterDistVillage value=''>";
  7807. menu += "<select id=defFilterDistType>";
  7808. menu += "<option value=1 selected>" + trans.sp.all.closer + "</option><option value=-1>" + trans.sp.all.further + "</option></select>";
  7809. menu += "&nbsp;F <input type=text size=3 id=defFilterDistFields value=" + user_data.restack.fieldsDistanceFilterDefault + ">";
  7810. menu += "<input type=button id=defFilterDist value='" + trans.sp.defOverview.distFilter + "' title='" + trans.sp.defOverview.distFilterTooltip + "'>";
  7811.  
  7812. menu += "&nbsp; | &nbsp;";
  7813. menu += "<input type=button id=attackFilter value='" + trans.sp.defOverview.filterUnderAttack + "'>";
  7814.  
  7815. menu += "<br>";
  7816.  
  7817. menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": ";
  7818.  
  7819. menu += "&nbsp; <input type=text size=12 id=defFilterTextValue value=''>";
  7820. menu += "<input type=button id=defFilterText value='" + trans.sp.groups.villageFilter + "'>";
  7821.  
  7822. menu += "&nbsp; <input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>";
  7823.  
  7824. menu += "&nbsp; <input type=textbox size=3 id=defFilterAmountText maxlength=2><input type=button id=defFilterAmount value='" + trans.sp.groups.amountFilter + "'>";
  7825. menu += "&nbsp; <input type=textbox size=4 id=defFilterPointsText maxlength=5><input type=button id=defFilterPoints value='" + trans.sp.groups.pointsFilter + "'>";
  7826. menu += "&nbsp; <input type=textbox size=5 id=defFilterFarmText maxlength=6><input type=button id=defFilterFarm value='" + trans.tw.all.farm + "'>";
  7827.  
  7828. menu += "&nbsp; <input type=text size=12 id=defFilterGroupValue value=''>";
  7829. menu += "<input type=button id=defFilterGroup value='" + trans.sp.groups.groupNameFilter + "'>";
  7830. menu += "</th></tr></table>";
  7831.  
  7832. var selectAllRow = $("#group_assign_table tr:last");
  7833. $("#group_assign_table").before(menu).after("<table class=vis width='100%'><tr><th><input type=checkbox id=selectAllVisible> " + selectAllRow.text() + "</th></tr></table>");
  7834. selectAllRow.remove();
  7835.  
  7836. // Select all checkbox behavior
  7837. $("#selectAllVisible").change(function () {
  7838. var isChecked = $(this).is(":checked");
  7839. $("#group_assign_table input:checked").prop("checked", false);
  7840. if (isChecked) {
  7841. $("#group_assign_table input[type='checkbox']").not(":hidden").prop("checked", true);
  7842. }
  7843.  
  7844. //$("#group_assign_table input:hidden").prop("checked", false);
  7845. //$("#group_assign_table input:visible").prop("checked", isChecked);
  7846. });
  7847.  
  7848. // Change tooltips when clicking the reverse filter checkbox
  7849. $("#defReverseFilter").change(function () {
  7850. var isChecked = $(this).is(":checked");
  7851. var defTrans = trans.sp.groups;
  7852. $("#defFilterText").attr("title", isChecked ? defTrans.villageFilterTitle : defTrans.villageFilterTitleRev);
  7853. $("#defFilterContinent").attr("title", isChecked ? trans.sp.commands.continentFilterTooltip : trans.sp.commands.continentFilterTooltipReverse);
  7854.  
  7855. $("#defFilterAmount").attr("title", isChecked ? defTrans.amountFilterTitle : defTrans.amountFilterTitleRev);
  7856. $("#defFilterPoints").attr("title", isChecked ? defTrans.pointsFilterTitle : defTrans.pointsFilterTitleRev);
  7857. $("#defFilterFarm").attr("title", isChecked ? defTrans.farmFilterTitle : defTrans.farmFilterTitleRev);
  7858.  
  7859. $("#defFilterGroup").attr("title", isChecked ? defTrans.groupNameFilterTitle : defTrans.groupNameFilterTitleRev);
  7860. });
  7861. $("#defReverseFilter").change();
  7862.  
  7863. /**
  7864. * Perform a filter on the groups table rows
  7865. * @param {function} filterStrategy jQuery object with the row is the first parameter
  7866. * @param {boolean} reverseFilter
  7867. * @param {function} [keepRowStrategy]
  7868. * @param {*} [tag] passed as second param to filterStrategy and keepRowStrategy
  7869. */
  7870.  
  7871. function filterGroupRows(filterStrategy, reverseFilter, keepRowStrategy, tag) {
  7872. if (typeof reverseFilter === "undefined") {
  7873. reverseFilter = !$("#defReverseFilter").is(":checked");
  7874. }
  7875.  
  7876. var goners = $();
  7877. var totalVisible = 0;
  7878. $("#group_assign_table tr:gt(0)").each(function () {
  7879. var row = $(this);
  7880. if (row.is(":visible")) {
  7881. if (!reverseFilter != !filterStrategy(row, tag)) {
  7882. goners = goners.add(row);
  7883. //$("input:eq(1)", row).val("");
  7884. } else {
  7885. totalVisible++;
  7886. if (keepRowStrategy != null) {
  7887. keepRowStrategy(row, tag);
  7888. }
  7889. }
  7890. }
  7891. });
  7892. goners.remove();
  7893. var firstHeaderCell = $("#group_assign_table th:first");
  7894. var firstHeaderCellHtml = firstHeaderCell.html();
  7895. firstHeaderCell.html(firstHeaderCellHtml.substr(0, firstHeaderCellHtml.lastIndexOf(" ")) + " (" + totalVisible + ")");
  7896. }
  7897.  
  7898. // Filter on distance to given village
  7899. $("#defFilterDist").click(function () {
  7900. var targetVillage = getVillageFromCoords($("#defFilterDistVillage").val(), true);
  7901. if (!targetVillage.isValid) {
  7902. alert(trans.sp.defOverview.distanceToVillageNoneEntered);
  7903. return;
  7904. }
  7905.  
  7906. trackClickEvent("FilterDistance");
  7907. var reverseFilter = !($("#defFilterDistType").val() != "-1");
  7908. var maxDistance = parseInt($("#defFilterDistFields").val(), 10);
  7909.  
  7910. var isAlreadyVisible = $("#filterContext").size() == 1;
  7911. var distanceHeader =
  7912. trans.sp.defOverview.distanceToVillage.replace(
  7913. "{0}",
  7914. "<a href='"
  7915. + getUrlString("&screen=map&x=" + targetVillage.x + "&y=" + targetVillage.y + "'>")
  7916. + targetVillage.coord + "</a>");
  7917.  
  7918. if (isAlreadyVisible) {
  7919. $("#filterContext").html(distanceHeader);
  7920. } else {
  7921. $("#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>");
  7922. $(".sortDistance").click(function () {
  7923. if ($(this).attr("direction") == "up") {
  7924. $("#group_assign_table").find("tr:gt(0)").filter(":visible").sortElements(function (a, b) {
  7925. return parseInt($(a).attr("fieldAmount"), 10) > parseInt($(b).attr("fieldAmount"), 10) ? 1 : -1;
  7926. });
  7927. } else {
  7928. $("#group_assign_table").find("tr:gt(0)").filter(":visible").sortElements(function (a, b) {
  7929. return parseInt($(a).attr("fieldAmount"), 10) < parseInt($(b).attr("fieldAmount"), 10) ? 1 : -1;
  7930. });
  7931. }
  7932. });
  7933. }
  7934.  
  7935. filterGroupRows(
  7936. function (row, tag) {
  7937. var compareVillage = getVillageFromCoords(row.find("td:first").text());
  7938. tag.distance = getDistance(targetVillage.x, compareVillage.x, targetVillage.y, compareVillage.y, 'ram').fields;
  7939. return tag.distance > maxDistance;
  7940.  
  7941. }, reverseFilter,
  7942. function (mainRow, tag) {
  7943. mainRow.attr("fieldAmount", tag.distance);
  7944. if (!isAlreadyVisible) {
  7945. mainRow.find("td:first").after("<td><b>" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + "</b></td>");
  7946. } else {
  7947. mainRow.find("td:eq(1)").html("<b>" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + "</b>");
  7948. }
  7949. }, { distance: 0 });
  7950. });
  7951.  
  7952. // Filter on incoming attacks
  7953. $("#attackFilter").click(function () {
  7954. trackClickEvent("FilterUnderAttack");
  7955. filterGroupRows(function (row) {
  7956. return $('td:first:not(:has(img[title=\'' + trans.tw.command.attack + '\']))', row).size() == 0;
  7957. });
  7958. });
  7959.  
  7960. // filter on village name
  7961. $("#defFilterText").click(function () {
  7962. trackClickEvent("FilterText");
  7963. var compareTo = $("#defFilterTextValue").val().toLowerCase();
  7964. if (compareTo.length > 0) {
  7965. filterGroupRows(function (row) {
  7966. return row.find("td:first").text().toLowerCase().indexOf(compareTo) != -1;
  7967. });
  7968. }
  7969. });
  7970.  
  7971. // filter on group names
  7972. $("#defFilterGroup").click(function () {
  7973. trackClickEvent("FilterGroupName");
  7974. var compareTo = $("#defFilterGroupValue").val().toLowerCase();
  7975. if (compareTo.length > 0) {
  7976. filterGroupRows(function (row) {
  7977. return row.find("td:eq(4)").text().toLowerCase().indexOf(compareTo) != -1;
  7978. });
  7979. }
  7980. });
  7981.  
  7982. $("#defFilterContinent").click(function () {
  7983. trackClickEvent("FilterContinent");
  7984. var compareTo = parseInt($("#defFilterContinentText").val(), 10);
  7985. if (compareTo >= 0) {
  7986. compareTo = compareTo.toString();
  7987. filterGroupRows(function (row) {
  7988. var villageContinent = $.trim(row.find("td:first").text()),
  7989. continentStart = villageContinent.lastIndexOf(trans.tw.all.continentPrefix);
  7990.  
  7991. return villageContinent.substr(continentStart + 1) === compareTo;
  7992. });
  7993. }
  7994. });
  7995.  
  7996. // filter on # groups
  7997. $("#defFilterAmount").click(function (){
  7998. trackClickEvent("FilterGroupCount");
  7999. var compareTo = parseInt($("#defFilterAmountText").val(), 10);
  8000. if (compareTo >= 0) {
  8001. if (!$("#defReverseFilter").is(":checked")) {
  8002. filterGroupRows(
  8003. function (row) {
  8004. return parseInt(row.find("td:eq(1)").text(), 10) > compareTo;
  8005. },
  8006. false);
  8007. } else {
  8008. filterGroupRows(
  8009. function (row) {
  8010. return parseInt(row.find("td:eq(1)").text(), 10) < compareTo;
  8011. },
  8012. false);
  8013. }
  8014. }
  8015. });
  8016.  
  8017. $("#defFilterPoints").click(function () {
  8018. trackClickEvent("FilterPoints");
  8019. var compareTo = parseInt($("#defFilterPointsText").val(), 10);
  8020. if (compareTo >= 0) {
  8021. filterGroupRows(function (row) {
  8022. return parseInt(row.find("td:eq(2)").text().replace(".", ""), 10) < compareTo;
  8023. });
  8024. }
  8025. });
  8026.  
  8027. $("#defFilterFarm").click(function () {
  8028. trackClickEvent("FilterFarm");
  8029. var compareTo = parseInt($("#defFilterFarmText").val(), 10);
  8030. if (compareTo >= 0) {
  8031. filterGroupRows(function (row) {
  8032. var farmValue = row.find("td:eq(3)").text();
  8033. farmValue = parseInt(farmValue.substr(0, farmValue.indexOf("/")), 10);
  8034. return farmValue < compareTo;
  8035. });
  8036. }
  8037. });
  8038. } catch (e) { handleException(e, "overview-groups"); }
  8039. //console.timeEnd("overview-groups");
  8040. }());
  8041. }
  8042. // SUPPORT OVERVIEW
  8043. else if (location.href.indexOf('type=support_detail') > -1
  8044. || location.href.indexOf('type=away_detail') > -1) {
  8045.  
  8046. (function() {
  8047. //console.time("overview-supportdetail");
  8048. try {
  8049. overviewTable = $("#units_table");
  8050. tableHandler.init("units_table", {
  8051. hasBottomTotalRow: true
  8052. });
  8053.  
  8054. /**
  8055. * true: we're on the support_detail page. false: away_detail page
  8056. * @type {boolean}
  8057. */
  8058. var isSupport = location.href.indexOf('type=support_detail') > -1;
  8059.  
  8060. /**
  8061. * Sets the correct rowcount in the first header cell
  8062. */
  8063. function setTotalCount() {
  8064. $("th:first", overviewTable).text(
  8065. trans.sp.defOverview.totalVillages.replace(
  8066. "{0}",
  8067. $("tr.units_away", overviewTable).size()));
  8068. }
  8069.  
  8070.  
  8071. var menu = "<table class='vis' width='100%'>";
  8072. menu += "<tr><th width='1%' nowrap>";
  8073. menu += "<input type=button id=defTotals value='" + trans.sp.defOverview.stackButton + "' title='" + trans.sp.defOverview.stackTooltip + "'>";
  8074. menu += "<input type=button id=defHideEmpty value='" + trans.sp.defOverview.filterNoSupport + "' title='" + trans.sp.defOverview.filterNoSupportTooltip + "'> ";
  8075.  
  8076. menu += "</th><th width='96%' nowrap>";
  8077. menu += "<input type=button id=attackFilter value='" + trans.sp.defOverview.filterUnderAttack + "'>";
  8078. if (!isSupport) {
  8079. menu += "&nbsp; <input type=button id=defFilterBarbarian value='" + trans.sp.defOverview.barbarianFilter + "' title='" + trans.sp.defOverview.barbarianFilterTooltip + "'>";
  8080. } else {
  8081. menu += "</th><th width='1%' nowrap>";
  8082. menu += "<input type=text size=8 id=defFilterTotalPopValue value='" + user_data.restack.defaultPopulationFilterAmount + "'>";
  8083. menu += "<select id=defFilterTotalPopComparer>";
  8084. menu += "<option value=-1>" + trans.sp.all.less + "</option><option value=1 selected>" + trans.sp.all.more + "</option></select>";
  8085. menu += "<input type=button id=defFilterTotalPop value='" + trans.sp.defOverview.stackFilter + "' title='" + trans.sp.defOverview.stackFilterTooltip + "'>";
  8086.  
  8087. menu += "</th><th width='1%' nowrap>";
  8088. menu += trans.sp.defOverview.village + " <input type=text size=5 id=defFilterDistVillage value=''>";
  8089. menu += "<select id=defFilterDistType>";
  8090. menu += "<option value=1 selected>" + trans.sp.all.closer + "</option><option value=-1>" + trans.sp.all.further + "</option></select>";
  8091. // TODO: untranslated F(ields)
  8092. menu += "&nbsp;F <input type=text size=3 id=defFilterDistanceValue value=" + user_data.restack.fieldsDistanceFilterDefault + ">";
  8093. menu += "<input type=button id=defFilterDist value='" + trans.sp.defOverview.distFilter + "' title='" + trans.sp.defOverview.distFilterTooltip + "'>";
  8094.  
  8095. menu += "</th><th width='1%' nowrap>";
  8096. 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 + "'>";
  8097. //menu += "</th></tr></table>";
  8098. }
  8099.  
  8100. menu += "</th></tr></table>";
  8101. menu += "<table class='vis' width='100%'><tr><th width='1%' nowrap>";
  8102. menu += isSupport ? trans.sp.defOverview.extraFiltersSupport : trans.sp.defOverview.extraFiltersDefense;
  8103.  
  8104. menu += "</th><th width='1%' nowrap>";
  8105. menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.defOverview.extraFiltersReverse + "'" + (user_data.restack.filterReverse ? " checked" : "") + "> " + trans.sp.defOverview.extraFiltersInfo;
  8106.  
  8107. menu += "</th><th width='1%' nowrap>";
  8108. menu += "<input type=text size=3 id=defFilterDistanceValue value=" + user_data.restack.fieldsDistanceFilterDefault + "> <input type=button id=defFilterDistance value='" + trans.sp.defOverview.distFilter2 + "'>";
  8109.  
  8110. menu += "</th><th width='1%' nowrap>";
  8111. menu += "&nbsp; <span style='background-color: #ecd19a; border: 1px solid black' id='unitFilterBox'>";
  8112. menu += "&nbsp; <img src='graphic/unit/unit_snob.png' id=filtersnob>&nbsp; <img src='graphic/unit/unit_spy.png' id=filterspy>";
  8113. menu += "&nbsp; <img src='graphic/buildings/barracks.png' id=filterAttack>&nbsp;<img src='graphic/unit/def.png' id=filterDefense>&nbsp;<img id=filterSupport src='graphic/command/support.png'>&nbsp;";
  8114. menu += "</span>&nbsp;&nbsp;";
  8115.  
  8116. menu += "</th><th width='96%' nowrap>";
  8117. menu += "<input type=text size=12 id=defFilterTextValue value=''>";
  8118. menu += "<input type=button id=defFilterText value='" + trans.sp.defOverview.freeTextFilter + "'>";
  8119. menu += "</th></tr></table>";
  8120.  
  8121. overviewTable.before(menu);
  8122.  
  8123. $("#defReverseFilter").change(function () {
  8124. var isChecked = $(this).is(":checked");
  8125. var defTrans = trans.sp.defOverview;
  8126. $("#unitFilterBox").find("img:eq(0)").attr("title", isChecked ? defTrans.nobleFilter : defTrans.nobleFilterRev);
  8127. $("#unitFilterBox").find("img:eq(1)").attr("title", isChecked ? defTrans.spyFilter : defTrans.spyFilterRev);
  8128. $("#unitFilterBox").find("img:eq(2)").attr("title", isChecked ? defTrans.attackFilter : defTrans.attackFilterRev);
  8129. $("#unitFilterBox").find("img:eq(3)").attr("title", isChecked ? defTrans.supportFilter : defTrans.supportFilterRev);
  8130.  
  8131. $("#unitFilterBox").find("img:eq(4)").attr("title", (isSupport ? defTrans.otherPlayerFilterFrom : defTrans.otherPlayerFilterTo).replace("{action}", isChecked ? defTrans.otherPlayerFilterShow : defTrans.otherPlayerFilterHide));
  8132. $("#defFilterText").attr("title", defTrans.freeTextFilterTooltip.replace("{villageType}", isSupport ? defTrans.filterTooltipVillageTypeSupporting : defTrans.filterTooltipVillageTypeSupported).replace("{filterType}", isChecked ? defTrans.freeTextFilterTooltipFilterTypeWith : defTrans.freeTextFilterTooltipFilterTypeWithout));
  8133. $("#defFilterDistance").attr("title", defTrans.distanceFilterTooltip.replace("{villageType}", isSupport ? defTrans.filterTooltipVillageTypeSupporting : defTrans.filterTooltipVillageTypeSupported).replace("{filterType}", !isChecked ? defTrans.distanceFilterTooltipFilterTypeCloser : defTrans.distanceFilterTooltipFilterTypeFurther));
  8134. });
  8135. $("#defReverseFilter").change();
  8136. // This file contains the filters on the FIRST row of the menu
  8137.  
  8138. // UNDER ATTACK FILTER
  8139. $("#attackFilter").click(function () {
  8140. trackClickEvent("FilterAttack");
  8141. var reverseFilter = true; // never reverse this filter!
  8142.  
  8143. var filterStrategy =
  8144. function (row) {
  8145. return $('td:first:not(:has(img[title=\'' + trans.tw.command.attack + '\']))', row).size() == 0;
  8146. };
  8147.  
  8148. var lastRow = $("tr:last", overviewTable).get(0);
  8149. var goners = $();
  8150. $("tr.units_away", overviewTable).each(function () {
  8151. var self = $(this);
  8152. if (!reverseFilter != !filterStrategy(self)) {
  8153. goners = goners.add(self);
  8154.  
  8155. var nextRow = self.next();
  8156. while (!nextRow.hasClass("units_away") && nextRow.get(0) !== lastRow) {
  8157. goners = goners.add(nextRow);
  8158. nextRow = nextRow.next();
  8159. }
  8160. }
  8161. });
  8162. goners.remove();
  8163. setTotalCount();
  8164.  
  8165. // this is already done in the code above :)
  8166. //$("#defHideEmpty").click();
  8167.  
  8168. if (user_data.restack.calculateDefTotalsAfterFilter
  8169. && !$("#defTotals").is(":disabled")) {
  8170.  
  8171. $("#defTotals").click();
  8172. }
  8173. });
  8174.  
  8175.  
  8176.  
  8177. /**
  8178. * Performs a filter on the OWN villages (ie not the villages supporting the OWN villages)
  8179. * The 'row' parameter are the rows with class grandTotal. These are the rows that get added after (below) all
  8180. * supporting os rows when the total def is being calculated.
  8181. * @param {function} filterStrategy return a boolean to filter all rows for the OWN away. first parameter is the (jQuery) row with the OWN village
  8182. * @param {boolean} reverseFilter reverse the above strategy
  8183. * @param {function} [survivorRowStrategy] execute on all rows that are not being removed (gets passed the row and optional tag)
  8184. * @param {*} [tag] this value is passed onto filterStrategy and survivorRowStrategy as the second parameter (row is the first param)
  8185. */
  8186. function filterMainRows(filterStrategy, reverseFilter, survivorRowStrategy, tag) {
  8187. if (!$("#defTotals").is(":disabled")) {
  8188. $("#defTotals").click();
  8189. }
  8190.  
  8191. /*var goners = $();
  8192. $("tr.grandTotal", overviewTable).each(function () {
  8193. var self = $(this),
  8194. prev;
  8195. if (!reverseFilter != !filterStrategy(self, tag)) {
  8196. goners = goners.add(self).add(self.next());
  8197.  
  8198. prev = self.prev();
  8199. while (!prev.hasClass("units_away")) {
  8200. goners = goners.add(prev);
  8201. prev = prev.prev();
  8202. }
  8203.  
  8204. goners = goners.add(prev);
  8205. } else if (survivorRowStrategy != null) {
  8206. prev = self.prev();
  8207. while (!prev.hasClass("units_away")) {
  8208. prev = prev.prev();
  8209. }
  8210. survivorRowStrategy(prev, tag);
  8211. }
  8212. });
  8213. goners.remove();
  8214. setTotalCount();*/
  8215.  
  8216. var lastRow = $("tr:last", overviewTable).get(0);
  8217. var goners = $();
  8218. $("tr.units_away", overviewTable).each(function () {
  8219. var self = $(this);
  8220. if (!reverseFilter != !filterStrategy(self, tag)) {
  8221. goners = goners.add(self);
  8222.  
  8223. var nextRow = self.next();
  8224. while (!nextRow.hasClass("units_away") && nextRow.get(0) !== lastRow) {
  8225. goners = goners.add(nextRow);
  8226. nextRow = nextRow.next();
  8227. }
  8228. }
  8229. else if (survivorRowStrategy != null) {
  8230. /*prev = self.prev();
  8231. while (!prev.hasClass("units_away")) {
  8232. prev = prev.prev();
  8233. }*/
  8234. survivorRowStrategy(self, tag);
  8235. }
  8236. });
  8237. goners.remove();
  8238. setTotalCount();
  8239. }
  8240.  
  8241.  
  8242.  
  8243. // filter the OWN villages on less/more population (requires total calculation)
  8244. $("#defFilterTotalPop").click(function () {
  8245. trackClickEvent("FilterFarm");
  8246. var reverseFilter = $("#defFilterTotalPopComparer").val() != "-1";
  8247. var compareTo = parseInt($("#defFilterTotalPopValue").val(), 10);
  8248.  
  8249. filterMainRows(
  8250. //q(row.attr("village") + "is:" + row.attr("population"));
  8251. function (row) { return (parseInt(row.attr("population"), 10) > compareTo); },
  8252. reverseFilter);
  8253. });
  8254.  
  8255. // filter the OWN villages on less/more distance to given coordinates (requires total calculation)
  8256. $("#defFilterDist").click(function () {
  8257. var targetVillage = getVillageFromCoords($("#defFilterDistVillage").val(), true);
  8258. if (!targetVillage.isValid) {
  8259. alert(trans.sp.defOverview.distanceToVillageNoneEntered);
  8260. return;
  8261. }
  8262.  
  8263. trackClickEvent("FilterDistanceToX");
  8264. var reverseFilter = !($("#defFilterDistType").val() != "-1");
  8265. var maxDistance = parseInt($("#defFilterDistanceValue").val(), 10);
  8266.  
  8267. // Change text of th cell to 'distance to ' + given village
  8268. overviewTable.find("th:eq(1)").html(
  8269. trans.sp.defOverview.distanceToVillage.replace(
  8270. "{0}",
  8271. "<a href='"
  8272. + getUrlString("&screen=map&x=" + targetVillage.x + "&y=" + targetVillage.y + "'>")
  8273. + targetVillage.coord + "</a>"));
  8274.  
  8275. filterMainRows(
  8276. function (row, tag) {
  8277. var compareVillage = getVillageFromCoords(row.attr("village"));
  8278. tag.distance = getDistance(targetVillage.x, compareVillage.x, targetVillage.y, compareVillage.y, 'ram').fields;
  8279. return tag.distance > maxDistance;
  8280. },
  8281. reverseFilter,
  8282. function (mainRow, tag) {
  8283. // Adds the distance between OWN village and the user given coordinates
  8284. mainRow.find("td:eq(1)").html("<b>" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + "</b>");
  8285. },
  8286. { distance: 0 });
  8287. });
  8288. // Calculate villages that don't have x population defense
  8289. // and create BBcodes textarea for it
  8290. $("#defRestack").click(function () {
  8291. trackClickEvent("BBCodeOutput");
  8292. if (!$("#defTotals").attr("disabled")) {
  8293. $("#defTotals").click();
  8294. }
  8295.  
  8296. var restackTo = parseInt($("#defRestackTo").val(), 10);
  8297. var counter = 0;
  8298.  
  8299. var request = "";
  8300. $("tr.grandTotal", overviewTable).each(function () {
  8301. var self = $(this);
  8302. var total = parseInt(self.attr('population'), 10);
  8303. if (restackTo - total > user_data.restack.requiredDifference) {
  8304. var villageCoords = self.attr("village");
  8305. counter++;
  8306. request += counter + "[village]" + villageCoords + "[/village] (" + parseInt((restackTo - total) / 1000, 10) + trans.sp.defOverview.thousandSuffix + ")\n";
  8307. }
  8308. });
  8309.  
  8310. if ($("#textsArea").size() == 0) {
  8311. $(this).parent().parent().parent().parent().after(
  8312. "<table class='vis' width='100%'><tr>"
  8313. + "<td id=textsArea width='50%' valign='top'></td>"
  8314. + "<td id='extraTextsArea' width='50%' valign='top'>"
  8315. + trans.sp.defOverview.freeText
  8316. + "<br><textarea cols=50 rows=9></textarea></td>"
  8317. + "</tr></table>");
  8318.  
  8319. $("#textsArea").parent().after("<tr><td colspan='2'><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea></td></tr>");
  8320. } else {
  8321. $("#textsArea").html("");
  8322. }
  8323.  
  8324. var title = trans.sp.troopOverview.restackTitle
  8325. .replace("{to}", parseInt(restackTo / 1000, 10))
  8326. .replace("{requiredDiff}", parseInt(user_data.restack.requiredDifference / 1000, 10));
  8327.  
  8328. $("#textsArea").append(title + "<br><textarea cols=50 rows=10 id=restackArea>" + request + "</textarea>");
  8329.  
  8330. $("#closeTextsArea").click(function() {
  8331. $("#textsArea").parent().parent().remove();
  8332. });
  8333. });
  8334. // Check all villages checkbox replacement
  8335. $("input.selectAll").replaceWith("<input type=checkbox id=selectAllVisible>");
  8336. $("#selectAllVisible").change(function () {
  8337. var isChecked = $(this).is(":checked");
  8338.  
  8339. $("input.village_checkbox:hidden", overviewTable).prop("checked", false);
  8340. $("input.village_checkbox:visible", overviewTable).prop("checked", isChecked);
  8341. });
  8342.  
  8343.  
  8344. // Hide all OWN rows/villages that don't have any support rows anymore
  8345. $("#defHideEmpty").click(function () {
  8346. trackClickEvent("FilterEmpty");
  8347. var goners = $();
  8348. if ($("#defTotals").is(":disabled")) {
  8349. $("tr.units_away", overviewTable).each(function () {
  8350. var mainRow = $(this),
  8351. nextRow = mainRow.next();
  8352.  
  8353. if (nextRow.hasClass("grandTotal")) {
  8354. goners = goners.add(mainRow).add(nextRow.next()).add(nextRow);
  8355. }
  8356. else if (nextRow.hasClass("units_away")) {
  8357. goners = goners.add(mainRow);
  8358. }
  8359. });
  8360. } else {
  8361. $("tr.units_away", overviewTable).each(function () {
  8362. var mainRow = $(this),
  8363. nextRow = mainRow.next();
  8364.  
  8365. if (nextRow.hasClass("units_away")) {
  8366. goners = goners.add(mainRow);
  8367. }
  8368. });
  8369. }
  8370.  
  8371. goners.remove();
  8372. setTotalCount();
  8373. });
  8374.  
  8375.  
  8376. // Calculate the amount of def in each village
  8377. // Give sensible background row colors
  8378. // Add attributes to the grandTotal class rows 'village' (coords) and 'population'
  8379. // Add attribute 'distance' the distance between OWN and supporting villages, in fields
  8380. $("#defTotals").click(function () {
  8381. trackClickEvent("FilterTotalDef");
  8382. $(this).attr("disabled", true);
  8383. var rowColor = 0;
  8384. var goners = $();
  8385. overviewTable.find("tr.units_away").each(function () {
  8386. var self = $(this);
  8387. var firstCell = self.find("td:first");
  8388. var villageCoord = getVillageFromCoords(firstCell.text().replace(firstCell.find(".quickedit-label").attr("data-text"), ""));
  8389.  
  8390. // ensure row color swapping for each own village
  8391. rowColor++;
  8392. if (rowColor % 2 == 1) {
  8393. self.removeClass("row_a").addClass("row_b");
  8394. } else {
  8395. self.removeClass("row_b").addClass("row_a");
  8396. }
  8397.  
  8398. // village attribute both to .units_away and .grandTotal rows ;)
  8399. self.attr("village", villageCoord.coord);
  8400.  
  8401. var nextRow = self.next();
  8402. if (nextRow.hasClass("units_away")) {
  8403. if (user_data.restack.removeRowsWithoutSupport) {
  8404. goners = goners.add(self);
  8405. }
  8406. } else {
  8407. // calculate total support
  8408. var grandTotal = 0;
  8409. var totals = [];
  8410. while (nextRow.hasClass("row_a") || nextRow.hasClass("row_b")) {
  8411. // supporting rows loop
  8412. var total = 0;
  8413. $("td:gt(0)", nextRow).each(function (i) {
  8414. // total support per supporting village
  8415. var cellSelf = $(this);
  8416. var cellContent = $.trim(cellSelf.text());
  8417. if (!(cellContent == '0' || i >= world_data.unitsPositionSize.length)) {
  8418. total += cellContent * world_data.unitsPositionSize[i];
  8419. if (totals[i] == undefined) {
  8420. totals[i] = parseInt(cellContent, 10);
  8421. } else {
  8422. totals[i] += parseInt(cellContent, 10);
  8423. }
  8424. }
  8425. });
  8426. grandTotal += total;
  8427. $("td:eq(" + (world_data.unitsPositionSize.length + 1) + ")", nextRow).text(formatNumber(total));
  8428.  
  8429. // print distance between own village
  8430. var supportedCell = $("td:first", nextRow);
  8431. var supportedVillage = getVillageFromCoords(supportedCell.text());
  8432. var distance = parseInt(getDistance(supportedVillage.x, villageCoord.x, supportedVillage.y, villageCoord.y, 'ram').fields, 10);
  8433. //supportedCell.html(supportedCell.html() + ' <b>' + trans.sp.all.fieldsSuffix.replace("{0}", distance) + '</b>');
  8434. supportedCell.append(' <b>' + trans.sp.all.fieldsSuffix.replace("{0}", distance) + '</b>');
  8435. nextRow.attr("distance", distance);
  8436.  
  8437. if (rowColor % 2 == 1) {
  8438. nextRow.removeClass("row_a").addClass("row_b");
  8439. } else {
  8440. nextRow.removeClass("row_b").addClass("row_a");
  8441. }
  8442.  
  8443. nextRow = nextRow.next();
  8444. }
  8445.  
  8446. // row colors for the support villages
  8447. if (rowColor % 2 == 1) {
  8448. nextRow.removeClass("row_a").addClass("row_b");
  8449. } else {
  8450. nextRow.removeClass("row_b").addClass("row_a");
  8451. }
  8452.  
  8453. var troopCells = "";
  8454. for (var i = 0; i < world_data.unitsPositionSize.length; i++) {
  8455. if (typeof totals[i] !== 'undefined') {
  8456. troopCells += "<td>" + formatNumber(totals[i]) + "</td>";
  8457. } else {
  8458. troopCells += "<td><span class=hidden>0</span></td>";
  8459. }
  8460. }
  8461.  
  8462. self.attr("population", grandTotal);
  8463. var color = getStackColor(grandTotal);
  8464. color = "<td style='background-color: " + color + "; border:1px solid black'>" + formatNumber(grandTotal) + "</td>";
  8465.  
  8466. nextRow.before("<tr class='grandTotal " + (rowColor % 2 == 1 ? "row_b" : "row_a") + "' village='" + villageCoord.coord + "' population='" + grandTotal + "'><td>&nbsp;</td><td>" + (isSupport ? trans.sp.defOverview.totalFromOtherVillages : trans.sp.defOverview.totalInOtherVillages) + "</td>" + troopCells + color + "</tr><tr height=10></tr>");
  8467. }
  8468. });
  8469.  
  8470. goners.remove();
  8471. });
  8472. // This file contains the filters on the SECOND row of the menu
  8473.  
  8474. /**
  8475. * Loops over all supporting rows and removes the rows that fail the filterStrategy predicate. Where the
  8476. * filterMainRows function loops over the OWN villages, this one loops over all the others.
  8477. * @param {Function} filterStrategy gets each jQuery row that represents a supporting village passed as parameter
  8478. * @param {string=after} [calcDefTotalsTime] is "before" or "after". before if it uses row attributes set by #defTotals
  8479. */
  8480. function filterTable(filterStrategy, calcDefTotalsTime) {
  8481. if (typeof calcDefTotalsTime === 'undefined') {
  8482. calcDefTotalsTime = "after";
  8483. }
  8484. if (calcDefTotalsTime === "before" && !$("#defTotals").is(":disabled")) {
  8485. $("#defTotals").click();
  8486. }
  8487. var totalDefCalced = $("#defTotals").is(":disabled");
  8488.  
  8489. var reverseFilter = $("#defReverseFilter").is(":checked");
  8490. var goners = $();
  8491. $("tr", overviewTable).slice(1).each(function () {
  8492. var self = $(this);
  8493. if ((totalDefCalced && self.attr("distance"))
  8494. || (!totalDefCalced && (self.hasClass("row_a") || self.hasClass("row_b")))) {
  8495.  
  8496. if (!reverseFilter != !filterStrategy(self)) {
  8497. goners = goners.add(self);
  8498. }
  8499. }
  8500. });
  8501. goners.remove();
  8502. setTotalCount();
  8503. if (user_data.restack.autohideWithoutSupportAfterFilter) {
  8504. $("#defHideEmpty").click();
  8505. }
  8506.  
  8507. if (user_data.restack.calculateDefTotalsAfterFilter
  8508. && calcDefTotalsTime === "after"
  8509. && !$("#defTotals").is(":disabled")) {
  8510.  
  8511. $("#defTotals").click();
  8512. }
  8513. }
  8514.  
  8515.  
  8516.  
  8517.  
  8518.  
  8519. // NOBLES and SCOUTS
  8520. $("#filtersnob, #filterspy").click( function () {
  8521. trackClickEvent("FilterSnobOrSpy");
  8522. var position = $.inArray($(this).attr("id").substr(6), world_data.units) + 1;
  8523. filterTable(function (row) {
  8524. return row.find("td").eq(position).text() != "0";
  8525. });
  8526. });
  8527.  
  8528. // OTHER PLAYERS SUPPORT
  8529. $("#filterSupport").click( function () {
  8530. trackClickEvent("FilterSupport");
  8531. filterTable(function (row) {
  8532. return row.find("td:first a").length != 2;
  8533. });
  8534. });
  8535.  
  8536. // DEFENSIVE & OFFENSIVE UNITS
  8537. $("#filterAttack, #filterDefense").click( function () {
  8538. trackClickEvent("FilterOffOrDef");
  8539. var unitArray = $(this).attr('id') == "filterDefense" ? world_data.units_def : world_data.units_off;
  8540. filterTable(function (row) {
  8541. var hideRow = false;
  8542. $("td:gt(0)", row).each(function (i) {
  8543. if (world_data.units[i] != undefined
  8544. && world_data.units[i] != "heavy"
  8545. && parseInt($(this).text(), 10) > 0
  8546. && $.inArray(world_data.units[i], unitArray) > -1) {
  8547.  
  8548. hideRow = true;
  8549. return false;
  8550. }
  8551. });
  8552.  
  8553. return hideRow;
  8554. });
  8555. });
  8556.  
  8557. /// BARBARIAN VILLAGES filter
  8558. $("#defFilterBarbarian").click( function () {
  8559. trackClickEvent("FilterBarbarian");
  8560. filterTable(function (row) {
  8561. var text = row.find("td:first").text();
  8562. return text.match(/\(---\)\s+\(F\d+\)$/); // Unlocalized F(ields) string
  8563. });
  8564. });
  8565.  
  8566. // TEXT FILTER
  8567. $("#defFilterText").click( function () {
  8568. trackClickEvent("FilterText");
  8569. var compareTo = $("#defFilterTextValue").val().toLowerCase();
  8570. if (compareTo.length > 0)
  8571. filterTable(function (row) {
  8572. return row.text().toLowerCase().indexOf(compareTo) == -1;
  8573. });
  8574. });
  8575.  
  8576. // DISTANCE between OWN and supporting village
  8577. $("#defFilterDistance").click(function () {
  8578. trackClickEvent("FilterDistance");
  8579. var maxDistance = $("#defFilterDistanceValue").val();
  8580. filterTable(
  8581. function (row) {
  8582. var distance = $(row).attr("distance");
  8583. return (distance != '' && parseInt(distance, 10) < maxDistance);
  8584. },
  8585. "before");
  8586. });
  8587.  
  8588. } catch (e) { handleException(e, "overview-supportdetail"); }
  8589. //console.timeEnd("overview-supportdetail");
  8590. }());
  8591. }
  8592. // COMMANDS OVERVIEW
  8593. else if (location.href.indexOf('mode=commands') > -1) {
  8594. (function() {
  8595. //console.time("overview-commands");
  8596. try {
  8597. overviewTable = $("#commands_table");
  8598. tableHandler.init("commands_table", {
  8599. hasBottomTotalRow: true
  8600. });
  8601.  
  8602. var commandListType = getQueryStringParam("type");
  8603.  
  8604. var menu = "";
  8605. menu += "<table class=vis width='100%'>";
  8606. menu += "<tr>";
  8607. if (location.href.indexOf('type=all') > -1 || location.href.indexOf('&type=') == -1) {
  8608. menu += "<th width='1%'>";
  8609. menu += "<input type=button id=filterReturning value='" + trans.sp.commands.filterReturn + "' title=\"" + trans.sp.commands.filterReturnTooltip + "\">";
  8610. menu += "</th>";
  8611. }
  8612.  
  8613. menu += "<th width='1%' nowrap>";
  8614. menu += "<input type=checkbox id=sortSum " + (user_data.command.sumRow ? "checked" : "") + "> " + trans.sp.commands.totalRows + " ";
  8615. var isSupport = location.href.indexOf('type=support') > -1;
  8616. menu += "<input type=button id=sortIt value='" + trans.sp.commands.group + "'>";
  8617.  
  8618. menu += "</th><th width='98%'>";
  8619.  
  8620. menu += "<input type=button id=BBCodeOutput value='" + trans.sp.commands.bbCodeExport + "' title='" + trans.sp.commands.bbCodeExportTooltip + "'>";
  8621.  
  8622. if (commandListType !== "attack" && commandListType !== "return") {
  8623. menu += "&nbsp; &nbsp;";
  8624. menu += "<input type=text id=supportPlayerName size=>&nbsp;";
  8625. menu += "<input type=button id=supportPlayerExport value='" + trans.sp.commands.supportPlayerExport + "' title='" + trans.sp.commands.supportPlayerExportTooltip + "'>";
  8626. }
  8627.  
  8628. menu += "</th></tr></table>";
  8629.  
  8630. // second row
  8631. menu += "<table><tr><th width='1%' nowrap>";
  8632. menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": ";
  8633.  
  8634. menu += "</th><th width='1%' nowrap>";
  8635. menu += "<span style='background-color: #ecd19a; border: 1px solid black' id='unitFilterBox'>";
  8636. menu += "&nbsp; <img src='graphic/unit/unit_snob.png' id=filtersnob>&nbsp; <img src='graphic/unit/unit_spy.png' id=filterspy>&nbsp; <img src='graphic/face.png' id=filterFake>&nbsp;";
  8637. menu += "&nbsp; </span>";
  8638.  
  8639. menu += "</th><th width='1%' nowrap>";
  8640. menu += "<input type=text size=12 id=defFilterTextValue value=''>";
  8641. menu += "<input type=button id=defFilterText value='" + trans.sp.commands.freeTextFilter + "'>";
  8642.  
  8643. menu += "</th><th width='97%' nowrap>";
  8644. menu += "<input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>";
  8645.  
  8646. menu += "</th></tr>";
  8647. menu += "</table>";
  8648. $("#commands_table").before(menu);
  8649.  
  8650. $("#select_all").replaceWith("<input type='checkbox' id='selectAll'>");
  8651. var selectAllCheckboxes = function() {
  8652. var isChecked = $("#selectAll").is(":checked");
  8653. $("#commands_table tr:visible").find(":checkbox").prop("checked", isChecked);
  8654. };
  8655. $("#selectAll").change(selectAllCheckboxes);
  8656.  
  8657. var offsetToUnits = 3;
  8658.  
  8659. $("#defReverseFilter").change( function () {
  8660. var isChecked = $(this).is(":checked");
  8661. var defTrans = trans.sp.commands;
  8662. $("#unitFilterBox").find("img:eq(0)").attr("title", !isChecked ? defTrans.nobleFilter : defTrans.nobleFilterRev);
  8663. $("#unitFilterBox").find("img:eq(1)").attr("title", isChecked ? defTrans.spyFilter : defTrans.spyFilterRev);
  8664. $("#unitFilterBox").find("img:eq(2)").attr("title", !isChecked ? defTrans.fakeFilter : defTrans.fakeFilterRev);
  8665.  
  8666. $("#defFilterContinent").attr("title", isChecked ? defTrans.continentFilterTooltip : defTrans.continentFilterTooltipReverse);
  8667.  
  8668. $("#defFilterText").attr("title", defTrans.freeTextFilterTooltip.replace("{filterType}", isChecked ? defTrans.freeTextFilterTooltipFilterTypeWith : defTrans.freeTextFilterTooltipFilterTypeWithout));
  8669. });
  8670.  
  8671. $("#defReverseFilter").change();
  8672. var hasGrouped = false;
  8673.  
  8674. // generate bb code or JSON (for player os) export
  8675. $("#BBCodeOutput,#supportPlayerExport").click(function () {
  8676. trackClickEvent($(this).attr("id"));
  8677. var villages = [];
  8678. var request = {};
  8679. var filter = hasGrouped ? "tr.command" : "tr:gt(0)";
  8680. $("#commands_table " + filter).filter(":visible").each(function () {
  8681. var row = $(this);
  8682. var cells = $("td", row);
  8683. var firstCell = cells.first();
  8684. var commandType = firstCell.find("img:first").attr("src");
  8685.  
  8686. if (typeof commandType !== 'undefined'
  8687. && commandType.indexOf("command/cancel.png") == -1
  8688. && commandType.indexOf("command/other_back.png") == -1
  8689. && commandType.indexOf("command/back.png") == -1
  8690. && commandType.indexOf("command/return.png") == -1) {
  8691.  
  8692. // We get the village coords from the description of the command
  8693. // Meaning if the user changes the name to "blabla" that we can't parse it
  8694. var village = getVillageFromCoords($.trim(firstCell.text()));
  8695. //assert(village.isValid, $.trim(firstCell.text()) + " could not be converted to village");
  8696. if (village.isValid) {
  8697. if (request[village.coord] == undefined) {
  8698. request[village.coord] = { village: village.coord, attacks: [], hasSupport: false };
  8699. villages.push(village.coord);
  8700. }
  8701.  
  8702. var unitsSent = {};
  8703. $.each(world_data.units,
  8704. function (i, val) {
  8705. unitsSent[val] = parseInt(cells.eq(offsetToUnits + i).text(), 10);
  8706. });
  8707.  
  8708. var isSupport = false;
  8709. if (commandListType == "support") {
  8710. isSupport = true;
  8711. }
  8712. else if (commandListType == "attack") {
  8713. isSupport = false;
  8714. } else {
  8715. isSupport = cells.first().has("img[src*='command/support.png']").size() == 1;
  8716. }
  8717.  
  8718. request[village.coord].hasSupport = isSupport;
  8719. request[village.coord].attacks.push({
  8720. isSupport: isSupport,
  8721. units: unitsSent,
  8722. unitsString: buildAttackString(null, unitsSent, null, isSupport, user_data.command.bbCodeExport.requiredTroopAmount),
  8723. commandName: isSupport ? $.trim(firstCell.text()) : "",
  8724. commandId: isSupport ? firstCell.find(":checkbox").attr("value") : null,
  8725. arrivalDate: getDateFromTodayTomorrowTW(cells.eq(2).text())
  8726. });
  8727. }
  8728. }
  8729. });
  8730.  
  8731. var exportWidgets = [];
  8732. if ($(this).attr("id") === "BBCodeOutput") {
  8733. var requestsPer500 = [""];
  8734. var requestComposed = "";
  8735. for (var i = 0; i < villages.length; i++) {
  8736. var currentVillage = request[villages[i]];
  8737. var currentText = "";
  8738. currentText += "[spoiler][code]";
  8739. var attackCount = 0;
  8740. var supportCount = 0;
  8741. var lastAttack = null;
  8742. var largestAttack = 0;
  8743. var totalPop = 0;
  8744. for (var attackId = 0; attackId < currentVillage.attacks.length; attackId++) {
  8745. var currentAttack = currentVillage.attacks[attackId];
  8746. if (currentAttack.isSupport) {
  8747. supportCount++;
  8748. $.each(world_data.units, function (i, val) {
  8749. totalPop += currentAttack.units[val] * world_data.unitsPositionSize[i];
  8750. });
  8751. } else {
  8752. attackCount++;
  8753. if (lastAttack == null || lastAttack < currentAttack.arrivalDate) {
  8754. lastAttack = currentAttack.arrivalDate;
  8755. }
  8756. }
  8757. if (largestAttack < currentAttack.unitsString.length) {
  8758. largestAttack = currentAttack.unitsString.length;
  8759. }
  8760. }
  8761.  
  8762. for (var attackId = 0; attackId < currentVillage.attacks.length; attackId++) {
  8763. var currentAttack = currentVillage.attacks[attackId];
  8764. currentText += currentAttack.unitsString;
  8765. var extraTabs = (largestAttack - currentAttack.unitsString.length) / 1;
  8766. if (Math.ceil(extraTabs) == extraTabs) {
  8767. extraTabs = Math.ceil(extraTabs);
  8768. }
  8769. for (var tabs = 0; tabs < extraTabs + 1; tabs++) {
  8770. currentText += " ";
  8771. }
  8772.  
  8773. currentText += "\t" + twDateFormat(currentAttack.arrivalDate, true) + "\n";
  8774. }
  8775. currentText += "[/code][/spoiler]\n";
  8776.  
  8777. var headerTemplate;
  8778. if (!currentVillage.hasSupport && attackCount !== 0) {
  8779. headerTemplate = trans.sp.commands.exportAttackHeader;
  8780. }
  8781. else if (currentVillage.hasSupport && attackCount === 0) {
  8782. headerTemplate = trans.sp.commands.exportDefenseHeader;
  8783. } else {
  8784. headerTemplate = trans.sp.commands.exportCompleteHeader;
  8785. }
  8786.  
  8787. requestComposed +=
  8788. headerTemplate
  8789. .replace("{#}", attackCount)
  8790. .replace("{support#}", supportCount)
  8791. .replace("{totalStack}", formatNumber(totalPop))
  8792. .replace("{lastAttack}", lastAttack !== null ? twDateFormat(lastAttack, true) : "")
  8793. .replace("{village}", "[village]" + villages[i] + "[/village]")
  8794. + "\n " + currentText;
  8795.  
  8796. // splits per 500 [ characters (limit in TW)
  8797. var amountBracket = requestsPer500[requestsPer500.length - 1].match(/\[/g);
  8798. if (amountBracket != null && (requestComposed.match(/\[/g).length + amountBracket.length > server_settings.allowedSquareBrackets)) {
  8799. requestsPer500.push("");
  8800. }
  8801. requestsPer500[requestsPer500.length - 1] += requestComposed;
  8802. requestComposed = "";
  8803. }
  8804.  
  8805. for (i = 0; i < requestsPer500.length; i++) {
  8806. exportWidgets.push("<textarea cols=80 rows=10 class=restackArea>" + requestsPer500[i] + "</textarea>");
  8807. }
  8808.  
  8809. } else {
  8810. // JSON export for player support
  8811. var exportAttacks = [],
  8812. playerName = $.trim($("#supportPlayerName").val()),
  8813. filter = playerName.length === 0
  8814. ? function(attackString) { return true; }
  8815. : function(attackString) { return attackString.indexOf(playerName) !== -1 };
  8816.  
  8817. for (var i = 0; i < villages.length; i++) {
  8818. var currentVillage = request[villages[i]];
  8819.  
  8820. if (currentVillage.hasSupport) {
  8821. for (var attackId = 0; attackId < currentVillage.attacks.length; attackId++) {
  8822. var currentAttack = currentVillage.attacks[attackId];
  8823. if (currentAttack.isSupport && filter(currentAttack.commandName)) {
  8824. exportAttacks.push({
  8825. commandName: currentAttack.commandName,
  8826. commandId: currentAttack.commandId
  8827. });
  8828. /*q(villages[i]);
  8829. q(currentVillage)
  8830. q(currentAttack);
  8831. q("---------------------");*/
  8832. }
  8833. }
  8834. }
  8835. }
  8836.  
  8837. if (exportAttacks.length > 0) {
  8838. exportWidgets.push("<textarea style='width: 96%' rows=10 class=restackArea>" + JSON.stringify(exportAttacks, null, 4) + "</textarea>");
  8839. } else {
  8840. alert(trans.sp.commands.exportNone);
  8841. }
  8842. }
  8843.  
  8844. if (exportWidgets.length > 0) {
  8845. if ($("#textsArea").size() == 0) {
  8846. $(this).parent().parent().parent().append("<tr><td id=textsArea colspan=3></td></tr>");
  8847. } else {
  8848. $("#textsArea").html("");
  8849. }
  8850. for (var i = 0; i < exportWidgets.length; i++) {
  8851. $("#textsArea").append(exportWidgets[i]);
  8852. }
  8853. $("#textsArea").append("<br><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>");
  8854. $("#closeTextsArea").click(function() {
  8855. $("#textsArea").parent().remove();
  8856. });
  8857. }
  8858. });
  8859.  
  8860. function filterCommandRows(filterStrategy) {
  8861. // return true to hidethe row; false keep row visible (without reverse filter checkbox)
  8862. var reverseFilter = $("#defReverseFilter").is(":checked");
  8863. var goners = $();
  8864. var filter = hasGrouped ? "tr.command" : "tr:gt(0)";
  8865. $("#commands_table " + filter).filter(":visible").each(function () {
  8866. if ($("th", this).size() != 0) {
  8867. // don't do anything anymore when on the total row
  8868. return;
  8869. }
  8870. if (!reverseFilter != !filterStrategy($(this))) {
  8871. goners = goners.add($(this));
  8872. $("input:eq(1)", this).val("");
  8873. }
  8874. });
  8875. goners.remove();
  8876.  
  8877. // Show totals
  8878. var amountOfCommandos = $("#commands_table " + filter).size();
  8879. if (hasGrouped) {
  8880. $("#commands_table tr.sumLine").hide();
  8881. } else {
  8882. amountOfCommandos--;
  8883. }
  8884.  
  8885. $("#commands_table th:first").text(trans.sp.commands.tableTotal.replace("{0}", amountOfCommandos));
  8886. $("#amountOfAttacks").text(amountOfCommandos);
  8887. if ($("#amountOfAttacks").size() == 1) {
  8888. $("#amountOfTargets").val("???");
  8889. }
  8890.  
  8891. $("#commands_table tr").not(":visible").find(":checkbox").prop("checked", false);
  8892. }
  8893.  
  8894. // Filter sent back, returning and cancelled commands
  8895. $("#filterReturning").click(function () {
  8896. $(this).attr("disabled", "disabled");
  8897. trackClickEvent("FilterReturning");
  8898. filterCommandRows( function (row) {
  8899. var firstCellImage = $("td:first img:first", row).attr("src");
  8900. return firstCellImage.indexOf("command/other_back.png") != -1
  8901. || firstCellImage.indexOf("command/back.png") != -1
  8902. || firstCellImage.indexOf("command/return.png") != -1
  8903. || firstCellImage.indexOf("command/cancel.png") != -1;
  8904. });
  8905. });
  8906.  
  8907. $("#defFilterText").click(function () {
  8908. trackClickEvent("FilterText");
  8909. var compareTo = $("#defFilterTextValue").val().toLowerCase();
  8910. if (compareTo.length > 0) {
  8911. filterCommandRows(function (row) {
  8912. return row.text().toLowerCase().indexOf(compareTo) == -1;
  8913. });
  8914. }
  8915. });
  8916.  
  8917. $("#filterspy").click(function () {
  8918. trackClickEvent("FilterSpy");
  8919. var position = $.inArray($(this).attr("id").substr(6), world_data.units);
  8920. filterCommandRows(function (row) {
  8921. if (row.find("td").eq(position + offsetToUnits).text() == "0") {
  8922. return false;
  8923. }
  8924. var totalScout = row.find("td").eq(position + offsetToUnits).text();
  8925.  
  8926. var cell = row.find("td:eq(" + (offsetToUnits - 1) + ")");
  8927. for (var i = 0; i < world_data.units.length; i++) {
  8928. cell = cell.next();
  8929. if (totalScout < cell.text()) {
  8930. return false;
  8931. }
  8932. }
  8933. return true;
  8934. });
  8935. });
  8936.  
  8937. $("#filtersnob").click(function () {
  8938. trackClickEvent("FilterSnob");
  8939. var position = $.inArray($(this).attr("id").substr(6), world_data.units) + offsetToUnits;
  8940. filterCommandRows(function (row) {
  8941. return row.find("td").eq(position).text() == "0";
  8942. });
  8943. });
  8944.  
  8945. $("#filterFake").click(function () {
  8946. trackClickEvent("FilterFake");
  8947. var maxPop = user_data.command.filterFakeMaxPop;
  8948. filterCommandRows(function (row) {
  8949. var total = 0;
  8950. var cell = row.find("td:eq(" + (offsetToUnits - 1) + ")");
  8951. for (var i = 0; i < world_data.units.length; i++) {
  8952. cell = cell.next();
  8953. total += parseInt(cell.text(), 10);
  8954.  
  8955. // An attack with a noble is (almost) never a fake:
  8956. if (i == world_data.units.length - 1 && cell.text() != "0") {
  8957. return false;
  8958. }
  8959.  
  8960. if (total > maxPop) {
  8961. return false;
  8962. }
  8963. }
  8964. return true;
  8965. });
  8966. });
  8967.  
  8968. $("#defFilterContinent").click(function () {
  8969. trackClickEvent("FilterContinent");
  8970. var continent = parseInt($("#defFilterContinentText").val(), 10);
  8971. if (!isNaN(continent)) {
  8972. filterCommandRows(function (row) {
  8973. var village = getVillageFromCoords(row.find("td:first").text());
  8974. var village2 = getVillageFromCoords(row.find("td:eq(1)").text());
  8975. if (!village.isValid || !village2.isValid) {
  8976. return true;
  8977. }
  8978. return village.continent() != continent && village2.continent() != continent;
  8979. });
  8980. }
  8981. });
  8982.  
  8983. // Sort/group incoming attacks
  8984. $("#sortIt").click(function () {
  8985. trackClickEvent("Sort");
  8986. hasGrouped = true;
  8987. var newTable = "";
  8988. var targets = [];
  8989. var amountOfCommandos = 0;
  8990. var sum = $('#sortSum').is(':checked');
  8991. $("#filterReturning").attr("disabled", true);
  8992.  
  8993. $("#commands_table").find("tr:gt(0)").filter(":visible").each(function () {
  8994. var target = $.trim($(".quickedit-label", this).text());
  8995. var village = getVillageFromCoords(target);
  8996. if (village.isValid) {
  8997. amountOfCommandos++;
  8998. if (targets[village.coord] == undefined) {
  8999. targets.push(village.coord);
  9000. targets[village.coord] = new Array();
  9001. }
  9002. targets[village.coord].push($(this));
  9003. }
  9004. });
  9005.  
  9006. var mod = 0;
  9007. if (isSupport) {
  9008. $.each(targets, function (i, v) {
  9009. mod++;
  9010. var amount = 0;
  9011. var totalDef = new Array();
  9012. totalDef['pop'] = 0;
  9013. $.each(world_data.units, function (index, value) { totalDef[value] = 0; });
  9014.  
  9015. $.each(targets[v], function (index, value) {
  9016. var villageId = $("td:eq(1) a:first", value).attr("href").match(/id=(\d+)/)[1];
  9017. newTable += "<tr class='command nowrap row_" + (mod % 2 == 0 ? 'b' : 'a') + (villageId == game_data.village.id ? " selected" : "") + "'>" + value.html() + "</tr>";
  9018. amount++;
  9019.  
  9020. var unitAmounts = $("td:gt(2)", value);
  9021. $.each(world_data.units, function (iUnit, vUnit) {
  9022. var amount = parseInt(unitAmounts.eq(iUnit).html(), 10);
  9023. if (amount == 1) {
  9024. totalDef[vUnit] = amount;
  9025. } else {
  9026. totalDef[vUnit] += amount;
  9027. }
  9028. totalDef['pop'] += amount * world_data.unitsSize['unit_' + vUnit];
  9029. });
  9030. });
  9031.  
  9032. if (sum) {
  9033. newTable += "<tr class='sumLine'><td align=right colspan=3><b>" + trans.sp.commands.totalRowsText.replace("{0}", amount).replace("{1}", formatNumber(totalDef['pop'])) + "&nbsp;</b></td>";
  9034. $.each(world_data.units, function (iUnit, vUnit) {
  9035. newTable += "<td>" + (totalDef[vUnit] == 0 ? "&nbsp;" : formatNumber(totalDef[vUnit])) + "</td>";
  9036. });
  9037. newTable += "</tr>";
  9038. }
  9039. });
  9040. } else {
  9041. // attacks (meaning: no support commands)
  9042. $.each(targets, function (i, v) {
  9043. mod++;
  9044. var amount = 0;
  9045. var lastArrival = '';
  9046. $.each(targets[v], function (index, value) {
  9047. var villageId = $("td:eq(1) a:first", value).attr("href").match(/id=(\d+)/)[1];
  9048.  
  9049. var currentArrival = $(value).find("td:eq(2)").text();
  9050. if (lastArrival == currentArrival) {
  9051. // Don't show when it's on the same second
  9052. // Only practical on full second worlds really
  9053. newTable += "<tr class='command nowrap row_" + (mod % 2 == 0 ? 'b' : 'a') + (villageId == game_data.village.id ? " selected" : "") + "'>";
  9054. $(this).find("td").each(function (i) {
  9055. if (i == 2) {
  9056. newTable += "<td>&nbsp;</td>";
  9057. }
  9058. else if ($(this).text() == 0) {
  9059. newTable += "<td class=hidden>0</td>";
  9060. } else {
  9061. newTable += "<td>" + $(this).html() + "</td>";
  9062. }
  9063. });
  9064. newTable += "</tr>";
  9065. }
  9066. else {
  9067. newTable += "<tr class='command nowrap row_" + (mod % 2 == 0 ? 'b' : 'a') + (villageId == game_data.village.id ? " selected" : "") + "'>" + value.html() + "</tr>";
  9068. }
  9069. lastArrival = currentArrival;
  9070. amount++;
  9071. });
  9072.  
  9073. if (sum) {
  9074. newTable += "<tr class='sumLine'><td align=right colspan=" + (3 + world_data.units.length) + ">" + amount + "&nbsp;</td></tr>";
  9075. }
  9076. });
  9077. }
  9078.  
  9079. var menu = $("#commands_table tr").first().html(),
  9080. totalRow = $("#commands_table tr:last");
  9081. $("#commands_table").html("<table id='commands_table' class='vis'>" + menu + newTable + totalRow.outerHTML() + "</table>");
  9082. $("#selectAll").change(selectAllCheckboxes);
  9083.  
  9084. // total number of attacks
  9085. if ($("#amountOfAttacks").size() == 0) {
  9086. var totalDesc = (isSupport ? trans.sp.commands.totalSupport : trans.sp.commands.totalAttack);
  9087. var totalVillagesDesc = isSupport ? trans.sp.commands.totalVillagesSupport : trans.sp.commands.totalVillagesAttack;
  9088. var pageSize = $("input[name='page_size']");
  9089. if (pageSize.size() == 0) {
  9090. pageSize = $("input[type='submit']:last");
  9091. 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>");
  9092. } else {
  9093. pageSize[0].id = "amountOfTargets";
  9094. pageSize.parent().prev().text(totalVillagesDesc);
  9095. pageSize = pageSize.val(targets.length).parent().parent().parent();
  9096. pageSize.append('<tr><th colspan=2>' + totalDesc + ':</th><td id="amountOfAttacks">' + amountOfCommandos + '</td></tr>');
  9097. }
  9098. } else {
  9099. $("#amountOfTargets").val(targets.length);
  9100. $("#amountOfAttacks").text(amountOfCommandos);
  9101. }
  9102. });
  9103. } catch (e) { handleException(e, "overview-commands"); }
  9104. //console.timeEnd("overview-commands");
  9105. }());
  9106. }
  9107. // INCOMINGS OVERVIEW
  9108. else if (location.href.indexOf('mode=incomings') > -1) {
  9109. (function() {
  9110. //console.time("overview-incomings");
  9111. try {
  9112. overviewTable = $("#incomings_table");
  9113. tableHandler.init("incomings_table", {
  9114. hasBottomTotalRow: getQueryStringParam("subtype") !== "supports"
  9115. });
  9116.  
  9117. var table = {
  9118. /**
  9119. * Quick sort adds extra rows with the .total class
  9120. */
  9121. hasTotalRows: false,
  9122. /**
  9123. * Some buttons add extra columns
  9124. */
  9125. newColumns: {
  9126. before: 0,
  9127. after: 0
  9128. },
  9129. getColspan: function() {
  9130. return 7 + this.newColumns.before + this.newColumns.after;
  9131. },
  9132. /**
  9133. * Remove the total rows so that other filters can operate again
  9134. */
  9135. fixTable: function() {
  9136. if (this.hasTotalRows === true) {
  9137. overviewTable.find("tr.total").remove();
  9138. this.hasTotalRows = false;
  9139. }
  9140. },
  9141. getVillageRows: function() {
  9142. var rows = overviewTable.find("tr:gt(0)");
  9143. if (tableHandler.settings.hasBottomTotalRow) {
  9144. rows = rows.not("tr:last");
  9145. }
  9146. return rows;
  9147. },
  9148. /**
  9149. * Set the table total rows count correctly
  9150. * @param {number} rowCount
  9151. * @param {number} [villagesTargeted]
  9152. */
  9153. setTotals: function(rowCount, villagesTargeted) {
  9154. var amountOfCommandsHeaderCell = $("tr:first", overviewTable).find("th:first"),
  9155. amountOfRows = $("#amountOfRows");
  9156.  
  9157. assert(amountOfCommandsHeaderCell.length === 1, "couldn't find the command headercell");
  9158. amountOfCommandsHeaderCell.html(amountOfCommandsHeaderCell.html().replace(/\(\d+\)/, "(" + rowCount + ")"));
  9159.  
  9160. if (typeof villagesTargeted !== "undefined") {
  9161. if (amountOfRows.size() === 0) {
  9162. var pageSize = $("input[name='page_size']");
  9163. pageSize.parent().prev().text(trans.sp.commands.totalVillagesAttack);
  9164. pageSize = pageSize.attr("id", "villagesTargeted").parent().parent().parent();
  9165. pageSize.append('<tr><th colspan=2>' + trans.sp.incomings.amount + '</th><td id="amountOfRows">' + rowCount + '</td></tr>');
  9166. } else {
  9167. $("#amountOfRows").text(villagesTargeted);
  9168. $("#villagesTargeted").val(villagesTargeted);
  9169. }
  9170. }
  9171. }
  9172. };
  9173.  
  9174. var columnsToFilterCount = 5;
  9175.  
  9176. // build sangu menu
  9177. var menu = "";
  9178. menu += "<table width='100%' class='vis' id='sangu_menu'>";
  9179. menu += "<tr><th width='1%'>";
  9180. menu += "<input type=button id=sortIt value='" + trans.sp.incomings.dynamicGrouping + "' title='" + trans.sp.incomings.dynamicGroupingTooltip + "'>";
  9181. menu += "</th><th width='1%' nowrap>";
  9182. menu += "<input type=checkbox id=sortShowTotalRow " + (user_data.command.sumRow ? "checked" : "") + "> " + trans.sp.incomings.summation + " ";
  9183. menu += "<input type=button id=sortQuick value='" + trans.sp.incomings.fastGrouping + "' title='" + trans.sp.incomings.fastGroupingTooltip + "'>";
  9184. menu += "</th><th width='1%'>";
  9185.  
  9186. menu += "<input type=button id=sortByAttackId value='" + trans.sp.incomings.sortByAttackId + "' title='" + trans.sp.incomings.sortByAttackIdTooltip + "'>";
  9187.  
  9188. menu += "</th><th width='96%'>";
  9189. menu += "<input type=button id=filterAttack value='" + trans.sp.incomings.showNewIncomings + "'>";
  9190.  
  9191. menu += "</th><th width='1%' nowrap>";
  9192. menu += "<input type=button id=commandsImport value='" + trans.sp.incomings.commandsImport + "' title='" + trans.sp.incomings.commandsImportTooltip + "'>";
  9193. menu += "</th></tr>";
  9194. menu += "</table>";
  9195.  
  9196. // second row
  9197. menu += "<table width='100%' class=vis>";
  9198. menu += "<tr><th width='1%' nowrap>";
  9199.  
  9200. menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": ";
  9201. menu += "</th>";
  9202.  
  9203. // generate one input field/button filter with a select for the first cells
  9204. var defaultColumnFilters = (function() {
  9205. var headerCells = $("tr:first th", overviewTable),
  9206. cols = [],
  9207. headerCellText;
  9208.  
  9209. for (i = 0; i < columnsToFilterCount; i++) {
  9210. headerCellText = headerCells.eq(i).text();
  9211. if (headerCellText.indexOf(" ") !== -1) {
  9212. headerCellText = $.trim(headerCellText.substr(0, headerCellText.indexOf(" ")));
  9213. }
  9214. cols.push(headerCellText);
  9215. }
  9216. return cols;
  9217. }());
  9218.  
  9219. /**
  9220. * builds a textinput+select+button filter that filters rows based on table column index
  9221. */
  9222. function buildColumnFilter() {
  9223. var i,
  9224. defualtIndex = pers.get("incomingsColumnFilterIndex"),
  9225. menu = "<th width='99%' nowrap>";
  9226.  
  9227. menu += "<input type='text' size='20' id='filterColumnValue'>";
  9228. menu += "<select id='filterColumnIndex'>";
  9229. for (i = 0; i < defaultColumnFilters.length; i++) {
  9230. menu += "<option value='" + i + "'"
  9231. + (defualtIndex == i ? " selected" : "") + ">"
  9232. + defaultColumnFilters[i] + "</option>";
  9233. }
  9234. menu += "</select>";
  9235. menu += "<input type='button' id='filterColumn' value='"
  9236. + trans.sp.incomings.filterColumnButton + "'"
  9237. + "'>";
  9238. menu += "</th>";
  9239. return menu;
  9240. }
  9241.  
  9242. menu += buildColumnFilter();
  9243.  
  9244. //menu += "<th width='97%' nowrap>";
  9245. //menu += "<input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>";
  9246. //menu += "</th></tr>";
  9247.  
  9248.  
  9249. menu += "</table>";
  9250. overviewTable.before(menu);
  9251.  
  9252. $("#filterColumnIndex").change(function() {
  9253. pers.set("incomingsColumnFilterIndex", $("#filterColumnIndex").val());
  9254. });
  9255.  
  9256. // switch tooltips on reverse filter checkbox change
  9257. $("#defReverseFilter").change( function () {
  9258. var isChecked = $(this).is(":checked"),
  9259. overviewTrans = trans.sp.incomings;
  9260.  
  9261. //$("#").attr("title", isChecked ? overviewTrans.continentFilterTooltip : overviewTrans.continentFilterTooltipReverse);
  9262.  
  9263. $("#filterColumn").attr(
  9264. "title",
  9265. overviewTrans.filterColumnButtonTooltip.replace(
  9266. "{type}",
  9267. isChecked ? overviewTrans.filterColumnButtonTooltipHide : overviewTrans.filterColumnButtonTooltipShow));
  9268. }).change();
  9269.  
  9270.  
  9271. // select all checkbox
  9272. $("#select_all").replaceWith("<input type='checkbox' id='selectAll'>");
  9273. $("#selectAll").change(function() {
  9274. var isChecked = $("#selectAll").is(":checked");
  9275. $("tr", overviewTable).find(":checkbox").prop("checked", isChecked);
  9276. });
  9277. // IMPORT os exported by other player
  9278. $("#commandsImport").click(function() {
  9279. if ($("#textsArea").size() == 0) {
  9280. $(this).parent().parent().parent().append("<tr><td id=textsArea colspan=5></td></tr>");
  9281. $("#textsArea").append(
  9282. "<textarea cols=80 rows=10 id=commandImportText></textarea>"
  9283. + "<br>"
  9284. + "<input type=button value='" + trans.sp.incomings.commandsImport + "' id=commandsImportReal>"
  9285. + "<input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>");
  9286.  
  9287. $("#closeTextsArea").click(function() {
  9288. $("#textsArea").parent().remove();
  9289. });
  9290.  
  9291. $("#commandsImportReal").click(function() {
  9292. var commandsToImport;
  9293. try {
  9294. commandsToImport = JSON.parse($("#commandImportText").val());
  9295. var test = commandsToImport[0].commandName;
  9296. }
  9297. catch (e) {
  9298. alert(trans.sp.incomings.commandsImportError);
  9299. }
  9300.  
  9301. var amountReplaced = 0,
  9302. commandsSent = [],
  9303. i;
  9304.  
  9305. for (i = 0; i < commandsToImport.length; i++) {
  9306. commandsSent[commandsToImport[i].commandId] = commandsToImport[i].commandName;
  9307. }
  9308.  
  9309. table.getVillageRows().each(function () {
  9310. var firstCell = $("td:first", this),
  9311. commandId = firstCell.find(":input:first").attr("name");
  9312.  
  9313. //q("inputfield: " + firstCell.find(":input:first").length);
  9314. //q("commandId = " + commandId + " in cell: " + firstCell.text());
  9315.  
  9316. //assert(commandId, "couldn't find command id inputfield");
  9317. //assert(commandId.indexOf("command_ids") === 0, "inputfields have been renamed");
  9318. commandId = parseInt(commandId.match(/\d+/)[0], 10);
  9319. if (typeof commandsSent[commandId] !== 'undefined') {
  9320. var inputField = $(':input[id^="editInput"]', firstCell);
  9321. //assert(inputField.length === 1, "couldn't find the inputfield");
  9322. inputField.val(commandsSent[commandId]);
  9323. inputField.next().click();
  9324.  
  9325. amountReplaced++;
  9326. }
  9327. });
  9328.  
  9329. alert(trans.sp.incomings.commandsImportSuccess
  9330. .replace("{replaced}", amountReplaced)
  9331. .replace("{total}", commandsToImport.length));
  9332. });
  9333. }
  9334. });
  9335.  
  9336. // Sort by attack id (and add extra column)
  9337. $("#sortByAttackId").click(function() {
  9338. $(this).attr("disabled", true);
  9339. table.fixTable();
  9340. table.newColumns.after += 2;
  9341.  
  9342. var diffGroups = user_data.incomings.attackIdDescriptions;
  9343. function getFancyAttackIdDiffDescription(diff) {
  9344. var i;
  9345. for (i = 0; i < diffGroups.length; i++) {
  9346. if (diff < diffGroups[i].minValue) {
  9347. return diffGroups[i].text;
  9348. }
  9349. }
  9350.  
  9351. return user_data.incomings.attackIdHigherDescription;
  9352. }
  9353.  
  9354. // new column in header
  9355. tableHandler.overviewTable.find("tr:first").append("<th>"+trans.sp.incomings.attackId+"</th><th>"+trans.sp.incomings.attackIdDifference+"</th>");
  9356.  
  9357. var rows = table.getVillageRows();
  9358. rows.sortElements(function (rowA, rowB) {
  9359. var a = $("input:first", rowA).attr("name").match(/\d+/)[0];
  9360. var b = $("input:first", rowB).attr("name").match(/\d+/)[0];
  9361. //q($("input:first", rowA).attr("name") + "=>" + a);
  9362. return parseInt(a, 10) > parseInt(b, 10) ? 1 : -1;
  9363. });
  9364.  
  9365. var previousRowAttackId = 0;
  9366. rows.each(function() {
  9367. var attackId = parseInt($(this).find("input:first").attr("name").match(/\d+/)[0], 10),
  9368. diff = 0,
  9369. diffDescription = "&nbsp;";
  9370.  
  9371. if (previousRowAttackId != 0) {
  9372. diff = Math.abs(attackId - previousRowAttackId);
  9373. diffDescription = getFancyAttackIdDiffDescription(diff);
  9374. }
  9375. previousRowAttackId = attackId;
  9376.  
  9377. $(this).append("<td align=right>"+attackId+"</td><td>"+diffDescription+"</td>");
  9378. });
  9379. });
  9380.  
  9381. // QUICK sort: performs faster but also freezes the screen (ie no countdowns)
  9382. // --> This might also be good in case the page is refreshing too often otherwise
  9383. $("#sortQuick").click(function () {
  9384. trackClickEvent("SortQuick");
  9385. table.fixTable();
  9386. table.hasTotalRows = true;
  9387.  
  9388. var newTable = "";
  9389. var targets = [];
  9390. var commandCounter = 0;
  9391. var addTotalRow = $('#sortShowTotalRow').is(':checked');
  9392.  
  9393. table.getVillageRows().each(function () {
  9394. var target = $("td:eq(1)", this).text();
  9395. var village = getVillageFromCoords(target);
  9396. if (village.isValid) {
  9397. commandCounter++;
  9398. if (targets[village.coord] == undefined) {
  9399. targets.push(village.coord);
  9400. targets[village.coord] = [];
  9401. }
  9402. targets[village.coord].push($(this));
  9403. }
  9404. });
  9405.  
  9406. var mod = 0;
  9407. $.each(targets, function (i, v) {
  9408. mod++;
  9409. var rowColor = "row_" + (mod % 2 == 0 ? 'b' : 'a');
  9410. var amount = 0;
  9411. $.each(targets[v], function (index, row) {
  9412. var villageId = row.find("td:eq(1) a:first").attr("href").match(/village=(\d+)/)[1];
  9413. newTable += "<tr class='nowrap " + rowColor + "'"
  9414. + (villageId == game_data.village.id ? " selected" : "") + ">"
  9415. + row.html() + "</tr>";
  9416. amount++;
  9417. });
  9418.  
  9419. if (addTotalRow) {
  9420. if (amount === 1) {
  9421. newTable += "<tr class='" + rowColor + " total'><td align=right colspan=" + table.getColspan() + ">&nbsp;</td></tr>";
  9422. } else {
  9423. newTable += "<tr class='" + rowColor + " total'><td align=right colspan=" + table.getColspan() + "><b>" + trans.sp.incomings.amount + "&nbsp; " + amount + "</b>&nbsp; &nbsp;</td></tr>";
  9424. }
  9425. }
  9426. });
  9427.  
  9428. var menu = $("tr:first", overviewTable).html();
  9429. var totalRow = $("tr:last", overviewTable).html();
  9430. overviewTable.html("<table id='incomings_table' class='vis'>" + menu + newTable + totalRow + "</table>");
  9431.  
  9432. table.setTotals(commandCounter, targets.length);
  9433. });
  9434.  
  9435.  
  9436.  
  9437.  
  9438.  
  9439. // DYNAMIC sort incoming attacks
  9440. $("#sortIt").click(function () {
  9441. table.fixTable();
  9442. trackClickEvent("Sort");
  9443.  
  9444. var rows = table.getVillageRows();
  9445. rows.sortElements(function (a, b) {
  9446. a = getVillageFromCoords($("td:eq(1)", a).text());
  9447. b = getVillageFromCoords($("td:eq(1)", b).text());
  9448.  
  9449. return (a.x * 1000 + a.y) > (b.x * 1000 + b.y) ? 1 : -1;
  9450. });
  9451.  
  9452. var amountOfVillages = 0;
  9453. var current = "";
  9454. rows.each(function () {
  9455. var village = $("td:eq(1)", this);
  9456. if (current != village.text()) {
  9457. current = village.text();
  9458. amountOfVillages++;
  9459. }
  9460. var type = amountOfVillages % 2 == 0 ? 'row_a' : 'row_b';
  9461.  
  9462. var villageId = village.find("a:first").attr("href").match(/village=(\d+)/)[1];
  9463. this.className = "nowrap " + type + (villageId == game_data.village.id ? " selected" : "");
  9464. });
  9465.  
  9466. table.setTotals(rows.size(), amountOfVillages);
  9467. });
  9468. /**
  9469. *
  9470. * @param {function} filterStrategy return true to hidethe row; false keep row visible (without reverse filter checkbox)
  9471. * @param {Object} options
  9472. */
  9473. function filterVillageRows(filterStrategy, options) {
  9474. options = $.extend({}, {
  9475. checkboxReverses: true
  9476. }, options);
  9477.  
  9478. var reverseFilter = options.checkboxReverses && $("#defReverseFilter").is(":checked"),
  9479. goners = $(),
  9480. villageCounter = 0;
  9481.  
  9482. trackClickEvent(options.gaEventName);
  9483.  
  9484. table.fixTable();
  9485.  
  9486. table.getVillageRows().each(function () {
  9487. var self = $(this);
  9488. if (!reverseFilter != !filterStrategy(self)) {
  9489. goners = goners.add(self);
  9490. } else {
  9491. villageCounter++;
  9492. }
  9493. });
  9494. goners.remove();
  9495.  
  9496. // Show totals
  9497. table.setTotals(villageCounter);
  9498. }
  9499.  
  9500. // Show new attacks only
  9501. $("#filterAttack").click(function () {
  9502. var strategy = function(row) {
  9503. return $.trim($("td:first", row).text()) != trans.tw.command.attack;
  9504. };
  9505.  
  9506. filterVillageRows(strategy, {
  9507. gaEventName: "FilterNewAttacks",
  9508. checkboxReverses: false
  9509. });
  9510. });
  9511.  
  9512.  
  9513. // Filter rows on column 0 - 3 (command, target, origin, player)
  9514. $("#filterColumn").click(function() {
  9515. var filter = {
  9516. index: $("#filterColumnIndex").val(),
  9517. searchText: $.trim($("#filterColumnValue").val()).toLowerCase()
  9518. };
  9519.  
  9520. var filterStrategy = function(row) {
  9521. return row.find("td").eq(filter.index).text().toLowerCase().indexOf(filter.searchText) === -1;
  9522. };
  9523.  
  9524. filterVillageRows(filterStrategy, {
  9525. gaEventName: "column-" + $("#filterColumnIndex").text()
  9526. });
  9527. });
  9528.  
  9529.  
  9530. } catch (e) { handleException(e, "overview-incomings"); }
  9531. //console.timeEnd("overview-incomings");
  9532. }());
  9533. }
  9534.  
  9535. // make the editting groups box less wide
  9536. // and add alternating row colors
  9537. $("#edit_group_href").click(function () {
  9538. var groupTable = $("#group_list");
  9539. groupTable.width(300);
  9540.  
  9541. groupTable.find("th:first").attr("colspan", "3");
  9542. var mod = 0;
  9543. groupTable.find("tr:gt(0)").each(function () {
  9544. mod++;
  9545. $(this).addClass("row_" + (mod % 2 == 0 ? "a" : "b"));
  9546. });
  9547. });
  9548.  
  9549. // change troops overview link to active sangu page
  9550. if (user_data.command.changeTroopsOverviewLink) {
  9551. var troopsOverviewLink = $("#overview_menu a[href*='mode=units']");
  9552. troopsOverviewLink.attr("href", troopsOverviewLink.attr("href") + "&type=own_home");
  9553. }
  9554.  
  9555. if (user_data.overviews.addFancyImagesToOverviewLinks) {
  9556. var overviewLinks = $("#overview_menu a");
  9557. overviewLinks.each(function(index) {
  9558. var overviewLink = $(this),
  9559. imageToAdd = "";
  9560.  
  9561. switch (index) {
  9562. case 0:
  9563. // overviewLink.parent()
  9564. // .css("background-image", 'url("https://www.tribalwars.vodka/graphic/icons/header.png")')
  9565. // .css("background-repeat", "no-repeat")
  9566. // .css("background-position", "-324px 0px")
  9567. // .css("background-size", "200px Auto");
  9568. //
  9569. // overviewLink.prepend("&nbsp; &nbsp;");
  9570. break;
  9571. case 1:
  9572. imageToAdd = "graphic/buildings/storage.png";
  9573. break;
  9574. case 2:
  9575. imageToAdd = "graphic/buildings/market.png";
  9576. break;
  9577. case 3:
  9578. if (overviewLink.parent().hasClass("selected")) {
  9579. $("table.modemenu:last a", content_value).each(function(index) {
  9580. imageToAdd = "";
  9581. switch (index) {
  9582. case 1:
  9583. imageToAdd = "graphic/buildings/place.png";
  9584. break;
  9585. case 2:
  9586. imageToAdd = "graphic/pfeil.png";
  9587. break;
  9588. case 3:
  9589. case 4:
  9590. $(this).css("opacity", "0.5");
  9591. break;
  9592. case 5:
  9593. imageToAdd = "graphic/command/support.png";
  9594. break;
  9595. case 6:
  9596. imageToAdd = "graphic/rechts.png";
  9597. break;
  9598. }
  9599.  
  9600. if (imageToAdd !== "") {
  9601. $(this).prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text() + " &gt; " + $(this).text()+"' /> &nbsp;");
  9602. }
  9603. });
  9604. }
  9605.  
  9606. imageToAdd = "graphic/unit/unit_knight.png";
  9607. break;
  9608. case 4:
  9609. if (overviewLink.parent().hasClass("selected")) {
  9610. $("table.modemenu:last a", content_value).each(function(index) {
  9611. imageToAdd = "";
  9612. switch (index) {
  9613. case 1:
  9614. imageToAdd = "graphic/command/attack.png";
  9615. break;
  9616. case 2:
  9617. imageToAdd = "graphic/command/support.png";
  9618. break;
  9619. case 3:
  9620. imageToAdd = "graphic/command/return.png";
  9621. break;
  9622. }
  9623.  
  9624. if (imageToAdd !== "") {
  9625. $(this).prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text() + " &gt; " + $(this).text()+"' /> &nbsp;");
  9626. }
  9627. });
  9628. }
  9629.  
  9630. imageToAdd = "graphic/command/attack.png";
  9631. break;
  9632. case 5:
  9633. if (overviewLink.parent().hasClass("selected")) {
  9634. $("table.modemenu:last a", content_value).each(function(index) {
  9635. imageToAdd = "";
  9636. switch (index) {
  9637. case 1:
  9638. imageToAdd = "graphic/command/attack.png";
  9639. break;
  9640. case 2:
  9641. imageToAdd = "graphic/command/support.png";
  9642. break;
  9643. }
  9644.  
  9645. if (imageToAdd !== "") {
  9646. $(this).prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text() + " &gt; " + $(this).text()+"' /> &nbsp;");
  9647. }
  9648. });
  9649. }
  9650.  
  9651. imageToAdd = "graphic/unit/att.png";
  9652. break;
  9653. case 6:
  9654. imageToAdd = "graphic/buildings/main.png";
  9655. break;
  9656. case 7:
  9657. imageToAdd = "graphic/buildings/smith.png";
  9658. break;
  9659. case 8:
  9660. imageToAdd = "graphic/group_right.png";
  9661. overviewLink.prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text()+"' /> &nbsp;");
  9662. imageToAdd = "graphic/group_left.png";
  9663. break;
  9664. case 9:
  9665. imageToAdd = "graphic/premium/coinbag_14x14.png";
  9666. overviewLink.parent().width(150);
  9667. break;
  9668. }
  9669. if (imageToAdd !== "") {
  9670. overviewLink.prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text()+"' />&nbsp;&nbsp;");
  9671. }
  9672. });
  9673. }
  9674. }
  9675.  
  9676. var logoffLink = $("#linkContainer a:last");
  9677. if (user_data.global.duplicateLogoffLink) {
  9678. $("#linkContainer a:first").after(" - ").after(logoffLink.clone());
  9679. }
  9680.  
  9681. logoffLink.before("<a target='_blank' title='"+trans.sp.sp.moreScriptsTooltip+"' href='"+server_settings.scriptsDatabaseUrl+"'>"+trans.sp.sp.moreScripts+"</a>")
  9682. .before(" - <a target='_top' id='sanguPackageEditSettingsLink' href='"+getUrlString("screen=settings&mode=sangu")+"' title='" + trans.sp.sp.sanguLinkTitle + "'>Sangu Package</a> - ");
  9683.  
  9684. (function() {
  9685. var position = $("#sanguPackageEditSettingsLink").position(),
  9686. options = {
  9687. left: position.left,
  9688. top: ($(window).height() - 100)
  9689. },
  9690. content = {
  9691. body: trans.sp.sp.firstTimeRunEditSettings
  9692. };
  9693.  
  9694. createFixedTooltip("sanguActivatorSettingsTooltip", content, options);
  9695. }());
  9696.  
  9697. (function() {
  9698. //console.time("resourceColoring");
  9699. try {
  9700. var storage = parseInt($("#storage").text(), 10);
  9701.  
  9702. // Color resources based on how full the storage place is
  9703. if (user_data.global.resources.active) {
  9704. $("#wood,#iron,#stone").each(function () {
  9705. var x = parseInt(this.innerHTML / storage * 10 - 1, 10);
  9706. $(this).css("background-color", user_data.global.resources.backgroundColors[x]);
  9707. });
  9708. }
  9709.  
  9710. // Blink full resources
  9711. if (user_data.global.resources.blinkWhenStorageFull) {
  9712. $("#wood,#iron,#stone").filter(function () {
  9713. return parseInt(this.innerHTML, 10) == storage;
  9714. }).css({ "font-weight": "bolder", "color": "black" }).fadeOut().fadeIn();
  9715. }
  9716. } catch (e) { handleException(e, "resourcecoloring"); }
  9717. //console.timeEnd("resourceColoring");
  9718. }());
  9719. // adjust links to incoming attacks/support
  9720. // keep track of current amount of incomings
  9721. if (user_data.global.incomings.editLinks || user_data.global.incomings.track) {
  9722. (function() {
  9723. //console.time("incomingsindicator");
  9724. try {
  9725. var incoming = $("table.box:last"),
  9726. incomingAttacksLinks = $("a[href*='subtype=attacks']", incoming),
  9727. variableReplacer = function (text) {
  9728. var difference = "";
  9729. if (sinceLastCheckTimeNew > 0) {
  9730. difference += "+" + sinceLastCheckTimeNew;
  9731. if (sinceLastCheckTimeArrived > 0) {
  9732. difference += " ";
  9733. }
  9734. }
  9735. if (sinceLastCheckTimeArrived > 0) {
  9736. difference += "-" + sinceLastCheckTimeArrived;
  9737. }
  9738.  
  9739. return text.replace("{difference}", difference)
  9740. .replace("{elapsed}", lastCheckTimeElapsed)
  9741. .replace("{time}", lastCheckTime)
  9742. .replace("{current}", currentAmountOfIncomings
  9743. .replace("{saved}", lastKnownAmountOfIncomings));
  9744. };
  9745.  
  9746. if (incomingAttacksLinks.size() > 0) {
  9747. if (user_data.global.incomings.editLinks) {
  9748. incomingAttacksLinks.attr("href", incomingAttacksLinks.attr("href") + "&page=-1&group=0");
  9749. }
  9750. if (user_data.global.incomings.track) {
  9751. incomingAttacksLinks.parent().css("white-space", "nowrap");
  9752.  
  9753. // Split current and new attacks in incomings link
  9754. var incomingAttacksAmountLink = incomingAttacksLinks.last();
  9755. var currentAmountOfIncomings = incomingAttacksAmountLink.text().match(/\d+/)[0];
  9756. var lastKnownAmountOfIncomings = parseInt(pers.get("lastKnownAmountOfIncomings" + game_data.player.sitter), 10) || 0,
  9757. sinceLastCheckTimeNew = parseInt(pers.get("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter), 10) || 0,
  9758. sinceLastCheckTimeArrived = parseInt(pers.get("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter), 10) || 0;
  9759.  
  9760. var lastCheckTime = pers.get("lastKnownAmountOfIncomingsTime" + game_data.player.sitter);
  9761. var lastCheckTimeElapsed;
  9762. if (!lastCheckTime) {
  9763. lastCheckTime = trans.sp.incomings.indicator.lastTimeCheckNotYetSet;
  9764. lastCheckTimeElapsed = lastCheckTime;
  9765. } else {
  9766. lastCheckTime = new Date().getTime() - parseInt(lastCheckTime, 10);
  9767. lastCheckTimeElapsed = prettyDate(lastCheckTime);
  9768. lastCheckTime = twDateFormat(new Date(lastCheckTime));
  9769. }
  9770.  
  9771. if (currentAmountOfIncomings != lastKnownAmountOfIncomings || sinceLastCheckTimeNew > 0 || sinceLastCheckTimeArrived > 0) {
  9772. var newAttacks = currentAmountOfIncomings - lastKnownAmountOfIncomings;
  9773. if (newAttacks > 0) {
  9774. sinceLastCheckTimeNew += newAttacks;
  9775. pers.set("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter, sinceLastCheckTimeNew);
  9776.  
  9777. } else if (newAttacks < 0) {
  9778. sinceLastCheckTimeArrived -= newAttacks;
  9779. pers.set("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter, sinceLastCheckTimeArrived);
  9780. }
  9781.  
  9782. pers.set("lastKnownAmountOfIncomings" + game_data.player.sitter, currentAmountOfIncomings);
  9783.  
  9784. $("#incomings_amount").html(variableReplacer(user_data.global.incomings.indicator));
  9785. incomingAttacksLinks.attr("title", variableReplacer(user_data.global.incomings.lastTimeCheckWarning));
  9786. incomingAttacksLinks.fadeOut("slow").fadeIn("slow");
  9787. }
  9788.  
  9789. // extra image to set the lastCheckTime on incomings overview page
  9790. if (current_page.screen === "overview_villages" && current_page.mode === "incomings") {
  9791. // Tooltip for first time users
  9792. if (lastCheckTime == trans.sp.incomings.indicator.lastTimeCheckNotYetSet) {
  9793. // show info tooltip
  9794. var position = incomingAttacksAmountLink.position();
  9795. var options = {
  9796. left: position.left - 200,
  9797. top: position.top + 35,
  9798. width: 250
  9799. };
  9800. var content = {body: trans.sp.incomings.indicator.lastTimeCheckHintBoxTooltip.replace("{img}", "<img src='graphic/ally_forum.png'>")};
  9801. createFixedTooltip("incomingsIndicatorHelp", content, options);
  9802. }
  9803.  
  9804. // change last incomings-check time
  9805. incomingAttacksLinks.last().parent().after(
  9806. "<td class='box-item' id='changeLastCheckTimeBox' style='white-space: nowrap'><a href='#' id='changeLastCheckTime'>&nbsp;"
  9807. + "<img src='graphic/ally_forum.png' style='padding-top: 5px' "
  9808. + "title='"+variableReplacer(user_data.global.incomings.indicatorTooltip)+"'/>&nbsp;</a></td>");
  9809.  
  9810. // Set last incomings-check time
  9811. $("#changeLastCheckTime").click(function() {
  9812. var newCheckTime = new Date();
  9813. pers.set("lastKnownAmountOfIncomingsTime" + game_data.player.sitter, newCheckTime.getTime());
  9814. pers.set("lastKnownAmountOfIncomings" + game_data.player.sitter, currentAmountOfIncomings);
  9815. pers.set("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter, 0);
  9816. pers.set("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter, 0);
  9817.  
  9818. pers.setGlobal("fixedToolTip_incomingsIndicatorHelp", 1);
  9819. $("#changeLastCheckTimeBox").fadeOut();
  9820. window.location.href = window.location.href;
  9821. });
  9822. }
  9823. }
  9824. } else {
  9825. // When there are no more incomings, stop tracking
  9826. if (user_data.global.incomings.track) {
  9827. pers.set("lastKnownAmountOfIncomings" + game_data.player.sitter, 0);
  9828. pers.set("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter, 0);
  9829. pers.set("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter, 0);
  9830. }
  9831. }
  9832.  
  9833. // change incoming support link
  9834. if (user_data.global.incomings.editLinks) {
  9835. var incomingSupport = $("a[href*='subtype=supports']", incoming);
  9836. if (incomingSupport.size() > 0) {
  9837. if (user_data.global.incomings.editLinks) {
  9838. incomingSupport.attr("href", incomingSupport.attr("href") + "&page=-1&group=0");
  9839. }
  9840. }
  9841. }
  9842. } catch (e) { handleException(e, "incomingsindicator"); }
  9843. //console.time("incomingsindicator");
  9844. }());
  9845. }
  9846. if (server_settings.ajaxAllowed && user_data.global.visualizeFriends) {
  9847. (function() {
  9848. //console.time("friends");
  9849. try {
  9850. function Friends() {
  9851. this.lastCheck = new Date().getTime();
  9852. this.online = {
  9853. names: "",
  9854. amount: 0
  9855. };
  9856. this.offlineAmount = 0;
  9857. }
  9858.  
  9859. /**
  9860. * Insert a 'friends' link with visual online/offline indication
  9861. */
  9862. function updateTWFriendsLink() {
  9863. var friendsLink = $("<a href='" + getUrlString("&screen=buddies") + "'></a>");
  9864. friendsLink.html(
  9865. trans.sp.rest.friendsOnline
  9866. .replace("{friends}", friendsLink.text())
  9867. .replace("{onlineimg}", "<img src='graphic/dots/green.png' />")
  9868. .replace("{online#}", friends.online.amount)
  9869. .replace("{offlineimg}", "<img src='graphic/dots/red.png' />")
  9870. .replace("{offline#}", friends.offlineAmount)
  9871. );
  9872. if (friends.online.amount > 0) {
  9873. friendsLink.attr("title", trans.sp.rest.friendsOnlineTitle.replace("{playerNames}", friends.online.names.substr(1)));
  9874. }
  9875. $("#sanguPackageEditSettingsLink").before(friendsLink).before(" - ");
  9876. }
  9877.  
  9878. /**
  9879. * Parse the #content_value and update the friends link.
  9880. * Is called from ajax call.
  9881. * @param {string} overview the #content_value of the friends page
  9882. */
  9883. function parseFriendsTable(overview) {
  9884. var friendsTable = $("h3+table.vis:first", overview);
  9885. if (friendsTable.size() == 1) {
  9886. var friendRows = friendsTable.find("tr:gt(0)");
  9887. friendRows.each(function() {
  9888. var friendName = $.trim($("a:first", this).text());
  9889. var statusIndicatorImage = $("img:first", this);
  9890. if( statusIndicatorImage.length > 0 ) {
  9891. if (/red\.png/.test(statusIndicatorImage.attr("src"))) {
  9892. friends.offlineAmount++;
  9893. } else {
  9894. if (friendName != game_data.player.name) {
  9895. friends.online.names += ", " + friendName;
  9896. friends.online.amount++;
  9897. }
  9898. }
  9899. }
  9900. });
  9901.  
  9902. // localStorage save of online friends
  9903. pers.set("friendsOnline", JSON.stringify(friends));
  9904.  
  9905. updateTWFriendsLink();
  9906. }
  9907. }
  9908.  
  9909. var friends = pers.get("friendsOnline");
  9910.  
  9911. // check friends page only every 5 minutes (or when on friends page itself)
  9912. if ($("#village_link").val() == "/game.php?screen=buddies") {
  9913. friends = new Friends();
  9914. parseFriendsTable(content_value);
  9915. }
  9916. else {
  9917. if (friends) {
  9918. friends = JSON.parse(friends);
  9919. }
  9920. if (!friends || friends.lastCheck < new Date().getTime() - 1000 * 60 * 3) {
  9921. friends = new Friends();
  9922. ajax("buddies", parseFriendsTable);
  9923. } else {
  9924. updateTWFriendsLink();
  9925. }
  9926. }
  9927. } catch (e) { handleException(e, "friends"); }
  9928. //console.timeEnd("friends");
  9929. }());
  9930. }
  9931.  
  9932.  
  9933.  
  9934.  
  9935. //var end_time = new Date();
  9936. //console.timeEnd("SanguPackage");
  9937. //q("" + pad(Math.abs(start_time.getTime() - end_time.getTime()), 3) + " -> " + location.search);
  9938. }
  9939. }
  9940.  
  9941. if (location.href.indexOf('sangu.be') !== -1) {
  9942. // sangu.be
  9943. (function() {
  9944. // Check current version with version on the sangu.be site
  9945. var lastVersion = $("#sanguPackageVersion"),
  9946. resultBox = $("#versionCheckResult");
  9947.  
  9948. if (lastVersion.length === 1) {
  9949. resultBox.show();
  9950. resultBox.css("padding", "20px");
  9951. resultBox.css("margin", "10px");
  9952. resultBox.css("font-size", 18);
  9953. resultBox.css("height", 30);
  9954. resultBox.css("text-align", "center");
  9955.  
  9956. if ('8.119.5'.indexOf(lastVersion.text()) === 0) {
  9957. resultBox.css("background-color", "green");
  9958. resultBox.text("Je hebt de laatste versie!");
  9959. } else {
  9960. resultBox.css("background-color", "red");
  9961. resultBox.text("Er is een nieuwe versie beschikbaar!");
  9962. }
  9963. }
  9964. }());
  9965.  
  9966. } else if (location.href.indexOf('tribalwars.nl') !== -1) {
  9967. // TribalWars page
  9968. (function (func, GM_xmlhttpRequest) {
  9969. var lastCheck = sessionStorage.lastUpdateCheck,
  9970. currentVersion = '8.119.5';
  9971.  
  9972. function displayNewVersion() {
  9973. var a = document.createElement('a');
  9974. var linkText = document.createTextNode(" - Sangu Package Update!");
  9975. a.appendChild(linkText);
  9976. a.title = "Er is een update voor het Sangu Package beschikbaar!";
  9977. a.href = "http://sangu.be";
  9978. a.style.color = "black";
  9979. a.style.fontWeight = "bolder";
  9980. a.style.backgroundColor = "yellow";
  9981.  
  9982. document.getElementById("linkContainer").appendChild(a);
  9983. }
  9984.  
  9985. if (typeof GM_xmlhttpRequest !== "undefined") {
  9986. if (!lastCheck) {
  9987. sessionStorage.lastUpdateCheck = "done";
  9988. try
  9989. {
  9990. // GM_xmlhttpRequest didn't work when put in sangu_ready
  9991. GM_xmlhttpRequest({
  9992. method: "GET",
  9993. url: "http://www.sangu.be/api/sangupackageversion.php",
  9994. synchronous: false,
  9995. onload: function(response) {
  9996. if (response.responseText !== currentVersion) {
  9997. sessionStorage.lastUpdateCheck = "hasNew";
  9998. displayNewVersion();
  9999. }
  10000. }
  10001. });
  10002. }
  10003. catch (e)
  10004. {
  10005. console.log("error fetching latest version number:");
  10006. console.log(e);
  10007. }
  10008. } else if (lastCheck === "hasNew") {
  10009. displayNewVersion();
  10010. }
  10011. }
  10012.  
  10013. var script = document.createElement('script');
  10014. script.setAttribute("type", "application/javascript");
  10015. if (window.mozInnerScreenX !== undefined) {
  10016. // Firefox has troubles with renaming commands, villages, ... (it works some of the time)
  10017. // But waiting for document.ready slows down the script so only wait for this on FF
  10018. // An optimization could be to put document.readys only around those blocks that are
  10019. // problematic.
  10020. script.textContent = '$(document).ready(' + func + ');';
  10021.  
  10022. } else {
  10023. script.textContent = '(' + func + ')();';
  10024. }
  10025.  
  10026. document.body.appendChild(script); // run the script
  10027. document.body.removeChild(script); // clean up
  10028. }(sangu_ready, (typeof GM_xmlhttpRequest === "undefined" ? undefined : GM_xmlhttpRequest)));
  10029.  
  10030.  
  10031. }
Add Comment
Please, Sign In to add comment