您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Package for Tribal Wars bullies
// ==UserScript== // @name Sangu Package // @author Laoujin / De Goede Fee // @namespace sangu.be // @description Package for Tribal Wars bullies // @icon http://www.sangu.be/images/favicon.png // @include https://*.tribalwars.nl/game.php?* // @include http://sangu.be/* // @include http://www.sangu.be/* // @version 8.90.1 // @grant GM_xmlhttpRequest // ==/UserScript== //We are Sangu. You will be assimilated. Resistance is Futile. // The not-one-file source code can be found at: // https://github.com/SanguPackage/Script function sangu_ready() { //var start_time = new Date(); //console.time("SanguPackage"); var /** * When game_data.majorVersion is different from Sangu version then activate sangu 'compatibility' mode (gray icon) */ sangu_version = '8.90.0', /** * true: popup with crash dump, false: don't show the popup */ sangu_crash = sangu_version.split(".").length === 4, /** * jQuery element of the cell (td) that contains all page specific widgets */ content_value = $("#content_value"), /** * config/ Configuration per server (nl, de). Contains stuff like ajaxAllowed, etc */ server_settings = {}, /** * config/ Contains all translations except for the setting related translations in sangu_trans */ trans = {}, /** * config/ Contains all user settings */ user_data = {}, /** * config/ The current world configuration. settings like hasArchers, nightbonus, etc */ world_config = {}, /** * config/ Contains all data for this world (resources, units, buildings, units_off, unitsSize, ...) * What's in this variable depends on world_config. * This variable is a complete and utter mess :) */ world_data = {}, /** * Identifies the current page based on the querystring */ current_page = { screen: game_data.screen, mode: game_data.mode }, keyCodeMap = { 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pausebreak", 20: "capslock", 27: "escape", 32: " ", 33: "pageup", 34: "pagedown", 35: "end", 36: "home", 37: "arrow left", 38: "arrow up", 39: "arrow right", 40: "arrow down", 43: "+", 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", 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", 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", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7", 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111: "/", 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8", 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scrolllock", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'" }; server_settings = { /** * Calculate how many more days we can attack in vacation mode */ maxSitDays: 60, helpdeskUrl: "https://forum.tribalwars.nl/showthread.php?137674-8-11-GM-Algemeen-discussietopic-Sangu-Package", /** * This needs to be here for 'historical' reasons (Innogames versionchecker API remembers email on the server) * when in 'compatibility' mode (gray sangu icon). Also used in the crash report. */ sangu: "sangu.be", sanguEmail: "[email protected]", /** * More then 500 [ cannot be sent in messages or pasted in the noteblock */ allowedSquareBrackets: 500, /** * Are ajax calls allowed on this server */ ajaxAllowed: true, /* * async: true on AJAX calls is only allowed when this property is true */ asyncAjaxAllowed: false, /** * True: we add a direct link in the place to fill in coordinates. False: Show coords in an input field */ coordinateLinkAllowed: false, /** * Can we fill in the coordinates directly in the place (using the url querystring) from troops overview */ autoFillCoordinatesAllowed: true, scriptsDatabaseUrl: "http://www.twscripts.nl/" }; //$.extend(server_settings, { // extraProperty: "yaye" //}); /** * Contains all translation * The highest level is split in * - tw = translations that should be translated by their server equivalents (they are used somewhere in the html by Innogames) * - sp = new translations specific for the Sangu Package */ trans = { tw: { units: { 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" }, 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." }, 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" }, militia: "Militia" }, all: { today: "vandaag om", tomorrow: "morgen om", dateOn: "op", timeOn: "om", farm: "Boerderij", wood: "Hout", iron: "IJzer", stone: "Leem", groups: "Groepen", continentPrefix: "C" }, main: { loyaltyHeader: "Toestemming:" }, command: { returnText: "Terugkeer", attack: "Aanval", support: "Ondersteuning", haul: "Buit:", abortedOperation: "Afgebroken commando", catapultTarget: "Katapultdoel:", buttonValue: "OK", attackOn: "Aanval op ", supportFor: "Ondersteuning voor ", walkingTimeTitle: "Duur:" }, incoming: { defaultCommandName: "Bevel" }, place: { troopMovements: "Troepenbewegingen" }, market: { incomingTransports: "Binnenkomende transporten" }, profile: { title: "Profiel", claimedBy: "Geclaimd door:", awardsWon: "Behaalde awards" }, overview: { village: "Dorp", incomingTroops: "Aankomend" } }, sp: { sp: { settings: { reset: "De standaard Sangu Package settings herstellen", resetAll: "Sangu Package 'fabrieksinstellingen' herstellen", configuration: "Configuratie", configurationFormTogglerTooltip: "Klik op de knoppen om de verschillende editeerschermen te openen", activate: "Activeer", deleteTooltip: "Verwijderen", addRecord: "» Toevoegen", exportSettings: "Instellingen exporteren", importSettings: "Instellingen importeren", 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.", importSettingsSuccess: "Settings zijn geïmporteerd!", importError: "Het ziet er naar uit dat de geplakte tekst foutief is.", importErrorContinueAnyway: "Toch importeren?" }, donate: { title: "Donatie", whyWouldI: "Als je op regelmatige basis functionaliteit van het Sangu Package gebruikt, dan is dat een goede reden om een donatie te doen." + "<br><br>" + "Jouw dankbaarheid en financiële steun helpen me motiveren verder te blijven werken aan het Sangu Package.", 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 :)", notable: "Een aantal personen hebben reeds een notabele donatie gedaan:", buttonAmount: "Doneer €{amount}", beer: "Trakteer me een biertje", food: "Een spaghetti voor Wouter! (of pizza!)", yaye: "Een nieuw IT boek voor mijn verzameling!" }, configuration: "Sangu Package configureren (v{version})", activatePackage: "Sangu Package activeren", deactivatePackage: "Sangu Package deactiveren", packageCrashTitle: "Het Sangu Package is gecrasht :)", packageCrashTooltip: "Crash!!! Klik op de bol om het crash rapport te bekijken. " + "Je kan dit rapport naar ons doorsturen waardoor we het probleem mogelijk kunnen oplossen.", packageCrash: "<a href='http://" + server_settings.sangu + "'>Controleer eerst of er een update is!</a><br>" + "<b>Foutmelding</b>: <i>{error}</i><br>" + "<b>Details</b>:<br>" + "<textarea style='width: 95%' rows='20' id='crashArea'>" + "Foutmelding: {error}\n" + "Pagina: {title} -> {page}\n" + "URL: {url}\n" + "Versie: {version}\n" + "Brower: {browser}\n" + "game_data: {game_data}\n" + "\n{stacktrace}\n" + "\n\n\n[HTML]\n" + "</textarea>" + "<br><br>Je kan de bug <a href='{forum-url}' target='_blank'>hier</a> melden." + "<br>Of je kan de bug <a href='mailto:{email}'>mailen</a>." + "<br><br><center><i>Een bug waarvan we niet weten dat ie bestaat zal ook niet gefixed worden!</i></center>" + "<br><center><b>Geef zoveel mogelijk informatie mee bij het sturen van een bugrapport!!!</b></center>", activatePackageWithCompatibility: "Sangu Package (v{version}) mogelijk incompatibel met huidige TW versie", 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.", firstTimeRunEditSettings: "Klik op de nieuwe 'Sangu Package' link om het package naar jouw smaak in te stellen!", removeScriptWarning: "Niet meer tonen", moreScripts: "Meer scripts", moreScriptsTooltip: "Ga naar de site met alle goedgekeurde TW scripts", sanguLinkTitle: "Het package naar jouw smaak instellen" }, all: { populationShort: "Pop", population: "Populatie", total: "Totaal", last: "Laatste", target: "Doel", targetEx: "Doelwit", more: "meer", less: "minder", all: "Alle", withText: "met", merchants: "Handelaren", further: "verder", closer: "dichter", fieldsSuffix: "(F{0})", close: "Sluiten" }, main: { unitsReplacement: "Eigen", unitsOther: "Ondersteunende Eenheden", rallyPointTroops: "troepen", ownStackTitle: "Totale populatie van de eigen troepen", supportingStackTitle: "Totale populatie van de ondersteunende troepen", showHiddenDivs: "» Alle verborgen terugzetten ({amount} verborgen)", hideDiv: "Volledig verbergen" }, map: { dodgeLastTagged: "Dodgetijd van de laatst getagde aanval" }, tagger: { openButton: "Open Tagger", rename: "Herbenoemen", renameTooltip: "Alle bevelen waarvan de checkbox aangevinkt is hernoemen", incomingTroops: "Binnenkomende troepen", arrival: "Aankomst", arrivalIn: "Aankomst in", sentNow: "Zojuist", sentSeconds: "seconde(n)", sent1Minute: "1 minuut", sentMinutes: "minuten", sent1Hour: "1 uur", sentHours: "uren", sentOn: "Verstuurtijd", ago: "Geleden", arrivesInNightBonus: " (NACHT!)", tagIt: "Aanval Taggen", checkAllSupport: "Aanvinken van alle zichtbare ondersteuning", uncheckAllSupport: "Uitvinken van alle zichtbare ondersteuning", tagged: "Tagged!", dodgeTime: "Dodgetijd", slowest: "Traagst", slowestTip: "Traagste eenheid in het dorp", allAbove: "Alle vroegere aanvallen aanvinken", allBelow: "Alle latere aanvallen aanvinken", renameTo: "Hernoemen naar: ", switchModus: "» Alle aanvallen openen/sluiten", checkAllAttacks: "Aanvinken van alle zichtbare aanvallen", uncheckAllAttacks: "Uitvinken van alle zichtbare aanvallen", activeDodgeTime: "Actieve dodgetijd (wordt op de kaart getoond)", totalAttacksOnVillage: "Aantal aanvallen", renameButtonShortcutTooltip: "Shortcut: CTRL + {hitkey}" }, place: { distance: "Afstand", backOn: "Terug op", onlyAttack: "1 aanval op {arrivalDateFirst} ({timeLeftFirst})", multipleAttack: "{amount} aanvallen tussen {arrivalDateFirst} ({timeLeftFirst}) en {arrivalDateLast} ({timeLeftLast})", changeSpeedImageTooltips: "{originalTitle} - Klik om de traagste eenheid te wijzigen" }, jumper: { goToMap: "Ga naar de kaart" }, command: { returnOn: "Terug op:", arrival: "Aankomst", dodgeNotFarEnough: "De dodge is niet ver genoeg!", dodgeMinuteReturn: "(Terugkeer na {minutes})", catapultImageTitle: "Klik om gebouw te vernietigen" }, overviews: { totalVillages: "Aantal dorpen:", loadNextPage: "[volgende pagina laden]" }, troopOverview: { help: "<b>Laat je looptijden uitrekenen door Sangu!</b><br>" + "Gebruik de nieuwe kolom uiterst rechts om de looptijden tot een ingegeven doeldorp te berekenen.<br>" + "<br>Je kan de eenheden icons ({unitIcon}) aanklikken om de snelheid van de traagste eenheid te wijzigen." + "<span style='line-height: 2'>" + "<br>Klikken wijzigt de <span style='border: 2px green dotted'>snelheid op de huidige pagina</span>. " + "<br>Dubbelklikken wijzigt de <span style='border: 3px red solid'>snelheid op alle pagina's</span>." + "</span>" + "<br>De cellen met de groene en rode rand geven de huidige traagst eenheid-snelheid aan." + "<br><br><b>De iconen in de 'Opdracht' kolom</b>:" + "<br>Gebruik <img src='graphic/dots/red.png'> om een rij te verwijderen." + "<br>Gebruik <img src='graphic/command/attack.png'> om naar de verzamelplaats te gaan." + "(gebruik de middelste muisknop om in een nieuwe tab te openen)", helpTitle: "Snel dorpen aanvallen (of ondersteunen)", removeVillage: "Dorp verwijderen", toThePlace: "Verzamelplaats", setTargetVillageButton: "OK", setTargetVillageButtonAlert: "Geef de coördinaten van het dorp dat je wil aanvallen (of ondersteunen)", commandTitle: "Opdracht", selectUnitSpeed: "Selecteer {0} als traagste eenheid. (Klik op deze pagina, Dubbel klik op alle pagina's.)", nightBonus: "Nacht?", village: "Dorp", filterTroops: "Filter", filterTroopsTooltip: "Toon enkel de dorpen met meer dan het aangegeven aantal eenheden", filterPopulation: "Filter populatie", filterPopulationTooltip: "Toon enkel de dorpen met meer/minder bevolking", filterWalkingTime: "Filter looptijd", filterWalkingTimeTooltip: "Toon enkel de dorpen met een langere looptijd (in uren) tot het doeldorp", calcStack: "Bereken stack", calcStackTooltip: "Toon de bevolking per dorp in de \"Nacht?\" kolom", filterNoble: "Toon edels", filterNobleTooltip: "Toon enkel de dorpen waar edels aanwezig zijn", filterUnderAttack: "Toon onder aanval", filterUnderAttackTooltip: "Toon enkel de dorpen die onder aanval zijn", sort: "Sorteren", sortTooltip: "Sorteren op looptijd tot doeldorp", restack: "Stack BB Codes", restackTitle: "<b>Alle dorpen met minstens {requiredDiff}k bevolking minder dan {to}k</b><br>" + "<font size='-2'>(configuratie wijzigbaar bij Sangu instellingen)</font>", cheapNobles: "Goedkope edelmannen beschikbaar", filtersReverse: "De filtering omdraaien", filtersReverseInfo: "Filters omdraaien", freeTextFilter: "Tekst filter", freeTextFilterTooltip: "Dorpen {filterType} de tekst wegfilteren", freeTextFilterTooltipFilterTypeWith: "met", freeTextFilterTooltipFilterTypeWithout: "zonder", continentFilter: "Continent", continentFilterTooltip: "Alle dorpen in continent wegfilteren", continentFilterTooltipReverse: "Alle dorpen in continent tonen" }, prodOverview: { filter: "Filter", filterFullGS: "Volle opslag", merchantTooltip: "Vink aan om handelaren te highlighten", merchantAmountTooltip: "Als de checkbox aangevinkt is worden dorpen met minder dan x handelaren in het rood gehighlight", bbCodes: "BB Codes", bbCodesInfo: "Gebruik IMG", filterTooltip: "Dorpen die niet aan de filtercriteria voldoen verbergen", filterTooltipReverse: "Dorpen die voldoen aan de filtercriteria highlighten", filterFullGSTooltip: "Dorpen waarbij niet minstens 1 van de grondstoffen vol is verbergen", filterFullGSTooltipReverse: "Dorpen waarbij minstens 1 van de grondstoffen vol is highlighten", filterAllTooltip: "Dorpen waarbij niet minstens 1 van de grondstoffen meer/minder dan x is verbergen", filterAllTooltipReverse: "Dorpen waarbij minstens 1 van de grondstoffen meer/minder dan x is highlighten", filter1Tooltip: "Dorpen waarbij er nier meer/minder dan x {0} is verbergen", filter1TooltipReverse: "Dorpen waarbij er meer/minder dan x {0} is highlighten", tooMuch: "Teveel:", tooMuchText: "Alle dorpen met minstens {diff}k meer grondstoffen dan {min}k", tooLittle: "Te weinig:", tooLittleText: "Alle dorpen met minstens {diff}k minder grondstoffen dan {min}k", bbCodeExtraInfo: "<br><font size='-2'>(configuratie wijzigbaar bij Sangu instellingen)</font>" }, buildOverview: { optimistic: "Optimistisch", mark: "Duiden", filter: "Filteren" }, smithOverview: { optimistic: "Optimistisch", mark: "Duiden", filter: "Filteren" }, defOverview: { stackButton: "Totalen berekenen", stackTooltip: "Totale stack en afstanden berekenen", stackFilter: "Filter op stack", stackFilterTooltip: "Filter dorpen met meer/minder dan x totale stack vanbuiten het dorp", village: "Dorp:", distFilter: "Filter op afstand", distFilterTooltip: "Filter alle dorpen die verder/dichter dan x velden liggen van dorp y", stackBBCodes: "Stack BBCodes", stackBBCodesTooltip: "Bepaal BB codes en aantal troepen voor een stack tot x populatie voor alle zichtbare dorpen", filterNoSupport: "Zonder OS wegfilteren", filterNoSupportTooltip: "Wegfilteren van alle dorpen waar geen ondersteuning meer zichtbaar is", extraFiltersSupport: "Ondersteunende dorpen filters:", extraFiltersDefense: "Ondersteuning filters:", extraFiltersReverse: "De filtering omdraaien", extraFiltersInfo: "Filters omdraaien", distFilter2: "Afstand filter", freeTextFilter: "Tekst filter", barbarianFilter: "Barbarendorpen", barbarianFilterTooltip: "Toon alle ondersteuningen naar barbarendorpen", nobleFilter: "Alle edel-ondersteuning tonen", nobleFilterRev: "Alle edel-ondersteuning wegfilteren", spyFilter: "Alle verkenner-ondersteuning tonen", spyFilterRev: "Alle verkenner-ondersteuning wegfilteren", attackFilter: "Alle aanval-ondersteuning tonen", attackFilterRev: "Alle aanval-ondersteuning wegfilteren", supportFilter: "Alle verdediging-ondersteuning tonen", supportFilterRev: "Alle verdediging-ondersteuning wegfilteren", otherPlayerFilterShow: "tonen", otherPlayerFilterHide: "wegfilteren", otherPlayerFilterTo: "Alle ondersteuningen naar andere spelers {action}", otherPlayerFilterFrom: "Alle ondersteuningen van andere spelers {action}", filterTooltipVillageTypeSupporting: "Ondersteunende dorpen", filterTooltipVillageTypeSupported: "Ondersteunde dorpen", freeTextFilterTooltip: "{villageType} {filterType} de tekst wegfilteren", freeTextFilterTooltipFilterTypeWith: "met", freeTextFilterTooltipFilterTypeWithout: "zonder", distanceFilterTooltip: "{villageType} die {filterType} dan het aangegeven aantal velden liggen wegfilteren", distanceFilterTooltipFilterTypeCloser: "dichter", distanceFilterTooltipFilterTypeFurther: "verder", totalFromOtherVillages: "totaal uit andere dorpen", totalInOtherVillages: "totaal in andere dorpen", freeText: "Vrij tekstveld (wordt niet opgeslagen!):", fieldsPrefix: "F{0}", thousandSuffix: "k", totalVillages: "Dorpen ({0})", distanceToVillageNoneEntered: "Geef een coördinaat! (eerste tekstveld)", distanceToVillage: "Afstand tot {0}", filterUnderAttack: "Filter onder aanval" }, commands: { filterReturn: "Filter terugkeer", filterReturnTooltip: "'Teruggestuurd' en 'Terugkeer' bevelen verbergen", totalRows: "Somlijn", group: "Groeperen", totalRowsText: "{0}x OS = {1} pop", totalVillagesSupport: "Ondersteunde dorpen:", totalVillagesAttack: "Aangevallen dorpen:", totalSupport: "Ondersteuningen", totalAttack: "Aanvallen", bbCodeExport: "BBCode Export", bbCodeExportTooltip: "Overblijvende aanvallen exporteren", supportPlayerExport: "Ondersteuning exporteren", supportPlayerExportTooltip: "Geef de naam van de speler waarvoor je de ondersteuning wil exporteren " + "(of laat leeg om alle ondersteuningen te exporteren). Door de export als mededeling " + "naar de andere speler door te sturen " + "kan deze jouw gestuurde troepen als bevelnaam zetten. (Hij heeft daarvoor natuurlijk" + " ook het Sangu Package nodig :)", filtersReverse: "De filtering omdraaien", filtersReverseInfo: "Filters omdraaien", freeTextFilter: "Tekst filter", freeTextFilterTooltip: "Aanvallen {filterType} de tekst wegfilteren", freeTextFilterTooltipFilterTypeWith: "met", freeTextFilterTooltipFilterTypeWithout: "zonder", nobleFilter: "Alle edelaanvallen tonen", nobleFilterRev: "Alle edelaanvallen wegfilteren", spyFilter: "Alle verkenneraanvallen tonen", spyFilterRev: "Alle verkenneraanvallen wegfilteren", tableTotal: "Bevel ({0})", fakeFilter: "Alle fake aanvallen wegfilteren", fakeFilterRev: "Alle fake aanvallen tonen", continentFilter: "Continent", continentFilterTooltip: "Alle dorpen in continent wegfilteren", continentFilterTooltipReverse: "Alle dorpen in continent tonen", exportAttackHeader: "{village} {#} aanvallen, laatste [b]{lastAttack}[/b]", exportDefenseHeader: "{village} {support#} ondersteuningen voor [b]{totalStack} pop[/b]", exportCompleteHeader: "{village} {#} aanvallen, laatste [b]{lastAttack}[/b]\n+ {support#} ondersteuningen voor [b]{totalStack} pop[/b]", exportNone: "Geen ondersteuning gevonden!" }, groups: { villageFilter: "Dorpsnaam", villageFilterTitle: "Alle dorpen met de tekst in de dorpsnaam wegfilteren", villageFilterTitleRev: "Alle dorpen met de tekst in de dorpsnaam tonen", pointsFilter: "Punten", amountFilter: "Aantal", groupNameFilter: "Groepsnaam", amountFilterTitle: "Alle dorpen met minder groepen wegfilteren", amountFilterTitleRev: "Alle dorpen met meer groepen wegfilteren", pointsFilterTitle: "Alle dorpen met minder punten wegfilteren", pointsFilterTitleRev: "Alle dorpen met meer punten wegfilteren", farmFilterTitle: "Alle dorpen met minder populatie wegfilteren", farmFilterTitleRev: "Alle dorpen met meer populatie wegfilteren", groupNameFilterTitle: "Alle dorpen met de tekst in een groepsnaam wegfilteren", groupNameFilterTitleRev: "Alle dorpen met de tekst in een groepsnaam tonen" }, snob: { canProduce: "Je kan meteen produceren:" }, profile: { twStatsMap: "TWStats Kaart", externalPage: "(Extern)", internalPage: "(Intern)", conquers: "Overnames", villages: "Dorpen:", graphPoints: "Punten", graphVillages: "Dorpen", graphOD: "OD Totaal", graphODD: "OD Verdediging", graphODA: "OD Aanval", graphODS: "OD Ondersteuning", graphRank: "Rang", graphMembers: "Leden", graphTWMap: "TribalWarsMap.com" }, incomings: { dynamicGrouping: "Dynamisch groeperen", dynamicGroupingTooltip: "Groepeert trager maar bevriest de pagina niet", summation: "Somlijn", fastGrouping: "Snel groeperen", fastGroupingTooltip: "Groepeert sneller en bevriest de pagina (geen refreshs wanneer een aanval binnenkomt)", showNewIncomings: "Toon nieuwe aanvallen", sortByAttackId: "Sorteer op aanvalsid", sortByAttackIdTooltip: "Een kleiner aanvalsid betekent een eerder verstuurde aanval", amount: "Aanvallen:", attackId: "Aanvalsid", attackIdDifference: "Verschil", filterColumnButton: "Kolom filter", filterColumnButtonTooltip: "Alle bevelen waarbij de geselecteerde kolom de ingegeven tekst bevat {type}", filterColumnButtonTooltipHide: "verbergen", filterColumnButtonTooltipShow: "tonen", indicator: { lastTimeCheckHintBoxTooltip: "Klik op {img} om de laatste tijdcheck met de huidige tijd te vervangen.", lastTimeCheckNotYetSet: "(nog niet)" }, commandsImport: "Ondersteuning importeren", commandsImportTooltip: "Ondersteuning naar jouw dorpen kan op jouw account ingelezen worden" + " door de andere speler zijn bevelen te laten exporteren via Sangu Package (Pagina Overzicht: Bevelen)" + " en die export hier te plakken.", commandsImportError: "Fout bij het inladen van de ondersteuningen.\nHet zou er zoals dit moeten uitzien: \n" + '[{"commandName": "702|459 (speler) Zw=1 (Pop: 1)", "commandId": "7538763"}]', commandsImportSuccess: "{replaced} van de {total} ondersteuningen zijn hernoemd." }, rest: { sittingAttackTill: "Aanvallen en verdedigen van dorpen niet in eigen beheer tot:", friendsOnline: "Vrienden {friends} ({onlineimg} {online#} | {offlineimg} {offline#})", friendsOnlineTitle: "Online: {playerNames}" } } }; /** * Log the parameter to the console (print yaye when undefined) */ function q(what) { console.log(typeof what === "undefined" ? "yaye" : what); } /** * Alert the parameter (yaye when undefined) */ function qa(what) { alert(typeof what === "undefined" ? "yaye" : what); } /** * Show crash report */ function sangu_alert(e, title) { var activator = $("#sangu_activator"); activator .attr("src", "graphic/dots/grey.png") .attr("title", trans.sp.sp.packageCrashTooltip); (function() { var position = $("#storage").position(), options = { left: position.left - 150, top: position.top + 35 }, content = {body: trans.sp.sp.packageCrashTooltip, title: trans.sp.sp.packageCrashTitle}; createFixedTooltip("sanguCrashTooltip", content, options); }()); activator.click(function() { var currentPageHtml = document.documentElement.innerHTML, position = $("#storage").position(), options = { left: $(window).width() / 2 - 300, top: position.top + 35, width: 600, showOnce: false }, game_dataSubset = { majorVersion: game_data.majorVersion, market: game_data.market, world: game_data.world, sitter: game_data.player.sitter, village_id: game_data.village.id, player_id: game_data.player.id, player_name: game_data.player.name, ally_id: game_data.player.ally_id, villages: game_data.player.villages, premium: game_data.player.premium/*, account_manager: game_data.player.account_manager, farm_manager: game_data.player.farm_manager*/ }, content = { title: trans.sp.sp.packageCrashTitle, body: trans.sp.sp.packageCrash .replace("{forum-url}", server_settings.helpdeskUrl) .replace("{title}", title) .replace(/\{error\}/g, e.message) .replace("{page}", JSON.stringify(current_page)) .replace("{url}", document.location.href) .replace("{version}", sangu_version) .replace("{browser}", JSON.stringify($.browser)) .replace("{game_data}", JSON.stringify(game_dataSubset)) .replace("{stacktrace}", e.stack ? e.stack + "\n\n" + e.stacktrace : "assertion?") .replace("{email}", server_settings.sanguEmail) .replace("{html}", currentPageHtml) }; createFixedTooltip("sanguCrash", content, options); $("#crashArea").val($("#crashArea").val() + currentPageHtml); return false; }); for(i = 0; i < 7; i++) { activator.fadeTo('slow', 0.2).fadeTo('slow', 1.0); } if (sangu_crash) { activator.click(); } } /** * Failed assertions show the crash report! */ function assert(shouldBeTruthy, message) { if (!shouldBeTruthy) { sangu_alert({message: message || "(broken assertion)"}); } } /** * Show crash report */ function handleException(e, title) { sangu_alert(e, title); } function pad(number, length) { var str = '' + number; while (str.length < length) { str = '0' + str; } return str; } /** * Gets a value from the querystring (or returns "") * @param {string} name the name of the querystring parameter * @param {string} [url] when omitted, the current location.url is assumed */ function getQueryStringParam(name, url) { name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); var regexS = "[\\?&]" + name + "=([^&#]*)"; var regex = new RegExp(regexS); if( url == undefined && name == "village" ) { return game_data.village.id; } else { var results = regex.exec(url == undefined ? window.location.href : url); if (results == null) { return ""; } else { return results[1]; } } } /** * Get a TW url taking account sitting etc in account * @param {string} url provide the url starting from &screen= * @param {number} [villageId] when omitted the current village is assumed */ function getUrlString(url, villageId) { if (url.indexOf("?") == -1) { var link = location.href.substr(0, location.href.indexOf("?")); link += "?village=" + (villageId ? villageId : getQueryStringParam("village")); var isSit = getQueryStringParam("t"); if (isSit) { link += "&t=" + isSit; } if (url.indexOf("=") == -1) { return link + "&screen=" + url; } else { return link + "&" + url; } } else { return url; } } /** * Perform an ajax call (if the server allows it) * @param {string} screen passed to getUrlString. (start from &screen=) * @param {function} strategy executed on success. Has parameter text (content of the parameter depends on opts.contentValue) * @param {object} [opts] object with properties * {false|number} [villageId] passed to getUrlString. Default is false which defaults to current village. Otherwise pass a village id. * {boolean=true} [contentValue] true (default): only return the #content_value. false: return entire DOM HTML * {boolean=true} [async] defaults to true */ function ajax(screen, strategy, opts) { if (!server_settings.ajaxAllowed) { alert("Ajax is not allowed on this server."); return; } opts = $.extend({}, { villageId: false, contentValue: true, async: false }, opts); $.ajax({ url: getUrlString(screen, opts.villageId), async: server_settings.asyncAjaxAllowed ? opts.async : false, success: function(text) { text = opts.contentValue ? $("#content_value", text) : text; strategy(text); } }); } function spSpeedCookie(setter) { if (setter == undefined) { var speedCookie = pers.get("targetVillageSpeed"); if (speedCookie == '') { speedCookie = 'ram'; } return speedCookie; } else { if (setter.indexOf('_') == 4) { setter = setter.substr(setter.indexOf('_') + 1); } pers.set("targetVillageSpeed", setter); return setter; } } function spTargetVillageCookie(setter) { if (setter == undefined) { return pers.get("targetVillageCoord"); } else { pers.set("targetVillageCoord", setter); return setter; } } function getDistance(x1, x2, y1, y2, speed) { var dist = {}; dist.fields = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); dist.travelTime = dist.fields * (speed == '' ? world_data.unitsSpeed.unit_ram : world_data.unitsSpeed['unit_' + speed]); dist.arrivalTime = getDateFromTW($("#serverTime").text(), true); dist.arrivalTime.setTime(dist.arrivalTime.getTime() + (dist.travelTime * 60 * 1000)); dist.isNightBonus = isDateInNightBonus(dist.arrivalTime); if (speed == 'snob' && dist.travelTime > world_config.maxNobleWalkingTime) { dist.html = "<font color='" + user_data.colors.error + "'><b>" + twDurationFormat(dist.travelTime) + "</b></font>"; dist.isNightBonus = true; } else { var displayTime = twDateFormat(dist.arrivalTime); if (speed != 'merchant' && dist.isNightBonus) { displayTime = "<font color='" + user_data.colors.error + "'><b>" + displayTime + "</b></font>"; } dist.html = user_data.walkingTimeDisplay .replace("{duration}", twDurationFormat(dist.travelTime)) .replace("{arrival}", displayTime); } if (dist.fields == 0) { dist.html = ""; } return dist; } _gaq.push(['b._setAccount', 'UA-30075487-3']); /** * Send click to google analytics * @param {string} action */ function trackClickEvent(action) { trackEvent("ButtonClick", action); } /** * google analytics event tracking */ function trackEvent(category, action, label) { // category: clicks (downloads, ...) // action: which button clicked if (typeof label === 'undefined') { label = getQueryStringParam("screen"); var mode = getQueryStringParam("mode"); if (mode) label += "-" + mode; } //_gaq.push(['b._setAccount', 'UA-30075487-3']); //_gaq.push(['b._trackPageview']); // _gat._getTrackerByName('b')._trackEvent("SanguPackage", "Loaded", "withGetB"); try { _gat._getTrackerByName('b')._trackEvent(category, action, label); } catch (e) { // no crash report for this } } function fillRallyPoint(units) { var script = ""; $.each(world_data.units, function (i, v) { if (units[v] != undefined && units[v] > 0) { script += "document.forms[0]." + v + ".value=\"" + units[v] + "\";"; } else { script += "document.forms[0]." + v + ".value=\"\";"; } }); return script; } /** * Tries to find village coords in str and convert it to a 'village' object * @param {string} str the string to be converted to a village object * @param {true|} looseMatch !!!Do not provide a value for looseMatch when converting a real village name.!!! * It should be set to true when it was the user that provided the input str. When true, * a str like 456-789 would also match. (so that Sangu Package users don't have to use | but can instead * use anything to seperate the 2 coordinates). * @returns {object} object with parameters isValid: false when the string could not be matched and true with extra properties * x, y, coord, validName (=html friendly id name) and continent */ function getVillageFromCoords(str, looseMatch) { // if str is "villageName (X|Y) C54" then the villageName could be something like "456-321" // the regex then thinks that the villageName are the coords // looseMatch var targetMatch = looseMatch != undefined ? str.match(/(\d+)\D(\d+)/g) : str.match(/(\d+)\|(\d+)/g); if (targetMatch != null && targetMatch.length > 0) { var coordMatch = targetMatch[targetMatch.length - 1].match(/(\d+)\D(\d+)/); var village = { "isValid": true, "coord": coordMatch[1] + '|' + coordMatch[2], "x": coordMatch[1], "y": coordMatch[2] }; village.validName = function () { return this.x + '_' + this.y; }; village.continent = function () { return this.y.substr(0, 1) + this.x.substr(0, 1); }; return village; } return { "isValid": false }; } function buildAttackString(villageCoord, unitsSent, player, isSupport, minimum, haulDescription) { var seperator = " "; if (minimum == undefined) { minimum = 0; } var totalPop = 0; var renamed = villageCoord == null ? "" : villageCoord + seperator; var sent = ""; $.each(world_data.units, function (i, val) { var amount = unitsSent[val]; if (amount != 0) { if (val == "snob") { renamed += trans.tw.units.names[val] + "! "; } else if (amount >= minimum) { sent += ", " + trans.tw.units.shortNames[val] + "=" + amount; } totalPop += amount * world_data.unitsPositionSize[i]; } }); if (player) { renamed += '(' + player + ')' + seperator; } if (sent.length > 2) { sent = sent.substr(2); } if (isSupport) { sent += seperator + "(" + trans.sp.all.populationShort + ": " + formatNumber(totalPop) + ")"; } if (user_data.attackAutoRename.addHaul && typeof haulDescription !== 'undefined') { sent += " (" + trans.tw.command.haul + " " + haulDescription + ")"; } return renamed + sent; } function calcTroops(units) { // units is an array of numbers; keys are the unit names (without unit_) var x = {}; x.totalDef = 0; function removeElement(arr, element) { var idx = arr.indexOf(element); if (idx != -1) { arr.splice(idx, 1); } return arr; } // heavy doesn't count in determining whether the village is def/off (since you got some crazy guys using hc as offense and defense:) $.each(removeElement(world_data.units_def, 'heavy'), function (i, v) { x.totalDef += units[v] * world_data.unitsSize['unit_' + v]; }); x.totalOff = 0; $.each(removeElement(world_data.units_off, 'heavy'), function (i, v) { x.totalOff += units[v] * world_data.unitsSize['unit_' + v]; }); x.isDef = x.totalDef > x.totalOff; x.isScout = units.spy * world_data.unitsSize.unit_spy > x.totalDef + x.totalOff; x.isMatch = function (type) { return (type == 'all' || (type == 'def' && this.isDef) || (type == 'off' && !this.isDef)); }; x.getSlowest = function () { var slowest_unit = null; $.each(world_data.units, function (i, v) { if (units[v] > 0 && (slowest_unit == null || world_data.unitsSpeed["unit_" + slowest_unit] < world_data.unitsSpeed["unit_" + v])) { slowest_unit = v; } }); return slowest_unit; }; x.colorIfNotRightAttackType = function (cell, isAttack) { var isSet = false; if (units.snob != undefined && units.snob > 0) { if (isAttack) { if (units.snob > 1) { isSet = true; cell.css("background-color", user_data.colors.error).css("border", "1px solid black"); cell.animate({ width: "70%", opacity: 0.4, marginLeft: "0.6in", fontSize: "3em", borderWidth: "10px" }, 5000, function () { // Animation complete. }); } else { return; } } else { isSet = true; } } else if (x.totalDef + x.totalOff < user_data.command.filterFakeMaxPop) { // fake return; } if (!isSet && (x.isScout || x.isMatch(isAttack ? 'off' : 'def'))) { return; } cell.css("background-color", user_data.colors.error); }; return x; } function stackDisplay(totalFarm, stackOptions) { // TODO: this function is only used on main village overview if (stackOptions == undefined) { stackOptions = {}; } var farmSize = game_data.village.buildings.farm * world_config.farmLimit; var stackDesc = '<b>' + formatNumber(totalFarm); if (stackOptions.showFarmLimit && world_config.farmLimit > 0) { stackDesc += ' / ' + formatNumber(farmSize); } if (stackOptions.percentage) { stackDesc += ' (' + stackOptions.percentage + ')</b>'; } var bgColor = getStackColor(totalFarm, farmSize); if (stackOptions.cell == undefined) { return { color: bgColor, desc: stackDesc, cssColor: "style='background-color:" + bgColor + "'" }; } else { if (stackOptions.appendToCell) { stackOptions.cell.append(" » " + stackDesc); } else { stackOptions.cell.html(stackDesc); } if (!stackOptions.skipColoring) { stackOptions.cell.css("background-color", bgColor); } } } /** * Gets the configured stack backgroundcolor for the given stackTotal * @param stackTotal {number} * @returns {color} */ function getStackColor(stackTotal) { var color = null, arrayToIterate, farmLimitModifier; if (world_config.farmLimit > 0) { arrayToIterate = user_data.farmLimit.acceptableOverstack; farmLimitModifier = 30 * world_config.farmLimit; } else { arrayToIterate = user_data.farmLimit.unlimitedStack; farmLimitModifier = 1; // = No modifier } if (arrayToIterate.length > 0) { $.each(arrayToIterate, function (index, configValue) { if (color == null && stackTotal < farmLimitModifier * configValue) { if (index === 0) { color = ""; } else { color = user_data.farmLimit.stackColors[index - 1]; //q(stackTotal +"<"+ farmLimitModifier +"*"+ configValue); //q("return " + (index - 1) + "->" + color); } return false; } }); if (color != null) { //q(stackTotal + " -> " + color); return color; } return user_data.farmLimit.stackColors[user_data.farmLimit.stackColors.length - 1]; } return ""; } var modernizr = (function () { // Difference in capital letter with the Modernizr library // So nothing will break should TW start making use of it return { localstorage: (function supports_html5_storage() { try { return 'localStorage' in window && window['localStorage'] !== null; } catch (e) { return false; } })() }; })(); var pers; (function (pers) { function getKey(key) { return 'sangu_' + key; } function getWorldKey(key) { return 'sangu_' + game_data.world + '_' + key; } function getCookie(key) { key = getWorldKey(key); return (function() { var x, cooks, cookie; if (document.cookie.match(/;/)) { cooks = document.cookie.split("; "); for (x = 0; x < cooks.length; x++) { cookie = cooks[x]; if (cookie.match(key + "=")) { return cookie.replace(key + "=", ""); } } } else { if (document.cookie.match(key + "=")) { return document.cookie.replace(key + "=", ""); } } return ''; })(); } function getGlobal(key) { key = getKey(key); if (modernizr.localstorage) { var value = localStorage[key]; return typeof value === 'undefined' ? '' : value; } else { return getCookie(key); } } function getSession(key) { key = getWorldKey(key); if (modernizr.localstorage) { var value = sessionStorage[key]; return typeof value === 'undefined' ? '' : value; } else { return getCookie(key); } } function get(key) { return getGlobal(key); } function setCookie(key, value, expireMinutes) { key = getWorldKey(key); (function() { var date_obj = new Date(), time = date_obj.getTime(); if (typeof expireMinutes === 'undefined') { time += 60 * 1000 * 24 * 356; } else { time += expireMinutes * 1000 * 60; } date_obj.setTime(time); document.cookie = key + "=" + value + ";expires=" + date_obj.toGMTString() + ";"; })(); } function setGlobal(key, value) { key = getKey(key); if (modernizr.localstorage) { localStorage[key] = value; } else { setCookie(key, value); } } function setSession(key, value) { key = getWorldKey(key); if (modernizr.localstorage) { sessionStorage[key] = value; } else { setCookie(key, value); } } function set(key, value) { setGlobal(key, value); } function removeSessionItem(key) { key = getKey(key); if (modernizr.localstorage) { sessionStorage.removeItem(key); } // fuck cookies } function clear() { if (modernizr.localstorage) { sessionStorage.clear(); localStorage.clear(); } } pers.removeSessionItem = removeSessionItem; pers.getWorldKey = getWorldKey; pers.getKey = getKey; pers.set = set; pers.setCookie = setCookie; pers.setGlobal = setGlobal; pers.setSession = setSession; pers.get = get; pers.getCookie = getCookie; pers.getGlobal = getGlobal; pers.getSession = getSession; pers.clear = clear; })(pers || (pers = {})); $.fn.sortElements = (function () { var sort = [].sort; return function (comparator, getSortable) { getSortable = getSortable || function () { return this; }; var placements = this.map(function () { var sortElement = getSortable.call(this), parentNode = sortElement.parentNode, // Since the element itself will change position, we have // to have some way of storing its original position in // the DOM. The easiest way is to have a 'flag' node: nextSibling = parentNode.insertBefore( document.createTextNode(''), sortElement.nextSibling ); return function () { if (parentNode === this) { throw new Error("You can't sort elements if any one is a descendant of another."); } // Insert before flag: parentNode.insertBefore(this, nextSibling); // Remove flag: parentNode.removeChild(nextSibling); }; }); return sort.call(this, comparator).each(function (i) { placements[i].call(getSortable.call(this)); }); }; })(); $.fn.outerHTML = function () { return $('<div>').append(this.clone()).remove().html(); }; /** * Create a dialog box on a fixed position with self closing functionality * @param {string} id The DOM ID of the div * @param content .title: Short title. Defaults to Sangu Package. * .body: The HTML to show in the body of the tooltip * @param options .top: CSS top in px * .left: CSS left in px * .width: CSS width in px. Defaults to 350. * .showOnce: If true the tooltip will never be shown again once closed. Defaults to true. */ function createFixedTooltip(id, content, options) { if (typeof options.width === 'undefined') { options.width = 350; } if (typeof options.showOnce === 'undefined') { options.showOnce = true; } if (typeof content.title === 'undefined') { content.title = "Sangu Package"; } var persKey = "fixedToolTip_"+id; // Other implementations depend on this naming if (!options.showOnce || pers.getGlobal(persKey) == '') { content_value.after('<div id="' + id + '" class="vis" style="z-index: 100001; margin: 2px; ' + 'width: '+options.width+'px; display: block; position:absolute; top: '+options.top+'px; left: '+options.left+'px; border: 1px solid black; background-color: #F4E4BC">' + '<h4>' + '<img class="'+id+'closeTooltip" style="float: right; cursor: pointer;" src="graphic/minus.png">' + content.title + '</h4>' + '<div style="display: block; text-align: left; margin: 2px;">' + content.body + '</div>' + '</div>'); $("."+id+"closeTooltip", "#" + id).click(function() { $("#" + id).hide(); if (options.showOnce) { pers.setGlobal(persKey, "1"); } }); } } function createSpoiler(button, content, opened) { return "<div id='spoiler'><input type='button' value='" + button + "' onclick='toggle_spoiler(this)' /><div><span style='display:" + (opened ? 'block' : 'none') + "'>" + content + "</span></div></div>"; } function createMoveableWidget(id, title, content) { return '<div id=' + id + '+ class="vis moveable widget"><h4><img style="float: right; cursor: pointer;"' + ' onclick="return VillageOverview.toggleWidget(\'' + id + '\', this);" src="graphic/minus.png">' + title + '</h4><div style="display: block;">' + content + '</div></div>'; } function printCoord(village, desc) { if (server_settings.coordinateLinkAllowed) { return "<a href=# onclick=\"$('#inputx').val("+village.x+"); $('#inputy').val("+village.y+"); return false;\">" + desc + "</a>"; } else { return "<b>" + desc + "</b> <input type=text onclick='this.select(); this.focus()' size=7 value='" + village.x + '|' + village.y + "'>"; } } // Activate / deactivate the tool var isSanguActive = pers.get("sanguActive") == "true"; if (location.href.indexOf('changeStatus=') > -1) { isSanguActive = location.href.indexOf('changeStatus=true') > -1; pers.set("sanguActive", isSanguActive); pers.setGlobal("fixedToolTip_sanguActivatorTooltip", 1); } var activatorImage = isSanguActive ? "green" : 'red'; var activatorTitle = (!isSanguActive ? trans.sp.sp.activatePackage : trans.sp.sp.deactivatePackage) + " (v" + sangu_version + ")"; function isSanguCompatible() { return sangu_version.indexOf(game_data.majorVersion) === 0; } // Check for new version var loginMonitor = pers.get("sanguLogin"); if (typeof GM_xmlhttpRequest !== "undefined" && !isSanguCompatible() && loginMonitor !== '') { var parts = loginMonitor.match(/(\d+)/g); if (parseInt(parts[2], 10) != (new Date()).getDate()) { GM_xmlhttpRequest({ method: "GET", url: "http://www.sangu.be/api/sangupackageversion.php", onload: function (response) { console.log(response.status, response.responseText.substring (0, 80)); } }); } } if (pers.get("forceCompatibility") === '' || pers.get("forceCompatibility") === 'false') { if (isSanguActive) { // Check compatibility with TW version if (!isSanguCompatible()) { try { ScriptAPI.register('Sangu Package', sangu_version, 'Laoujin', server_settings.sanguEmail); } catch (e) { $("#script_list a[href$='mailto:"+server_settings.sanguEmail+"']").after(" <a href='' id='removeScriptWarning'>"+trans.sp.sp.removeScriptWarning+"</a>"); $("#removeScriptWarning").click(function() { pers.set("forceCompatibility", "true"); }); } } } // gray icon when tw version doesn't match if (!isSanguCompatible()) { activatorImage = "grey"; activatorTitle = trans.sp.sp.activatePackageWithCompatibility.replace("{version}", sangu_version); } } $("#storage").parent() .after( "<td class='icon-box' nowrap><a href=" + location.href.replace("&changeStatus=" + isSanguActive, "") + "&changeStatus=" + (!isSanguActive) + "><img src='graphic/dots/" + activatorImage + ".png' title='" + activatorTitle + "' id='sangu_activator' /></a> </td>"); // First time run message - Position beneath resource/storage display if (!isSanguActive) { (function() { var position = $("#storage").position(), options = { left: position.left - 150, top: position.top + 35 }, content = {body: trans.sp.sp.firstTimeRun.replace("{img}", "<img src='graphic/dots/red.png' />")}; createFixedTooltip("sanguActivatorTooltip", content, options); }()); } else { (function() { var position = $("#storage").position(), options = { left: position.left - 150, top: position.top + 35 }, 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!'}; createFixedTooltip("twTacticsTooltip", content, options); }()); } // User config // Configure the Sangu Package /* user_data = pers.get('sangusettings'); if (user_data !== '') { user_data = JSON.parse(user_data); } else {*/ user_data = { proStyle: true, displayDays: false, /* true: display (walking)times in days when > 24 hours. false: always displays in hours */ walkingTimeDisplay: "{duration} || {arrival}", colors: { error: "#FF6347", good: "#32CD32", special: "#00FFFF", neutral: "#DED3B9" }, global: { resources: { active: true, /* All pages: true/false: color the resources based on how much the storage is filled */ 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 */ blinkWhenStorageFull: true /* All pages: Blink the resources if the storage is full */ }, incomings: { editLinks: true, /* All pages: Edit the incoming attacks/support links: add "show all groups" and "show all pages" to the original links */ track: true, indicator: "({current} <small>{difference}</small>)", indicatorTooltip: "Laatste tijdcheck: {elapsed} geleden", lastTimeCheckWarning: "Aanvallen: {difference}. Laatste tijdcheck: {elapsed} geleden" }, visualizeFriends: true, duplicateLogoffLink: false }, scriptbar: { editBoxCols: 700, editBoxRows: 12 }, main: { 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'] */ 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 */ ajaxLoyalty: true /* Get the loyalty at the building construction/destruction page */ }, other: { calculateSnob: true, /* nobles: calculates how many nobles can be produced immediately */ reportPublish: ["own_units", "own_losses", "opp_units", "opp_losses", "carry", "buildings", "own_coords", "opp_coords", "belief"] /* Publishing report: automatically check the 'show' checkboxes */ }, market: { resizeImage: true, autoFocus: true }, farmLimit: { stackColors: ['#DED3B9', '#3CB371', '#FF6347'], acceptableOverstack: [0.5, 1.2, 1.35], /* Different pages: % of acceptable overstack (only relevant for farmlimit worlds) */ unlimitedStack: [24000, 60000, 100000] /* Different pages: Calculate stacks based on total troops (for non farmlimit worlds) */ }, command: { /* features for the own troops overview page */ changeTroopsOverviewLink: true, /* Change the link to the own troops overview */ middleMouseClickDeletesRow2: false, /* Let the new default overwrite the old one */ filterMinPopulation: 18000, /* Default number filled in to filter on village stack */ filterMinDefaultType: 'axe', /* This unit type is by default selected in the filter dropdown */ filterMinDefault: 5000, /* The default number filled in to filter on troop amounts */ 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 */ filterMinOther: 5000, /* Use this number as the default when the unit is not present in filterMin */ filterAutoSort: true, /* Automatically sort the list on walking distance when entering a target village */ /* These features apply to the commands overview page */ sumRow: true, /* Add a totalrow between different villages */ filterFakeMaxPop: 300, /* Commands fake filter: Everything below 300 pop is considered a fake attack */ bbCodeExport: { /* BB code export */ requiredTroopAmount: 100 } }, incomings: { attackIdDescriptions: [ {minValue: 10, text: " "}, {minValue: 50, text: "10-50"}, {minValue: 100, text: "50-100"}, {minValue: 200, text: "100-200"}, {minValue: 500, text: "200-500"}, {minValue: 1000, text: "500-1000"}, {minValue: 5000, text: "1000-5000"} ], attackIdHigherDescription: "5000+" }, overviews: { addFancyImagesToOverviewLinks: true }, incoming: { /* Features for the built in TW tagger */ autoOpenTagger: true, /* Open the tagger automatically if the incoming attack has not yet been renamed */ forceOpenTagger: true, /* Always open the tagger automatically */ 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. */ villageBoxSize: 600, /* Adjust the width of the table with the village information (support for 2-click) */ invertSort: true /* true=noblemen at the top and scouts at the bottom of the table */ }, overview: { /* The default village overview page */ ajaxSeperateSupport: true, /* Village overview: Seperate own and supported troops */ ajaxSeperateSupportStacks: true, /* Village overview: Calculate stacks for own and supported troops */ canHideDiv: true }, mainTagger2: { active: true, autoOpen: true, inputBoxWidth: 300, defaultDescription: "{xy} OK", otherDescs: [ { active: true, name: "Dodgen", hitKey: "D", renameTo: "{xy}----------------------------------------- DODGE THIS" }, { active: true, name: "Nacht", hitKey: "N", renameTo: "{xy} NIGHTBONUS" }, { active: true, name: "Check stack", hitKey: "P", renameTo: "{xy}----------------------------------------- CHECK STACK" }, { active: true, name: "Timen!", hitKey: "T", renameTo: "{xy}***************************************** TIME IT!" }, { active: true, name: "Edelen!", hitKey: "E", renameTo: "{xy}----------------------------------------- NOBLE!!" }, { active: false, name: "Leeg1", hitKey: "L", renameTo: "It has to be, automatically" }, { active: false, name: "Leeg2", hitKey: "U", renameTo: "Check it out, you'd better work it out" }, { active: false, name: "Leeg3", hitKey: "Y", renameTo: "Change to another route" }, { active: false, name: "Leeg4", hitKey: "O", renameTo: "My techniques, strategies, abilities" } ], keepReservedWords: true, reservedWords: [ "Edel.", "Edelman", "Ram", "Kata.", "Katapult", "Zcav.", "Zware cavalerie", "Lcav.", "Lichte Cavalerie", "Bereden boog", "Bboog.", "Verk.", "Verkenner", "Bijl", "Zwaard", "Speer", "Boog", "Ridder" ], autoOpenCommands: false, minutesDisplayDodgeTimeOnMap: 3, minutesWithoutAttacksDottedLine: 3 * 60, colorSupport: '#FFF5DA' /* Main village overview: give incoming support a different background color */ }, villageInfo4: [ { /* On info_village page add extra link to attack. */ active: true, off_link: { name: "Aanvalleuh!", group: 0, filter: { active: true, unit: "axe", amount: 5000 }, sort: true, changeSpeed: "ram", icon: "graphic/unit/unit_knight.png" }, def_link: { name: "Verdedigen!", group: 0, filter: { active: true, unit: "spear", amount: 4000 }, sort: true, changeSpeed: "spear", icon: "graphic/command/support.png" } }, { /* On info_village page add extra link to attack. */ active: false, off_link: { name: "» off2", group: 0, filter: { active: false, unit: "axe", amount: 4000 }, sort: true, changeSpeed: "ram" }, def_link: { name: "» Snelle Os!", group: 0, filter: { active: true, unit: "spear", amount: 1000 }, sort: true, changeSpeed: "spear" } } ], resources: { requiredResDefault: 250000, requiredMerchants: 50, filterMerchants: true, filterRows: false, bbcodeMinimumDiff: 50000, highlightColor: "#FF7F27" }, jumper: { enabled: true, autoShowInputbox: false }, attackAutoRename: { active: true, addHaul: false }, confirm: { addExtraOkButton: false, replaceNightBonus: true, replaceTribeClaim: true, addCatapultImages: true }, place: { attackLinks: { scoutVillage: 100, scoutPlaceLinks: [5, 100, 500], scoutPlaceLinksName: "Scout{amount}", fakePlaceLink: true, fakePlaceExcludeTroops: [], fakePlaceLinkName: "Fake", noblePlaceLink: true, /* (de)Activate all noble links */ noblePlaceLinkFirstName: "NobleFirst", /* Name for the first noble which has most troops */ noblePlaceLinkSupportName: "NobleMin", /* snob with only minimal support */ noblePlaceLinksForceShow: true, /* Show NobleMin also where is only one 1 snob in the village */ nobleSupport: [ { amount: 50, unit: 'light', villageType: 'off' }, { amount: 50, unit: 'heavy', villageType: 'def'} ], noblePlaceLinkDivideName: "NobleDivide", noblePlaceLinkDivideAddRam: false /* false: Rams are not sent along with NobleDivide */ }, customPlaceLinks: [ // use minus zero numbers to leave so many units at home { active: true, type: 'def', name: 'AllDef', spear: 25000, heavy: 5000, archer: 25000, sword: 25000, sendAlong: 0 }, { active: true, type: 'def', name: '1/2-Zc', spear: 4000, heavy: 1000, sendAlong: 500 }, { 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 }, { active: true, type: 'off', name: 'Bijl', spear: 25000, axe: 25000, spy: 1, light: 5000, heavy: 5000, marcher: 5000, sendAlong: 0 }, { 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] }, { active: false, type: 'def', name: 'AlleDef', spear: 25000, sword: 25000, heavy: 5000, archer: 25000, sendAlong: 0 }, { active: false, type: 'def', name: '3deZc', spear: 2500, heavy: 650, sendAlong: 0 }, { active: false, type: 'def', name: '4deZc', spear: 2000, heavy: 500, sendAlong: 0 }, { active: false, type: 'def', name: 'HelftZw', spear: 5000, sword: 5000, sendAlong: 500 }, { active: false, type: 'def', name: '3deZw', spear: 3300, sword: 3300, sendAlong: 0 }, { active: false, type: 'def', name: '4deZw', spear: 2500, sword: 2500, sendAlong: 0 } ] }, /** * units_support_detail: options on the 2 def troop overview pages * on bbcode restack - and others!!) */ restack: { to: 72000, requiredDifference: 1000, fieldsDistanceFilterDefault: 30, filterReverse: true, autohideWithoutSupportAfterFilter: true, calculateDefTotalsAfterFilter: true, defaultPopulationFilterAmount: 80000, /* this isn't related to restack */ removeRowsWithoutSupport: false }, showPlayerProfileOnVillage: false, profile: { show: true, moveClaim: true, mapLink: { show: true, fill: '#000000', zoom: '200', grid: true, playerColor: '#ffff00', tribeColor: '#0000FF', centreX: 500, centreY: 500, ownColor: '#FFFFFF', markedOnly: true, yourTribeColor: "#FF0000" }, playerGraph: [["points", false], ["villages", false], ["od", false], ["oda", false], ["odd", false], ["rank", false]], // small / big / false tribeGraph: [["points", false], ["villages", false], ["od", false], ["oda", false], ["odd", false], ["rank", false], ["members", 'big', true]], twMapPlayerGraph: { player: [true, true], p_player: [false, false], oda_player: [true, false], odd_player: [true, false], ods_player: [true, false] }, twMapTribeGraph: { tribe: [true, true], p_tribe: [false, false], oda_tribe: [true, false], odd_tribe: [true, false] }, popup: { show: true, width: 900, height: 865, left: 50, top: 50 } }, smithy: [ ['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]}], ['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]}], ['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]}] ], buildings: { main: [20, 20], barracks: [25, 25], stable: [20, 20], garage: [1, 5], church: [0, 1], church_f: [0, 1], snob: [1, 3], smith: [20, 20], place: [1, 1], statue: [0, 1], market: [10, 20], wood: [30, 30], stone: [30, 30], iron: [30, 30], farm: [30, 30], storage: [30, 30], hide: [0, 10], wall: [20, 20] } }; //} (function() { var saved_data = pers.get('sangusettings'); if (saved_data !== '') { user_data = $.extend(true, user_data, JSON.parse(saved_data)); } }()); if (isSanguActive) { // world config: global game settings world_config = { hasMilitia: false, nightbonus: { active: false, from: 0, till: 0 }, smithyLevels: true, hasChurch: false, hasArchers: false, hasKnight: false, speed: 1, unitSpeed: 1, farmLimit: 0, minFake: 0, hasMinFakeLimit: false, coins: false, maxNobleWalkingTime: 999 }; if (pers.get('worldconfig') !== '') { world_config = JSON.parse(pers.get("worldconfig")); } else { // load new world through tw API if (server_settings.ajaxAllowed) { function world_config_setter_unit(configBag, unitInfoXml) { configBag.hasMilitia = $("config militia", unitInfoXml).length !== 0; } function world_config_setter(configBag, infoXml) { configBag.nightbonus = { active: $("night active", infoXml).text() === "1", from: parseInt($("night start_hour", infoXml).text(), 10), till: parseInt($("night end_hour", infoXml).text(), 10) }; configBag.smithyLevels = $("game tech", infoXml).text() === "1" || $("game tech", infoXml).text() === "0"; configBag.hasChurch = $("game church", infoXml).text() !== "0"; configBag.hasArchers = $("game archer", infoXml).text() !== "0"; configBag.hasKnight = $("game knight", infoXml).text() !== "0"; configBag.speed = parseFloat($("config speed", infoXml).text()); configBag.unitSpeed = parseFloat($("config unit_speed", infoXml).text()); configBag.farmLimit = parseInt($("game farm_limit", infoXml).text(), 10); configBag.minFake = parseInt($("game fake_limit", infoXml).text(), 10) / 100; configBag.hasMinFakeLimit = configBag.minFake > 0; configBag.coins = $("snob gold", infoXml).text() === "1"; configBag.maxNobleWalkingTime = parseInt($("snob max_dist", infoXml).text(), 10) * configBag.speed * configBag.unitSpeed; } function world_config_getter(world) { // world nl: http://nl16.tribalwars.nl/ // world de: http://de90.die-staemme.de/ if (typeof world === 'undefined') world = ''; var world_config = {}; $.ajax({ url: world + "interface.php?func=get_unit_info", async: false, success: function(xml) { world_config_setter_unit(world_config, xml); } }); $.ajax({ url: world + "interface.php?func=get_config", async: false, success: function(xml) { world_config_setter(world_config, xml); } }); return world_config; } world_config = world_config_getter(); } else { // Not allowed to get data with ajax: need to store the configuration here //world_config = (function() { // paste the world configurations for all worlds on servers that disallow ajax //})(); alert("No configurations present for this server! (see world_config.js)\nContinueing with default settings."); } pers.set("worldconfig", JSON.stringify(world_config)); } // world config // RESOURCES world_data.resources = ['holz', 'lehm', 'eisen']; world_data.resources_en = ['wood', 'stone', 'iron']; // BUILDINGS world_data.buildingsSize = [ ["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]], ["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]], ["stable", [8, 9, 11, 13, 15, 18, 21, 24, 28, 33, 38, 45, 53, 62, 72, 84, 99, 115, 135, 158]], ["garage", [8, 9, 11, 13, 15, 18, 21, 24, 28, 33, 38, 45, 53, 62, 72]], ["snob", [80, 94, 110]], ["smith", [20, 23, 27, 32, 37, 44, 51, 60, 70, 82, 96, 112, 132, 154, 180, 211, 247, 289, 338, 395]], ["place", [0]], ["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]], ["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]], ["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]], ["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]], ["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]], ["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]], ["hide", [2, 2, 3, 3, 4, 4, 5, 6, 7, 8]], ["wall", [5, 6, 7, 8, 9, 11, 13, 15, 18, 21, 24, 28, 33, 38, 45, 53, 62, 72, 84, 99]] ]; world_data.buildingsPoints = [ ["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]], ["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]], ["stable", [20, 24, 29, 35, 41, 50, 60, 72, 86, 103, 124, 149, 178, 214, 257, 308, 370, 444, 532, 639]], ["garage", [24, 29, 35, 41, 50, 60, 72, 86, 103, 124, 149, 178, 214, 257, 308]], ["snob", [512, 614, 737]], ["smith", [19, 23, 27, 33, 39, 47, 57, 68, 82, 98, 118, 141, 169, 203, 244, 293, 351, 422, 506, 607]], ["place", [0]], ["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]], ["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]], ["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]], ["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]], ["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]], ["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]], ["hide", [5, 6, 7, 9, 10, 12, 15, 18, 21, 26]], ["wall", [8, 10, 12, 14, 17, 20, 24, 29, 34, 41, 50, 59, 71, 86, 103, 123, 148, 177, 213, 256]] ]; world_data.buildings = ["main", "barracks", "stable", "garage"]; if (world_config.hasChurch) { world_data.buildingsSize.push(["church", [5000, 7750, 12013]]); world_data.buildingsSize.push(["church_f", [5]]); world_data.buildings.push("church"); } world_data.buildings = world_data.buildings.concat(["snob", "smith", "place"]); if (world_config.hasKnight) { world_data.buildingsSize.push(["statue", [10]]); world_data.buildingsPoints.push(["statue", [24]]); world_data.buildings.push("statue"); } world_data.buildings = world_data.buildings.concat(["market", "wood", "stone", "iron", "farm", "storage", "hide", "wall"]); // UNITS 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 }; 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 }; world_data.units_def = ["spear", "sword", "heavy"]; world_data.units_off = ["axe", "light", "heavy"]; if (!world_config.hasArchers && !world_config.hasKnight) { world_data.unitsPositionSize = [1, 1, 1, 2, 4, 6, 5, 8, 100]; world_data.units = ["spear", "sword", "axe", "spy", "light", "heavy", "ram", "catapult", "snob"]; } else { world_data.units = ["spear", "sword", "axe"]; world_data.unitsPositionSize = [1, 1, 1]; if (world_config.hasArchers) { world_data.units_off.push("marcher"); world_data.units_def.push("archer"); $.extend(world_data.unitsSize, { "unit_archer": 1 }, { "unit_marcher": 5 }); $.extend(world_data.unitsSpeed, { "unit_archer": 18 }, { "unit_marcher": 10 }); world_data.units.push("archer"); world_data.unitsPositionSize.push(1); } world_data.units.push("spy"); world_data.unitsPositionSize.push(2); world_data.units.push("light"); world_data.unitsPositionSize.push(4); if (world_config.hasArchers) { world_data.units.push("marcher"); world_data.unitsPositionSize.push(5); } world_data.units.push("heavy"); world_data.unitsPositionSize.push(6); world_data.units.push("ram"); world_data.unitsPositionSize.push(5); world_data.units.push("catapult"); world_data.unitsPositionSize.push(8); if (world_config.hasKnight) { $.extend(world_data.unitsSize, { "unit_knight": 10 }); $.extend(world_data.unitsSpeed, { "unit_knight": 10 }); world_data.units.push("knight"); world_data.unitsPositionSize.push(10); } world_data.units.push("snob"); world_data.unitsPositionSize.push(100); } // Unit speed adjustments world_config.maxNobleWalkingTime *= world_data.unitsSpeed.unit_snob; var speedModifier = world_config.speed * world_config.unitSpeed; if (speedModifier != 1) { $.each(world_data.unitsSpeed, function (index, value) { world_data.unitsSpeed[index] = world_data.unitsSpeed[index] / speedModifier; }); } /** * Adds a . thousands separator */ function formatNumber(nStr) { nStr += ''; var x = nStr.split('.'); var x1 = x[0]; var x2 = x.length > 1 ? '.' + x[1] : ''; var rgx = /(\d+)(\d{3})/; while (rgx.test(x1)) { x1 = x1.replace(rgx, '$1' + '.' + '$2'); } return x1 + x2; } // DATETIME FUNCTIONS function prettyDate(diff, showSeconds) { diff = diff / 1000; if (diff < 0) { return " "; } if (diff < 60) { if (showSeconds) { return diff + " " + trans.sp.tagger.sentSeconds; } return trans.sp.tagger.sentNow; } if (diff < 120) { return trans.sp.tagger.sent1Minute; } if (diff < 3600) { return Math.floor(diff / 60) + " " + trans.sp.tagger.sentMinutes; } if (diff < 7200) { return trans.sp.tagger.sent1Hour + ", " + Math.floor((diff - 3600) / 60) + " " + trans.sp.tagger.sentMinutes; } return Math.floor(diff / 3600) + " " + trans.sp.tagger.sentHours + ", " + Math.floor((diff % 3600) / 60) + " " + trans.sp.tagger.sentMinutes; } function twDurationFormat(num) { var days = 0; if (user_data.displayDays) { days = Math.floor(num / 1440); } num -= days * 1440; var hours = Math.floor(num / 60); num -= hours * 60; var mins = Math.floor(num); num -= mins; var secs = Math.round(num * 60); if (days > 0) { return days + '.' + pad(hours, 2) + ':' + pad(mins, 2) + ':' + pad(secs, 2); } else { return pad(hours, 2) + ':' + pad(mins, 2) + ':' + pad(secs, 2); } } function twDateFormat(dat, alwaysPrintFullDate, addYear) { var day = dat.getDate(); var cur = new Date().getDate(); if (!alwaysPrintFullDate && day == cur) { return trans.tw.all.today + " " + pad(dat.getHours(), 2) + ':' + pad(dat.getMinutes(), 2) + ':' + pad(dat.getSeconds(), 2); } else if (!alwaysPrintFullDate && day == cur + 1) { return trans.tw.all.tomorrow + " " + pad(dat.getHours(), 2) + ':' + pad(dat.getMinutes(), 2) + ':' + pad(dat.getSeconds(), 2); } else if (addYear) { 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() + ")"; } else { 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() + ")"; } } function getTimeFromTW(str) { // NOTE: huh this actually returns the current date // with some new properties with the "str" time //17:51:31 var timeParts = str.split(":"); var seconds = timeParts[2]; var val = {}; val.hours = parseInt(timeParts[0], 10); val.minutes = parseInt(timeParts[1], 10); if (seconds.length > 2) { var temp = seconds.split("."); val.seconds = parseInt(temp[0], 10); val.milliseconds = parseInt(temp[1], 10); } else { val.seconds = parseInt(seconds, 10); } val.totalSecs = val.seconds + val.minutes * 60 + val.hours * 3600; return val; } function getDateFromTW(str, isTimeOnly) { //13.02.11 17:51:31 var timeParts, seconds; if (isTimeOnly) { timeParts = str.split(":"); seconds = timeParts[2]; var val = new Date(); val.setHours(timeParts[0]); val.setMinutes(timeParts[1]); if (seconds.length > 2) { var temp = seconds.split("."); val.setSeconds(temp[0]); val.setMilliseconds(temp[1]); } else { val.setSeconds(seconds); } return val; } else { var parts = str.split(" "); var dateParts = parts[0].split("."); timeParts = parts[1].split(":"); seconds = timeParts[2]; var millis = 0; if (seconds.length > 2) { var temp = seconds.split("."); seconds = temp[0]; millis = temp[1]; } if (dateParts[2].length == 2) { dateParts[2] = (new Date().getFullYear() + '').substr(0, 2) + dateParts[2]; } return new Date(dateParts[2], (dateParts[1] - 1), dateParts[0], timeParts[0], timeParts[1], seconds, millis); } } function getDateFromTodayTomorrowTW(str) { var currentT = new Date(); var dateParts = []; var parts = $.trim(str).split(" "); if (str.indexOf(trans.tw.all.tomorrow) != -1) { // morgen om 06:35:29 uur dateParts[0] = currentT.getDate() + 1; dateParts[1] = currentT.getMonth(); } else if (str.indexOf(trans.tw.all.today) != -1) { // vandaag om 02:41:40 uur dateParts[0] = currentT.getDate(); dateParts[1] = currentT.getMonth(); } else { // op 19.05. om 11:31:51 uur dateParts = parts[1].split("."); dateParts[1] = parseInt(dateParts[1], 10) - 1; } // last part is "hour" but there is a script from lekensteyn that // corrects the projected arrival time each second // the script has not been updated to add the word "hour" after the time. var timeParts = parts[parts.length - 2].split(":"); if (timeParts.length === 1) { timeParts = parts[parts.length - 1].split(":"); } var seconds = timeParts[2]; var millis = 0; if (seconds.length > 2) { var temp = seconds.split("."); seconds = temp[0]; millis = temp[1]; } return new Date(new Date().getFullYear(), dateParts[1], dateParts[0], timeParts[0], timeParts[1], seconds, millis); } function isDateInNightBonus(date) { if (!world_config.nightbonus.active) return false; return date.getHours() >= world_config.nightbonus.from && date.getHours() < world_config.nightbonus.till; } function getBuildingSpace() { var total = 0; for (var building = 0; building < world_data.buildingsSize.length; building++) { var b = world_data.buildingsSize[building]; if (parseInt(game_data.village.buildings[b[0]], 10) > 0) { total += b[1][parseInt(game_data.village.buildings[b[0]], 10) - 1]; } } return total; } function getBuildingPoints() { var total = 0; for (var building = 0; building < world_data.buildingsPoints.length; building++) { var b = world_data.buildingsPoints[building]; if (parseInt(game_data.village.buildings[b[0]], 10) > 0) { total += b[1][parseInt(game_data.village.buildings[b[0]], 10) - 1]; } } return total; } if (user_data.jumper.enabled) { (function() { //console.time("jumper"); try { var cell = "<span style='display: none;' id=sanguJumperFrame>"; cell += "<input type=text type=text size=6 id=sangujumper style='height: 16px; border: 0; top: -2px; position: relative'>"; cell += "</span>"; cell += " <a href=# id=sangujumperOpen><span class='icon ally internal_forum' title='" + trans.sp.jumper.goToMap + "'></span></a>"; $("#menu_row2").append("<td>" + cell + "</td>"); $("#sangujumper").keyup(function (e) { if (e.which == 13) { $("#sangujumperOpen").click(); } }); $("#sangujumperOpen").click(function () { var input = $("#sangujumper"); if ($("#sanguJumperFrame").is(":visible")) { var village = getVillageFromCoords(input.val(), true); if (village.isValid) { trackClickEvent("JumperOpen_RealValue"); // Jump to coordinates on the map location.href = getUrlString("&screen=map&x=" + village.x + "&y=" + village.y); } else { // incorrect coordinates if (!$("#sangujumperpos").is(":visible")) { $("#sangujumperpos").show(); input.css("border", "1px solid red"); } else $("#sangujumperpos").hide(); } } else { // activate mapJumper var input = $("#sangujumper"); if (input.val() == "") { $("#sanguJumperFrame").fadeIn(); } else { $("#sanguJumperFrame").show(); $("#sangujumperOpen").click(); } } return false; }); if (user_data.jumper.autoShowInputbox) { $("#sangujumperOpen").click(); } } catch (e) { handleException(e, "jumper"); } //console.timeEnd("jumper"); }()); } // Send usage statistics to GA once/day (function() { //console.time("ga"); try { var loginMonitor = pers.get("sanguLogin"); if (loginMonitor !== '') { var parts = loginMonitor.match(/(\d+)/g); loginMonitor = new Date(parts[0], parts[1]-1, parts[2]); //if (Math.abs(loginMonitor.getTime() - (new Date()).getTime()) > 1000 * 3600 * 24) { if (parseInt(parts[2], 10) != (new Date()).getDate()) { loginMonitor = ''; } } if (loginMonitor === '') { loginMonitor = new Date(); loginMonitor.setHours(0, 0, 0); loginMonitor = loginMonitor.getFullYear() + '-' + pad(loginMonitor.getMonth()+1, 2) + '-' + pad(loginMonitor.getDate(), 2); trackEvent("ScriptUsage", "DailyUsage", loginMonitor); pers.set("sanguLogin", loginMonitor); // also log world/tribe usage trackEvent("ScriptUsage", "WorldUsage", game_data.world); trackEvent("ScriptUsage", "TribeUsage", game_data.world + " " + game_data.player.ally_id); trackEvent("ScriptUsage", "HasPremium", game_data.player.premium ? "Yes" : "No"); // Do we need to support non PA users? trackEvent("ScriptUsage", "HasAM", game_data.player.account_manager ? "Yes" : "No"); // Do we need to do stuff on the AM pages? } } catch (e) { handleException(e, "ga"); } //console.timeEnd("ga"); }()); q("-------------------------------------------------------------------- Start: "+sangu_version); // BEGIN PAGE PROCESSING switch (current_page.screen) { case "overview": // MAIN VILLAGE OVERVIEW (function() { /** * The slowest unit in the village in the form unit_spear */ var slowest_unit = null; (function() { /** * Each key is in the form unit_sword and holds the total amount of the type in the village * (own and supporting troops combined) */ var totalUnits = {}, /** * Total population of all units (own + supporting) */ totalFarm = 0, /** * Own population only (total - supporting) */ ownFarmTotal = 0, /** * jQuery div with the troops in the village (becomes the own troops only div) */ unitTable = $("#show_units"), /** * HTML table builder string for the supporting troops div */ supportingTroopsTable = "<table class=vis width='100%'>"; try { $("#show_units > h4").prepend(trans.sp.main.unitsReplacement); // calculate current stack $("table:first td", unitTable).not(":last").each(function () { var unit = $('img', this)[0].src, unitsSize, unitAmount; unit = unit.substr(unit.lastIndexOf('/') + 1); unit = unit.substr(0, unit.lastIndexOf('.')); unitsSize = world_data.unitsSize[unit]; unitAmount = $('strong', this); unitAmount[0].id = "spAmount" + unit; unitAmount = unitAmount[0].innerHTML; if( unit.match("knight") && !unitAmount ) { unitAmount = 1; } totalUnits[unit] = unitAmount; totalFarm += unitsSize * unitAmount; if (slowest_unit == null || world_data.unitsSpeed[slowest_unit] < world_data.unitsSpeed[unit]) { slowest_unit = unit; } }); // fetch own troops if (user_data.overview.ajaxSeperateSupport && totalFarm > 0) { if (server_settings.ajaxAllowed) { ajax("place", function (placeText) { if (placeText.find(".unitsInput").size() > 0) { slowest_unit = null; placeText.find(".unitsInput").each(function () { // separate own / supporting troops var unit = 'unit_' + this.id.substr(this.id.lastIndexOf("_") + 1); var unitAmount = $(this).next().text().substr(1); unitAmount = parseInt(unitAmount.substr(0, unitAmount.length - 1), 10); var unitsSize = world_data.unitsSize[unit]; ownFarmTotal += unitsSize * unitAmount; var unitLabel = $("#spAmount" + unit); var supportingTroopsAmount = totalUnits[unit] - unitAmount; if (supportingTroopsAmount > 0) { var unitDesc = $.trim(unitLabel.parent().text()); unitDesc = unitDesc.substr(unitDesc.indexOf(" ") + 1); supportingTroopsTable += "<tr><td>" + unitLabel.prev().outerHTML() + " <b>" + formatNumber(supportingTroopsAmount) + "</b> " + unitDesc + "</td></tr>"; } if (unitAmount > 0) { unitLabel.text(unitAmount); if (slowest_unit == null || world_data.unitsSpeed[slowest_unit] < world_data.unitsSpeed[unit]) { slowest_unit = unit; } } else { unitLabel.parent().parent().hide(); } }); } else { ownFarmTotal = totalFarm; // No rally point } }, {async: false}); } else { ownFarmTotal = totalFarm; // No ajax } if (slowest_unit != null) { $("#slowestUnitCell").html("<img title='"+trans.sp.tagger.slowestTip+"' src='graphic/unit/" + slowest_unit + ".png'>").attr("slowestUnit", slowest_unit); } if (ownFarmTotal > 0 && user_data.overview.ajaxSeperateSupportStacks) { // stack in the village unitTable.find("table:first").append("<tr><td><span class='icon header population' title='" + trans.sp.main.ownStackTitle + "'></span>" + stackDisplay(ownFarmTotal).desc + "</td></tr>"); } if (totalFarm - ownFarmTotal > 0) { // stack from other villages supportingTroopsTable += "<tr><td><a href='" + getUrlString("screen=place&mode=units") + "'>» " + trans.sp.main.rallyPointTroops + "</a></td></tr>"; if (user_data.overview.ajaxSeperateSupportStacks) { (function() { var supportDisplay = stackDisplay(totalFarm - ownFarmTotal, { showFarmLimit: true }); supportingTroopsTable += '<tr><td style="border-top: 1px solid #85550d ;background-color: ' + supportDisplay.color + '">' + '<span class="icon header population" title="' + trans.sp.main.supportingStackTitle + '"></span>' + '<b>' + supportDisplay.desc + '</b>' + '</td></tr>'; }()); } unitTable.after(createMoveableWidget("os_units", trans.sp.main.unitsOther, supportingTroopsTable + "</table>")); } // total stack (function() { var cell = $("#order_level_farm"), isClassicOverview = cell.length !== 0, percentage, stackDetails, cellContent; if (isClassicOverview) { cell = cell.parent(); if (game_data.player.premium) { cell = cell.next(); } percentage = world_config.farmLimit == 0 ? "" : cell.children().html(); stackDisplay( totalFarm, { showFarmLimit: true, percentage: percentage ? percentage.substr(0, percentage.indexOf('%') + 1) : "", cell: cell, appendToCell: !game_data.player.premium }); } else { stackDetails = stackDisplay( totalFarm, { showFarmLimit: true, percentage: $("#l_farm .building_extra").html() }); //cellContent = '<tr><td style="border-top: 1px solid #85550d ;background-color: ' + stackDetails.color + '">' + '<b>' + trans.tw.all.farm + ': ' + stackDetails.desc + '</b>' + '</td></tr>'; cellContent = ' | <b>' + trans.tw.all.farm + ': ' + stackDetails.desc + '</b>'; $("#show_units tbody:first td:last").append(cellContent).css("border-top", "1px solid #85550d").css("background-color", stackDetails.color); } }()); } } catch (e) { handleException(e, "supportingunits"); } }()); // Incoming/outgoing attacks var mainTable = $("#overviewtable"); var incomingTable = $("#show_incoming_units table.vis:first"); var outgoingTable = $("#show_outgoing_units"); if (incomingTable.size() == 1 || outgoingTable.size() == 1) { if (incomingTable.size() == 1) { // tagger - add header // inputBoxWidth : clicking the button focusses the newly created inputbox // solution is to no longer show inputboxes on screen load /*if (user_data.mainTagger2.inputBoxWidth != null) { $("a.rename-icon", incomingTable).click(); $("span.quickedit", incomingTable).each(function() { var renameSpan = this; //setTimeout(function() { $("span.quickedit-edit input:first", renameSpan).width(user_data.mainTagger2.inputBoxWidth); //}, 1); }); }*/ if (user_data.mainTagger2.active && incomingTable.has("img[src*='attack']").size() != 0) { $("th:first", incomingTable).append("<input type=button value='" + trans.sp.tagger.openButton + "' id=openTaggerButton>"); $("#openTaggerButton").click(function () { $(this).hide(); incomingTable.click(function (e) { if (e.target.nodeName === 'IMG') { var direction = $(e.target).attr("direction"); if (direction.length > 0) { var rowIndex = parseInt($(e.target).attr("rowIndex"), 10); direction = direction == "up"; $("input.incAt", incomingTable).each( function () { var rowIndexAttributeValue = parseInt($(this).attr("rowIndex"), 10); if ((direction && rowIndexAttributeValue <= rowIndex) || (!direction && rowIndexAttributeValue >= rowIndex)) { $(this).prop("checked", true); } else { $(this).prop("checked", false); } }); } } }); var rows = $("tr", incomingTable); var dodgeMenu = "<tr><td>"; dodgeMenu += '<img src="graphic/command/support.png" alt="" id="checkSupport" title="' + trans.sp.tagger.checkAllSupport + '" />'; dodgeMenu += " "; dodgeMenu += '<img src="graphic/command/return.png" alt="" id="uncheckSupport" title="' + trans.sp.tagger.uncheckAllSupport + '" />'; dodgeMenu += "<th colspan=3>"; dodgeMenu += trans.sp.tagger.renameTo + "<input type=textbox size=30 id=commandInput value='" + user_data.mainTagger2.defaultDescription + "'></th>"; dodgeMenu += "<th>" + trans.sp.tagger.slowest + "</th>"; dodgeMenu += "</td>"; dodgeMenu += "<td colspan=1 id=slowestUnitCell>"; if (slowest_unit != null) { dodgeMenu += "<img title='"+trans.sp.tagger.slowestTip+"' src='graphic/unit/" + slowest_unit + ".png' slowestunit='" + slowest_unit + "'>"; } dodgeMenu += "</td></tr>"; incomingTable.find("tbody:first").prepend(dodgeMenu); // checkbox manipulation $("#uncheckSupport").click(function () { $("input.incSupport", incomingTable).prop("checked", false); }); $("#checkSupport").click(function () { $("input.incSupport", incomingTable).prop("checked", true); }); var buttonParent = $("#commandInput").parent(); var commandIdToCoordCache = []; // No Ajax call on multiple renames with {xy} function renameCommand(commandName) { var dodgeCell; // capture last cell for dodgeCell coloring function getCommandIdFromDodgeCell(dodgeCell) { return Number(dodgeCell.find("span.quickedit").first().attr("data-id")); } function getVillageCoordsFromCommandId(commandId, callback) { if (server_settings.ajaxAllowed) { if (commandIdToCoordCache[commandId]) { callback(commandIdToCoordCache[commandId]); } else { ajax('screen=info_command&type=other&id='+commandId, function (overview) { var originVillageLink = $(".village_anchor:first", overview).find("a[href]"), originVillageDesc = originVillageLink.html(), originVillage = getVillageFromCoords(originVillageDesc); commandIdToCoordCache[commandId] = originVillage.coord; callback(originVillage.coord); }); } } callback(''); } function executeRename(dodgeCell, commandName) { function keepTwIcon(dodgeCell, commandName) { var oldName = $(".quickedit-label", dodgeCell).text().toUpperCase(), newName = commandName, i, unitName; for (i = 0; i < user_data.mainTagger2.reservedWords.length; i++) { unitName = user_data.mainTagger2.reservedWords[i]; if (oldName.indexOf(unitName.toUpperCase()) !== -1) { newName = unitName + ' ' + newName; return newName; // Only one icon possible } } return newName; } var button = dodgeCell.find("input[type='button']"), newName = user_data.mainTagger2.keepReservedWords ? keepTwIcon(dodgeCell, commandName) : commandName; button.prev().val(newName); button.click(); } $("input.taggerCheckbox", incomingTable).each(function () { var openRenameButton; if ($(this).is(":checked")) { dodgeCell = $(this).parent().next(); openRenameButton = $("a.rename-icon", dodgeCell); if (openRenameButton.is(":visible")) { openRenameButton.click(); } if (commandName.indexOf("{xy}") !== -1) { getVillageCoordsFromCommandId(getCommandIdFromDodgeCell(dodgeCell), function(vilCoords) { var nameWithCoords = commandName.replace("{xy}", vilCoords); setTimeout(executeRename(dodgeCell, nameWithCoords),150); }); } else { setTimeout(executeRename(dodgeCell, commandName),150); } } }); if (dodgeCell != null) { var unitSpeed = $("#slowestUnitCell img").attr("slowestunit"); if (unitSpeed != undefined) { dodgeCell = dodgeCell.parent().find("td").last().prev(); pers.setCookie("sanguDodge" + getQueryStringParam("village"), unitSpeed + "~" + dodgeCell.text(), user_data.mainTagger2.minutesDisplayDodgeTimeOnMap); $(".dodgers", incomingTable).css("background-color", "").attr("title", ""); dodgeCell.css("background-color", user_data.colors.good).attr("title", trans.sp.tagger.activeDodgeTime); } } } // std tag button var button = $("<input type=button title='" + trans.sp.tagger.renameTooltip + "' value='" + trans.sp.tagger.rename + "' onclick='select();'>"); button.click(function () { trackClickEvent("MainTagger-CustomRename"); var tagName = $("#commandInput").val(); renameCommand(tagName); }); buttonParent.append(button); if (user_data.mainTagger2.otherDescs != null && user_data.mainTagger2.otherDescs != false) { $.ctrl = function(key, callback, args) { $(document).keydown(function(e) { if(!args) args=[]; // IE barks when args is null if(e.keyCode == key.charCodeAt(0) && e.ctrlKey) { e.preventDefault(); e.stopPropagation(); callback.apply(this, args); return false; } }); }; // custom buttons $.each(user_data.mainTagger2.otherDescs, function (index, val) { if (val.active) { var button = $("<input type=button title='" + trans.sp.tagger.renameButtonShortcutTooltip.replace("{hitkey}", val.hitKey) + "' data-rename-to='" + val.renameTo + "' value='" + val.name + "' class=\"mainTaggerButtons\">").click( function () { // Cannot use input:checked : this works for Firefox but there is a bug in Opera trackClickEvent("MainTagger-ConfigRename"); renameCommand($(this).attr("data-rename-to")); }); buttonParent.append(button); } $.ctrl(val.hitKey, function(s) { trackClickEvent("MainTagger-ConfigRename"); renameCommand(val.renameTo); }); }); } // add checkboxes var lastRowIndex = rows.size(), lastSend = 0, prevSendTime = 0, firstNight = true, amountOfAttacks = 0; rows.each(function (rowIndex, rowValue) { var row = $(rowValue); if (rowIndex == 0) { // headerrow var header = "<td width=1% nowrap>"; header += "<img src='graphic/command/attack.png' title='" + trans.sp.tagger.checkAllAttacks + "' id=checkAll> <img src='graphic/command/cancel.png' title='" + trans.sp.tagger.uncheckAllAttacks + "' id=uncheckAll>"; header += "</td>"; row.replaceWith("<tr>" + header + "<th width='68%'>" + trans.sp.tagger.incomingTroops + "</th><th width='30%'>" + trans.sp.tagger.arrival + "</th><th width='10%'>" + trans.sp.tagger.arrival + "</th><th width=10% nowrap>" + trans.sp.tagger.dodgeTime + "</th><th width='1%'> </th>" + "</tr>"); $("#checkAll").click(function () { $("input.incAt", incomingTable).prop("checked", true); }); $("#uncheckAll").click( function () { $("input.incAt", incomingTable).prop("checked", false); }); } else { // non header row types if (row.find("th").size() != 0) { // this part is only executed when attacks can be ignored // select all checkbox row (right above link rows) $("th:first", row).replaceWith("<th><input type=checkbox id=selectAllIgnore> " + $("th:first", row).text() + "</th>"); $("#selectAllIgnore").click(function () { var ingoreBoxes = $("input[name^='id_']", incomingTable); var isChecked = $("#selectAllIgnore").is(":checked"); ingoreBoxes.each(function() { $(this).attr("checked", isChecked); }); }); row.prepend("<td title='" + trans.sp.tagger.totalAttacksOnVillage + "' align=center><b># " + amountOfAttacks + "</b></td>").find("td:last").attr("colspan", 4); } else if (row.find("td").size() == 1) { // link-rows (bottom) if ($("#switchModus").size() == 0) { if ($("#selectAllIgnore").size() == 0) { // attack hiding disabled in tw settings -> there is not yet a totalrow row.prepend("<td title='" + trans.sp.tagger.totalAttacksOnVillage + "' align=center><b># " + amountOfAttacks + "</b></td>"); } else { row.prepend("<td> </td>"); } row.before("<tr><td> </td><td colspan=5><a href='' id=switchModus>" + trans.sp.tagger.switchModus + "</a></td></tr>"); $("#switchModus").click(function () { trackClickEvent("MainTagger-OpenClose"); var editSpans = $("input.incAt", incomingTable).parent().parent().find("span.quickedit"), isInDisplayMode = function (editSpan) { return editSpan.find("span:first").is(":visible"); }, switchToOpen = isInDisplayMode(editSpans.first()); editSpans.each(function() { var editSpan = $(this), isDisplayMode = isInDisplayMode(editSpan); if (switchToOpen && isDisplayMode) { // make input form visible $("a.rename-icon", editSpan).click(); //setTimeout(function() { $("span.quickedit-edit input:first", editSpan).width(user_data.mainTagger2.inputBoxWidth); //}, 1); } else if (!switchToOpen && !isDisplayMode) { // make label display visible editSpan.find("span:first").show(); editSpan.find("span:last").remove(); } }); return false; }); } else { row.prepend("<td> </td>"); } row.find("td:last").attr("colspan", 5); } else { // normal incoming rows var checkboxCell = "<td><input type=checkbox rowIndex=" + rowIndex + " class='taggerCheckbox "; var incomingType = $("img[src*='graphic/command/support.png']", this).size() == 1 ? 'incSupport' : "incAt"; checkboxCell += incomingType + "'"; if (rowIndex == 1) { checkboxCell += " id=checkFirst"; } var currentArrivalTime = getDateFromTodayTomorrowTW($("td:eq(1)", this).text()); if (incomingType == 'incAt' && isDateInNightBonus(currentArrivalTime)) { // nightbonus row.find("td:eq(1)").css("background-color", user_data.colors.error); } // extra column with dodge time if (incomingType == 'incAt') { var dodgeTime = getTimeFromTW($("td:eq(2)", this).text()); row.find("td:last").before("<td class=dodgers>" + twDurationFormat(dodgeTime.totalSecs / 2 / 60) + "</td>"); amountOfAttacks++; } else { row.append("<td> </td>"); } // dotted line after x hours no incomings if (prevSendTime == 0 || (currentArrivalTime - prevSendTime) / 1000 / 60 > user_data.mainTagger2.minutesWithoutAttacksDottedLine) { if (prevSendTime != 0) { row.find("td").css("border-top", "1px dotted black"); } prevSendTime = currentArrivalTime; } // black line after each nightbonus if (lastSend == 0 || currentArrivalTime > lastSend) { if (lastSend != 0) { row.find("td").css("border-top", "1px solid black"); firstNight = false; } lastSend = new Date(currentArrivalTime); if (lastSend.getHours() >= world_config.nightbonus.till) { lastSend.setDate(lastSend.getDate() + 1); lastSend.setHours(world_config.nightbonus.from); lastSend.setMinutes(0); lastSend.setSeconds(0); } else if (lastSend.getHours() < world_config.nightbonus.from) { lastSend.setHours(world_config.nightbonus.from); lastSend.setMinutes(0); lastSend.setSeconds(0); } else { lastSend.setHours(world_config.nightbonus.till); lastSend.setMinutes(0); lastSend.setSeconds(0); } } // Automatically select? if (incomingType == "incAt") { if (firstNight) { var isDefaultDesc = false; if (!isDefaultDesc) { checkboxCell += " checked=true"; } } $("span:eq(2)", row).find("input:first").click(function () { $(this).select(); }); // extra buttons $("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'>"); } row.prepend(checkboxCell + "></td>"); if (user_data.mainTagger2.colorSupport != null && incomingType != "incAt") { row.find("td").css("background-color", user_data.mainTagger2.colorSupport); } } } }); }); } } // show tagger? if (user_data.mainTagger2.autoOpen) { $("#openTaggerButton").click(); } // Show attack rename inputboxes if (user_data.mainTagger2.autoOpenCommands) { $("#switchModus").click(); } // BUG: This breaks the TW remembering of the div positions!! var newLayout = "<tbody><tr><td colspan=2><div class='outerBorder' id=myprettynewcell>"; newLayout += "</div></td></tr></tbody>"; mainTable.append(newLayout); var prettyCell = $("#myprettynewcell"); prettyCell.append($("#show_incoming_units")); prettyCell.append($("#show_outgoing_units")); } if (user_data.overview.canHideDiv) { //console.time("main_overview_deletebuttons"); /** * Array with domIds of the hideable divs * @type {Array} */ var currentlyHidden = pers.get("mainvillage_hiddendivs"); currentlyHidden = currentlyHidden ? JSON.parse(currentlyHidden) : []; // add the X images $("#leftcolumn,#rightcolumn").find("div.moveable").each(function() { var self = $(this), domId = this.id; if (!self.hasClass("hidden_widget")) { if (currentlyHidden.indexOf(domId) !== -1) { self.hide(); } else { var header = self.find("h4:first"); header.prepend( '<span class="sanguHide" ' + " title='" + trans.sp.main.hideDiv + "'" + ' data-divid="' + domId + '"></span>'); } } }); // X image event $(".sanguHide", content_value).click(function() { var toHideId = $(this).attr("data-divid"); currentlyHidden.push(toHideId); $("#" + toHideId).hide(); q(currentlyHidden); pers.set("mainvillage_hiddendivs", JSON.stringify(currentlyHidden)); }); // css for X image var deleteImage = "data:image/png;base64," + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAAXNSR0IArs4c6QAAAARnQU1BAACx" + "jwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41" + "LjExR/NCNwAAAT5JREFUOE9jmBqv1R8uD0F9oTI9wZJdAaLI7A5fwTYv3g4fgU4/4VZ3Lgag6OYV" + "fUd3zj13aAkeBFQAVFZrx8DQGyIN5Nw6t+7p9W14EFABUFm9AwMD0GqgAUChDw/340FABUBljY5M" + "DN0BYsRrADkJ6Bs0DZe2NL68sfHN3R1XtrfCBSEaKm0YGIAeR9awoj22M1p5z+SIHX0hczI0t/fF" + "oGtodGJG1vD8+ubqYPXOEMnJMTI9EYqPz69E1oDFDw/PreyPUkw1YiiwYV9Z5fDq1lZkDVj8sKgh" + "NFiTIcdHPd5RIc2Se/eUZGQNWPwARH1VMU+vbb51akV7UQhcEKEBzQ+4EERDqRUDA9BZxGsotGBg" + "AMY28UkDpKHJmYX4xAfSAPQH0GXlNlAGEBVbMQAlkNn55gz5QNKCIdOUAQAxTOqhn6cegQAAAABJ" + "RU5ErkJggg=="; var css = document.createElement("style"); css.type = "text/css"; css.innerHTML = ".sanguHide { margin-left: 2px; float: right; cursor: pointer; " + "background: url(" + deleteImage + "); width: 16px; height: 16px; }"; document.body.appendChild(css); // show everything link content_value.append( "<br><a href='#' id='resetSanguMenu'>" + trans.sp.main.showHiddenDivs.replace("{amount}", currentlyHidden.length) + "</a>" ); $("#resetSanguMenu").click(function() { pers.set("mainvillage_hiddendivs", ""); location.reload(); }); //console.timeEnd("main_overview_deletebuttons"); } }()); break; case "map": (function() { //console.time("dodge_fromMainTagger"); try { var isDodge = pers.getCookie("sanguDodge" + getQueryStringParam("village")); if (isDodge) { // Display dodge time and slowest unit in the village (cookied from the mainTagger) isDodge = isDodge.split("~"); var header = $("h2:first", content_value); $("tbody:first", content_value) .prepend( "<tr><td><table width=100% cellpadding=0 cellspacing=0><tr><td width=99% style='font-size: 18pt'><b>" + header.html() + "</b></td><td nowrap width=250><div title='" + trans.sp.map.dodgeLastTagged + "' style='border: 1px solid black; padding: 2px; background-color: " + (isDodge[0] == 'unit_snob' ? user_data.colors.special : user_data.colors.good) + "'><img src=graphic/unit/" + isDodge[0] + ".png> <b>" + isDodge[1] + "</b></div></td></tr></table></td></tr>"); header.remove(); } } catch (e) { handleException(e, "dodge_fromMainTagger-"); } //console.timeEnd("dodge_fromMainTagger"); }()); break; case "report": if (current_page.mode === 'publish') { // Nice to haves when publishing a report (function() { try { if (location.href.indexOf('published=1') == -1 && user_data.other.reportPublish != null) { $.each(user_data.other.reportPublish, function (i, v) { $("#" + v).prop("checked", true); }); } else { $("h3~p:nth-child(4)").each(function () { var input = $("h3~p a")[0].href; if (input.indexOf("?t=") != -1) { input = input.substr(0, input.indexOf("?")); } $(this).append('<br><input type="text" size="75" onclick="this.select(); this.focus()" value="[url]' + input + '[/url]" />'); input = input.substr(input.lastIndexOf('/') + 1); $(this).append('<br><input type="text" size="75" onclick="this.select(); this.focus()" value="[report_display]' + input + '[/report_display]" />'); $(this).append('<br><input type="text" size="75" onclick="this.select(); this.focus()" value="[report]' + input + '[/report]" />'); }); } } catch (e) { handleException(e, "report"); } }()); } break; case "main": // Alternating row colors $("#buildings,#build_queue").find("tr:odd").addClass("row_b"); (function() { //console.time("main-renamevillage"); try { if (user_data.main.villageNames != null && user_data.main.villageNames.length > 0) { var showButtons = true; $.each(user_data.main.villageNames, function (i, v) { if (game_data.village.name == v) showButtons = false; }); if (showButtons) { var submitButton = $("input[type='submit']:last"); $.each(user_data.main.villageNames, function (i, v) { // rename village to one of the provided villageNames options var button = $("<input type=button class='btn' value='" + v + "'>") .click(function () { trackClickEvent("RenameVillage"); $("input[name='name']").val(v); if (user_data.main.villageNameClick) { $("input[type='submit']").click(); } }); var input = submitButton.parent().append(button); }); } } } catch (e) { handleException(e, "place-"); } //console.timeEnd("main-renamevillage"); }()); // show loyalty when building // destroy button is disabled now (but for how long?) if (server_settings.ajaxAllowed && user_data.main.ajaxLoyalty) { ajax("overview", function (overview) { var loyalty = $("#show_mood div.vis_item", overview); if (loyalty.size() == 1) { $(".modemenu tr:first").append("<td><b>" + trans.tw.main.loyaltyHeader + "</b> " + loyalty.html() + "</td>"); } }); } break; case "snob": if (current_page.mode === "train" || current_page.mode === null || current_page.mode === "produce") { if (user_data.other.calculateSnob && !world_config.coins) { // Calculate for how many nobles/snobs we've got packages (function() { try { //var table = $("table.vis:eq(1)", content_value); var table = $("table.vis[width='100%']", content_value).first(); var cost = $("td:eq(1)", table).html(); cost = parseInt(cost.substr(0, cost.indexOf(" ")), 10); var stored = $("tr:eq(1) td:eq(1)", table).html(); stored = parseInt(stored.substr(0, stored.indexOf(" ")), 10); var canProduce = 0; while (stored > cost) { stored -= cost; cost++; canProduce++; } var sumtable = $("table.main #content_value > table table.vis:last"); assert(sumtable.length, "no snob sumtable"); sumtable.append("<tr><th>" + trans.sp.snob.canProduce + "</th><td style='border: 1px solid black'><img src='/graphic/unit/unit_snob.png'><b>" + canProduce + "</b> " + "+ <img src='graphic/res.png'>" + stored + "</td></tr>"); } catch (e) { handleException(e, "snob"); } }()); } } break; case "info_command": if ($("#running_times").size() > 0) { // ---------------------------------------INCOMING ATTACK (function() { //console.time("info_command-incoming"); try { var link = $("#contentContainer tr:eq(10) a:last"); link.one('click', function () { var infoTable = $("#contentContainer"); var table = $("#running_times"); // convert runningtime to seconds // TODO: there is a function for this: getTimeFromTW function convertTime(cell) { var time = $(cell).find("td:eq(1)").text(); time = time.match(/(\d+):(\d+):(\d+)/); var obj = {}; obj.hours = parseInt(time[1], 10); obj.minutes = parseInt(time[2], 10); obj.seconds = parseInt(time[3], 10); obj.totalSeconds = obj.hours * 3600 + obj.minutes * 60 + obj.seconds; return obj; } // Sort on runningtime var unitRows = $("tr:gt(1)", table); unitRows.sortElements(function (a, b) { return convertTime(a).totalSeconds > convertTime(b).totalSeconds ? 1 : -1; }); // header sent times $("th:first", table).attr("colspan", 5); $("th:eq(2)", table).after("<th>" + trans.sp.tagger.sentOn + "</th><th>" + trans.sp.tagger.ago + "</th>"); var infoCell = $("td", infoTable); var attacker = infoCell.eq(5).text(); var attackerVillageName = infoCell.eq(7).text(); var attackerVillage = getVillageFromCoords(attackerVillageName); var defender = infoCell.eq(10).text(); var defenderVillage = getVillageFromCoords(infoCell.eq(12).text()); var arrivalTime = getDateFromTW(infoCell.eq(14).text()); var fields = parseInt(getDistance(attackerVillage.x, defenderVillage.x, attackerVillage.y, defenderVillage.y).fields, 10); var isNightbonus = isDateInNightBonus(arrivalTime); if (isNightbonus) { infoCell.eq(14).css("background-color", user_data.colors.error); } var remainingRunningTime = convertTime($("tr:eq(9)", infoTable)), plausibleSpeedFound = false; unitRows.each(function () { var unit = $("img:first", this).attr("src"); unit = unit.substr(unit.lastIndexOf("unit_") + 5); unit = unit.substr(0, unit.indexOf(".")); if (unit == "spear") { $(this).hide(); } else { var runningTime = convertTime(this), newDate = new Date(arrivalTime.getTime() - runningTime.totalSeconds * 1000), sendAt = prettyDate((new Date()).getTime() - newDate.getTime()), troopsRow = this, str; // Extra column with time sent $("td:eq(2)", troopsRow).before("<td>" + twDateFormat(newDate, true) + "</td><td>" + sendAt + "</td>"); // Rename default command name for each speed if (user_data.incoming.renameInputTexbox) { str = user_data.incoming.renameInputTexbox; var attackId = $("span.quickedit", this).attr("data-id"); str = str.replace("{village}", attackerVillageName).replace("{c}", attackerVillage.continent()).replace("{id}", attackId); str = str.replace("{player}", attacker).replace("{xy}", attackerVillage.coord).replace("{unit}", trans.tw.units.twShortNames[unit]); str = str.replace("{fields}", fields); if (str.indexOf("{night}") != -1) { if (isNightbonus) { str = str.replace("{night}", trans.sp.tagger.arrivesInNightBonus); } else { str = str.replace("{night}", ""); } } if (false) { // don't show rename inputs, just the labels $("span.quickedit-label", troopsRow).text(str).show(); } else { // show the rename inputboxes on form load $("span.quickedit-label", troopsRow).text(str); setTimeout(function() { $("a.rename-icon", troopsRow).click(); $("#focusPlaceHolder").focus(); }, 1); } if (runningTime.totalSeconds > remainingRunningTime.totalSeconds && !plausibleSpeedFound) { plausibleSpeedFound = true; $("table:first", content_value).prepend( "<input type=submit class='btn' id=focusPlaceHolder value='" + trans.sp.tagger.tagIt + " (" + trans.tw.units.twShortNames[unit] + ")'" + " data-command-name='" + str + "'" + ">"); $("#focusPlaceHolder").click(function () { trackClickEvent("TagDefault"); $("#command_comment").text($(this).attr("data-command-name")); $("#command_comment+a").click(); setTimeout(function() { $("#quickedit-rename input:last").click(); }, 1); $(this).val(trans.sp.tagger.tagged).attr("disabled", "disabled"); }); if (unit == "snob") { $("tr:last td", table).css("background-color", user_data.colors.error); } } } // Possible send times (now) in bold if (runningTime.totalSeconds > remainingRunningTime.totalSeconds) { $(this).css("font-weight", "bold"); } } }); // nobles can only walk so far var nobles = $("tr:last", table); if (convertTime(nobles).totalSeconds / 60 > world_config.maxNobleWalkingTime) { nobles.find("td").css("text-decoration", "line-through"); } if (user_data.incoming.invertSort) { unitRows.sortElements(function (a, b) { return convertTime(a).totalSeconds < convertTime(b).totalSeconds ? 1 : -1; }); } }); // AUTO OPEN TAGGER if (user_data.incoming.forceOpenTagger || (user_data.incoming.autoOpenTagger && $("#labelText").text() == trans.tw.incoming.defaultCommandName)) { link.click(); } if (user_data.proStyle && user_data.incoming.villageBoxSize != null && user_data.incoming.villageBoxSize != false) { $("table:first", content_value).css("width", user_data.incoming.villageBoxSize); } } catch (e) { handleException(e, "info_command-incoming"); } //console.timeEnd("info_command-incoming"); }()); } else { (function() { //console.time("info_command-command"); try { // Own attack/support/return ---------------------------------------------------------------------------------- Own attack/support/return var infoTable = $("table.vis:first", content_value); var type = $("h2:first", content_value).text(); var catapultTargetActive = infoTable.find("tr:eq(5) td:eq(0)").text() == trans.tw.command.catapultTarget; infoTable.width(600); // Add troop returntime and annulation return time var isSupport = type.indexOf(trans.tw.command.support) == 0; var offset = 5; if (catapultTargetActive) { offset += 1; } var arrivalCell = infoTable.find("tr:eq(" + (offset + 1) + ") td:last"); if (type.indexOf(trans.tw.command.returnText) == -1 && type.indexOf(trans.tw.command.abortedOperation) == -1) { var duration = getTimeFromTW(infoTable.find("tr:eq(" + offset + ") td:last").text()); var imgType = !isSupport ? "attack" : "support"; arrivalCell.prepend("<img src='graphic/command/" + imgType + ".png' title='" + trans.sp.command.arrival + "'> " + trans.tw.all.dateOn + " ").css("font-weight", "bold"); var stillToRun = getTimeFromTW(infoTable.find("tr:eq(" + (offset + 2) + ") td:last").text()); var cancelCell = infoTable.find("tr:last").prev(); var canStillCancel = cancelCell.has("a").length; if (canStillCancel) { cancelCell.find("td:first").attr("colspan", "1").attr("nowrap", "nowrap"); var returnTime = getDateFromTW($("#serverTime").text(), true); returnTime = new Date(returnTime.valueOf() + (duration.totalSecs - stillToRun.totalSecs) * 1000); cancelCell.append("<td>" + trans.sp.command.returnOn + "</td><td id=returnTimer>" + twDateFormat(returnTime, true, true).substr(3) + "</td>"); setInterval(function timeCounter() { var timer = $("#returnTimer"); var newTime = new Date(getDateFromTW(timer.text()).valueOf() + 2000); timer.text(twDateFormat(newTime, true, true).substr(3)); }, 1000); cancelCell = cancelCell.prev(); } if (type.indexOf(trans.tw.command.attack) == 0) { var returnTimeCell = cancelCell.find("td:last"); returnTimeCell.html("<img src='graphic/command/return.png' title='" + cancelCell.find("td:first").text() + "'> <b>" + returnTimeCell.text() + "</b>"); } } else { var imgType = type.indexOf(trans.tw.command.abortedOperation) == 0 ? imgType = "cancel" : "return"; arrivalCell.prepend("<img src='graphic/command/" + imgType + ".png' title='" + trans.sp.command.arrival + "'> " + trans.tw.all.dateOn + " ").css("font-weight", "bold"); } var player = infoTable.find("td:eq(7) a").text(); var village = getVillageFromCoords(infoTable.find("td:eq(9) a").text()); var second = infoTable.find("td:eq(" + (13 + (catapultTargetActive ? 2 : 0)) + ")").text(); var haulDescription = ""; if (type.indexOf(trans.tw.command.returnText) == 0) { infoTable = $("> table.vis:last", content_value); if (infoTable.find("td:first").text() == trans.tw.command.haul) { haulDescription = infoTable.find("td:last").text().match(/\s(\d+)\/(\d+)$/); if (haulDescription) { haulDescription = formatNumber(haulDescription[1]) + " / " + formatNumber(haulDescription[2]); } else { assert(infoTable.find("td:last").text() + " didn't match regexp for tw.command.haul"); } infoTable = infoTable.prev(); } infoTable = infoTable.find("tr:last"); } else { infoTable = $("> table.vis:last", content_value); } var unitsSent = {}; $.each(world_data.units, function (i, val) { unitsSent[val] = parseInt($("td:eq(" + i + ")", infoTable).text(), 10); }); var unitsCalc = calcTroops(unitsSent); unitsCalc.colorIfNotRightAttackType($("h2:first", content_value), !isSupport); if (user_data.attackAutoRename.active) { $.each($('.quickedit'), function(){ var renamed = buildAttackString(village.coord, unitsSent, player, isSupport, 0, haulDescription), commandID = $(this).attr('data-id'), $this = $(this); if (server_settings.ajaxAllowed) { $.ajax({ url: game_data.link_base_pure+'info_command&ajaxaction=edit_other_comment&id='+commandID+'&h='+game_data.csrf+'&', method: 'post', data: { text: renamed }, success:function() { $this.find(".quickedit-label:first").text(renamed); } }); } }); } /*if (server_settings.ajaxAllowed) { ajax("overview", function(overviewtext) { var idnumberlist = []; var index = 0; var links = $(overviewtext).find("#show_outgoing_units").find("table").find("td:first-child").find("a:first-child").find("span"); //^enkel 'find codes, dus alles wegselecteren wat onnodig is. links.each(function(){ var idgetal = $(this).attr('id').match(/\d+/); idnumberlist[index]=idgetal[0]; index++; $.trim(idnumberlist[index]); }); idthisattack= location.href.match(/id=(\d+)/);// deze aanval ophalen var idthisattacktrim = $.trim(idthisattack[1]); //eerste callback: Datgeen tussen haakjes dus. En gelijk maar trimmen, voor het geval dat. var counter=$.inArray(idthisattacktrim, idnumberlist); var arraylength = idnumberlist.length; var arraylengthminusone = arraylength -1; if (counter != arraylengthminusone) { var nextcommandID = idnumberlist[(counter +1)];} if (counter != 0) { var lastcommandID = idnumberlist[(counter - 1)]; } villageid = location.href.match(/village=(\d+)/); //alert(villageid[1]); if (counter != 0) { 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>'); } else { content_value.find("h2").after('<table><tr><td id="lastattack" style="width:83%"><b> XX</b></td> </tr> </table>'); } if (counter != arraylengthminusone){ $("#lastattack").after('<td id="nextcommand" ><a href="/game.php?village=' + villageid + '&id=' + nextcommandID + '&type=own&screen=info_command">'+ trans.sp.command.nextAttack+ '</a></td>'); } else { $("#lastattack").after('<td id="nextcommand"><b>XX</b></td>'); } //alert("Hoi"); }, {}); }*/ // When sending os, calculate how much population in total is sent if (isSupport) { var totalPop = 0; $.each(world_data.units, function (i, val) { var amount = unitsSent[val]; if (amount != 0) { totalPop += amount * world_data.unitsPositionSize[i]; } }); var unitTable = $("table.vis:last", content_value); unitTable.find("tr:first").append('<th width="50"><span class="icon header population" title="' + trans.sp.all.population + '"></span></th>'); unitTable.find("tr:last").append('<td>' + formatNumber(totalPop) + '</td>'); } } catch (e) { handleException(e, "info_command-command"); } //console.timeEnd("info_command-command"); }()); } break; case "market": (function() { try { if (location.href.indexOf('try=confirm_send') > -1) { if (user_data.proStyle && user_data.market.autoFocus) { $("input[type='submit']").focus(); } } else if (location.href.indexOf('&mode=') == -1 || location.href.indexOf('&mode=send') > -1) { if (location.href.indexOf('try=confirm_send') == -1) { // Spice up market: // 120 x 106 pixels: There are market images that are smaller // Making all images equally large results in the OK button remaining on the same place if (user_data.proStyle && user_data.market.resizeImage) { $("img[src*='big_buildings/market']").width(120).height(106); } // New last village: $("input[type='submit']").click(function () { var village = getVillageFromCoords($("#inputx").val() + "|" + $("#inputy").val()); if (village.isValid) { pers.set("lastVil", village.coord); } }); // Add last & target var vilHome = getVillageFromCoords(game_data.village.coord); var targetLocation = $("#inputx").parent().parent().parent(); var cookie = pers.get("lastVil"); var coord = getVillageFromCoords(cookie); var htmlStr = ''; if (coord.isValid) { var dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, 'merchant'); htmlStr = printCoord(coord, "» " + trans.sp.all.last + ": " + coord.x + "|" + coord.y); htmlStr += " <span id=lastVilTime>" + dist.html + "</span>"; } // Add target village var target = getVillageFromCoords(spTargetVillageCookie()); if (target.isValid) { var dist = getDistance(target.x, vilHome.x, target.y, vilHome.y, 'merchant'); if (htmlStr.length > 0) { htmlStr += "<br>"; } htmlStr += printCoord(target, "» " + trans.sp.all.target + ": " + target.x + "|" + target.y) + " <span id=targetVilTime>" + dist.html + "</span>"; } if (htmlStr.length > 0) { targetLocation.append("<tr><td colspan=2>" + htmlStr + "</td></tr>"); } // Calculate total resources sent var table = $("table.vis:last"); if (table.prev().text() == trans.tw.market.incomingTransports) { var sent = { stone: 0, wood: 0, iron: 0 }; table.find("tr:gt(0)").each(function () { var cell = $(this).find("td:eq(1)"); var resources = $.trim(cell.text().replace(/\./g, "").replace(/\s+/g, " ")).split(" "); for (var i = 0; i < resources.length; i++) { if (resources[i]) { var restype = cell.find("span.icon:eq(" + i + ")"); for (var resIndex = 0; resIndex < world_data.resources_en.length; resIndex++) { if (restype.hasClass(world_data.resources_en[resIndex])) { sent[world_data.resources_en[resIndex]] += parseInt(resources[i], 10); } } } } }); table.append("<tr><th>" + trans.sp.all.total + ":</th><td colspan=3><img src=graphic/holz.png> " + formatNumber(sent.wood) + " <img src=graphic/lehm.png> " + formatNumber(sent.stone) + " <img src=graphic/eisen.png> " + formatNumber(sent.iron) + "</td></tr>"); } } } } catch (e) { handleException(e, "market"); } }()); break; case "settings": // Add sangu to the menu (function() { var settingsMenu = $("table.vis:first", content_value); settingsMenu.append( "<tr><td> </td></tr><tr><th><a href='" + getUrlString("screen=settings&mode=sangu") + "'>Sangu Package</a></th></tr>"); settingsMenu.append( "<tr id='sanguImportRow'><td>" + "<a href='#' id='sanguImport'>" + trans.sp.sp.settings.importSettings + "</a>" + "</td></tr>" + "<tr id='sanguExportRow'><td>" + "<a href='#' id='sanguExport'>" + trans.sp.sp.settings.exportSettings + "</a>" + "</td></tr>"); settingsMenu.after( "<br>" + "<a target='_blank' href='http://"+server_settings.sangu+"'>" + "<div style='width: 100%; text-align: center; border: 1px solid black; background-color: yellow; padding: 10px 0 10px;'>" + "Sangu Website" + "</div>" + "</a>"); /** * Creates the textarea (and other UI elements) for displaying the user_data * @param activate {string} either Import or Export * @param deactivate {string} either Export or Import * @param textAreaValue {string} the content to assign to the textarea */ function importExportHandler(activate, deactivate, textAreaValue) { var settingsContainer = $("#sanguSettingsTextArea"); $("#sangu"+activate+"Row").addClass("row_b"); $("#sangu"+deactivate+"Row").hide(); $("#sanguSettingsForm").hide(); if (settingsContainer.length === 0) { //sanguConfigTitle is the h3 defined in inject.js $("#sanguConfigTitle").parent().append( trans.sp.sp.settings.importSettingsDesc + "<br><br>" + "<textarea id='sanguSettingsTextArea' style='width: 100%; height: 500px'>" + textAreaValue + "</textarea>"); } else { if (textAreaValue.length > 0) { settingsContainer.val(textAreaValue); } } } $("#sanguExport").click(function() { importExportHandler("Export", "Import", JSON.stringify(user_data, null, 4)); $("#sanguSettingsTextArea").select(); return false; }); $("#sanguImport").click(function() { var importSanguSettings = $("#importSanguSettings"); importExportHandler("Import", "Export", ""); if (importSanguSettings.length === 0) { $("#sanguSettingsTextArea") .after("<br><input type='button' id='importSanguSettings' value='" + trans.sp.sp.settings.importSettings + "'>"); $("#importSanguSettings").click(function() { var overwriteCurrentSettings = true, newUserData; try { newUserData = JSON.parse($("#sanguSettingsTextArea").val()); if (typeof newUserData.proStyle === 'undefined') { overwriteCurrentSettings = confirm(trans.sp.sp.settings.importError + trans.sp.sp.settings.importErrorContinueAnyway); } if (overwriteCurrentSettings) { user_data = $.extend({}, user_data, newUserData); pers.set("sangusettings", JSON.stringify(user_data)); alert(trans.sp.sp.settings.importSettingsSuccess); } } catch (ex) { alert(trans.sp.sp.settings.importError + "\n" + ex.message); } }); } $("#sanguSettingsTextArea").focus(); return false; }); })(); switch (current_page.mode) { case "vacation": var maxSitDays = server_settings.maxSitDays; var daysTable = $("table.vis:eq(1)", content_value); var days = $("td:last", daysTable).text(); days = maxSitDays - parseInt(days.substr(0, days.indexOf(" ")), 10); if (days > 0) { var tillTime = new Date(); tillTime.setDate(tillTime.getDate() + days); daysTable.append("<tr><td>" + trans.sp.rest.sittingAttackTill + "</td><td>" + (tillTime.getDate() + "." + pad(tillTime.getMonth() + 1, 2) + "." + tillTime.getFullYear()) + "</td></tr>"); } else { daysTable.find("td:last").css("background-color", user_data.colors.error); } break; case "quickbar_edit": if (user_data.scriptbar.editBoxCols != null && user_data.scriptbar.editBoxCols != false) { // TODO: textareaIfy: This might be useful on other places aswell. Move to func/UI? function textareaIfy(element) { var textarea = $('<textarea>') .attr('cols', Math.round(user_data.scriptbar.editBoxCols / 9)) .attr('rows', user_data.scriptbar.editBoxRows) .val($(element).val()); textarea.change(function () { element.val($(this).val()); }); element.before(textarea); $(element).hide(); } var url = $("form :input[type='text']").css("width", user_data.scriptbar.editBoxCols).last(); textareaIfy(url); } break; } // SANGU SETTING EDITOR if (location.href.indexOf('mode=sangu') > -1) { // settings.editor: : delimited: "array:string" or "required:boolean" etc function createArraySettingType(inputHandler, index, editor) { var propertyValueType = editor.split("|")[0]; function deleter() { inputHandler.getValue().splice(index, 1); } switch (propertyValueType) { case "number": return new FormInputHandler(inputHandler.formConfig, { getter: function() { return inputHandler.getValue()[index]; }, setter: function(value) { value = parseInt(value, 10); if (!isNaN(value)) { inputHandler.getValue()[index] = value; } else { inputHandler.getValue()[index] = 0; } }, deleter: deleter, editor: editor }); case "text": case "color": return new FormInputHandler(inputHandler.formConfig, { getter: function() { return inputHandler.getValue()[index]; }, setter: function(value) { inputHandler.getValue()[index] = value; }, deleter: deleter, editor: editor }); case "float": return new FormInputHandler(inputHandler.formConfig, { getter: function() { return inputHandler.getValue()[index]; }, setter: function(value) { value = parseFloat(value.replace(",", ".")); if (!isNaN(value)) { inputHandler.getValue()[index] = value; } else { inputHandler.getValue()[index] = 0; } }, deleter: deleter, editor: editor }); } alert(propertyValueType + " not supported"); } /** * Factory for creating different representations of a property * @type {string} */ function createSettingType(inputHandler, editors, editorIndex, arrayOptions) { var value = inputHandler.getValue(), decorators, inputType, propName; //array|addNew:number|delete|step=1000 //color=color+number=stack //q("with -> " + editors + ". isArray: " + isArrayType); //q(arrayOptions); if (!arrayOptions.isArrayType) { decorators = editors.split("|"); inputType = decorators[0]; if (inputType.indexOf("=") > -1) { propName = inputType.split("=")[1]; inputType = inputType.split("=")[0]; } //q("isArray: " + propName + "=> " + inputType); //q(decorators); switch (inputType) { case "bool": return { build: function(id) { //assert(typeof value === 'boolean', (typeof value) + ": not a boolean"); return "<input type='checkbox' id='"+id+"' "+(value ? " checked" : "")+" />"; }, bind: function(id) { $("#" + id).click(function() { inputHandler.setValue($(this).is(":checked")); }); } }; case "unit": return { build: function(id) { var i, html = "<select id='"+id+"'>"; for (i = 0; i < world_data.units.length; i++) { html += "<option "+(value == world_data.units[i] ? " selected" : "")+">"+world_data.units[i]+"</option>"; } html += "</select>"; return html; }, bind: function(id) { $("#" + id).click(function() { inputHandler.setValue($(this).val()); }); } }; case "text": case "color": case "number": case "float": return (function() { var htmlString = "", index, inputBoxSize = 13, extraInputAttributes = "", extraHtml = "", inputTypeAttribute = inputType === "float" ? "number" : inputType; switch (inputType) { case "text": if (typeof value === 'string') { value = value.toString().replace(/'/g, "'"); } inputBoxSize = 50; break; } if (decorators.length > 1) { (function() { var keyValuePair; for (index = 0; index < decorators.length; index++) { keyValuePair = decorators[index].split("="); switch (keyValuePair[0]) { case "delete": extraHtml += " <a href='#' id='{domId}_delete'><img src='graphic/delete.png' title='"+trans.sp.sp.settings.deleteTooltip+"' /></a>"; break; case "step": assert(inputType === "float" || inputType === "number", "step only works with numeric inputs"); assert(keyValuePair.length === 2, "expected input: step=value"); extraInputAttributes += " step='"+keyValuePair[1]+"'"; break; case "width": inputBoxSize = keyValuePair[1]; break; } } })(); } htmlString += "<input type='" + inputTypeAttribute + "' id='{domId}' size='" + inputBoxSize +"' " + (typeof value !== 'undefined' ? " value='"+value+"'" : "") + extraInputAttributes +" />" + extraHtml; return { build: function(id) { return htmlString.replace(/\{domId\}/g, id); }, bind: function(id) { $("#" + id).change(function() { var newValue = $("#" + id).val(); inputHandler.setValue(newValue, editorIndex); return false; }); $("#" + id + "_delete").click(function() { inputHandler.deleteValue(); location.reload(false); }); } }; })(); } } else { return (function() { var typesArray = [], arrayIndex, canAddNew = false, inlineDiv = false; decorators = arrayOptions.decorators; //q(editors); //q(decorators); //q("----"); if (decorators.length > 0) { for (arrayIndex = 0; arrayIndex < decorators.length; arrayIndex++) { switch (decorators[arrayIndex]) { case "addNew": canAddNew = true; break; case "inline": inlineDiv = true; break; } } } for (arrayIndex = 0; arrayIndex < value.length; arrayIndex++) { (function() { var fixedArrayIndex = arrayIndex; //q("createArraySettingType for" + fixedArrayIndex + "=" +editors); typesArray.push(createArraySettingType(inputHandler, fixedArrayIndex, editors)); })(); } return { build: function(id) { var htmlString = "", arrayIndex, domId; assert(typeof value === 'object', (typeof value) + ": not an object (array)"); for (arrayIndex = 0; arrayIndex < typesArray.length; arrayIndex++) { domId = id + "_" + arrayIndex; htmlString += "<div" + (inlineDiv ? " style='display: inline'> " : ">"); htmlString += typesArray[arrayIndex].build(domId); htmlString += "</div>"; } if (canAddNew) { htmlString += "<a href='#' id='"+id+"_new'>" + trans.sp.sp.settings.addRecord + "</a>"; } return htmlString; }, bind: function(id) { var domId, arrayIndex; if (canAddNew) { $("#" + id + "_new").click(function() { var domId = id + "_" + typesArray.length, newType; newType = createArraySettingType(inputHandler, typesArray.length, editors); $(this).before("<div>" + newType.build(domId) + "</div>"); newType.bind(domId); typesArray.push(newType); $("#"+domId).focus(); return false; }); } if (typesArray.length === 0 && canAddNew) { $("#" + id + "_new").click(); } else { for (arrayIndex = 0; arrayIndex < typesArray.length; arrayIndex++) { domId = id + "_" + arrayIndex; typesArray[arrayIndex].bind(domId); } } } }; })(); } assert(false, editors + " is not a valid editor"); return; } /** * @constructor */ function FormInputHandler(propertyFormConfig, propSettings, editorIndex) { var arraySplit = propSettings.editor.split(":"), editors, arrayOptions = {isArrayType: arraySplit[0].indexOf('array') === 0}, strategy; assert(typeof propSettings.getter === 'function', 'getter should be a function'); assert(typeof propSettings.setter === 'function', 'setter should be a function'); if (arrayOptions.isArrayType) { editors = arraySplit[1].split("+"); } else { editors = arraySplit[0].split("+"); } //q(editors); this.formConfig = propertyFormConfig; if (typeof propertyFormConfig.save === 'undefined') { this.setValue = propSettings.setter; this.deleteValue = propSettings.deleter; } else { this.setValue = function(value, editorIndex) { propSettings.setter(value, editorIndex); propertyFormConfig.save(); }; this.deleteValue = function() { propSettings.deleter(); propertyFormConfig.save(); }; } this.getValue = propSettings.getter; if (true) { //q("createSettingType for " + editors[0] + " index " + editorIndex); if (arrayOptions.isArrayType) { arrayOptions.decorators = arraySplit[0].split("|"); arrayOptions.decorators.splice(0, 1); } strategy = createSettingType(this, editors[0], editorIndex, arrayOptions); this.build = strategy.build; this.bind = strategy.bind; } else { (function(inputHandler) { var handlers = [], index; for (index = 0; index < editors.length; index++) { handlers.push(new FormInputHandler(propertyFormConfig, propSettings, index)); } inputHandler.build = function(id) { var i, htmlString = ""; for (i = 0; i < handlers.length; i++) { htmlString += handlers[i].build(id + '_col' + i); htmlString += " "; } return htmlString; }; inputHandler.bind = function(id) { var i; for (i = 0; i < handlers.length; i++) { handlers[i].bind(id + '_col' + i); } }; })(this); } } function buildConfigForm(contentPage, propertyFormConfig) { var config = propertyFormConfig.properties, prop, properties = [], propIndex, form = "", formRow, container; // show only relevant properties // has side-effects for (prop in config) { if (config.hasOwnProperty(prop)) { if (typeof config[prop].show === "undefined" || config[prop].show) { config[prop].ownName = prop; if (typeof config[prop].type === 'undefined') { // this is a variable <-> input form mapping config[prop].type = "propertyEditor"; config[prop].propUI = new FormInputHandler(propertyFormConfig, config[prop].propUI); } else { // these are other visual indications // ui is handled with if / else below } properties.push(config[prop]); } } } // build form form = "<table class='vis' width='100%'>"; form += "<tr><th colspan='2'>" + propertyFormConfig.title + "</th>"; form += "</table>"; form = $(form); container = $("<div class='propertyEditFormContainer' id='"+propertyFormConfig.id+"' style='display: none' />"); container.append(form).append("<br>"); contentPage.append(container); for (propIndex = 0; propIndex < properties.length; propIndex++) { var propUI = properties[propIndex]; if (propUI.type === 'propertyEditor') { formRow = "<tr>"; // label formRow += "<td width='25%'>"; if (typeof propUI.tooltip !== "undefined") { formRow += "<img src='graphic/questionmark.png' title='"+propUI.tooltip+"' /> "; } formRow += propUI.label; formRow += "</td>"; //editor if(propUI.label == sangu_trans.mainTagger.otherButtons.hitKey) { formRow += "<td width='75%'>ctrl + "; } else { formRow += "<td width='75%'>"; } formRow += propUI.propUI.build(propertyFormConfig.id+"_"+propUI.ownName); formRow += "</td>"; formRow += "</tr>"; form.append(formRow); // bind the form to the js variable if (typeof propUI.propUI.bind === 'function') { propUI.propUI.bind(propertyFormConfig.id+"_"+propUI.ownName); } } else { switch (propUI.type) { case "subtitle": form.append("<tr class='row_b'><td colspan='2'><b>"+propUI.label+"</b></td></tr>"); break; } } } } /** * Contains all translations for the property setting editors */ var sangu_trans = (function() { var sangu_trans = {}; sangu_trans.nl = { main: { title: "Hoofdgebouw", villageNames: "Standaard dorpsnamen:", villageNamesTooltip: "Voeg je veelgebruikte dorpsnamen toe om een dorp met 1 klik te hernoemen.", villageNameClick: "Autoclick?", villageNameClickTooltip: "Schakel deze feature uit indien je bijvoorbeeld nog een nummer aan een standaard dorpsnaam wil toevoegen.", ajaxLoyalty: "Toestemming tonen?" }, global: { title: "Op alle pagina's", tw_version: "Compatibiliteit met TW versie {version} afdwingen", 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!", resources: { title: "Met kleuren aanduiden hoe vol de opslagplaats is", activate: trans.sp.sp.settings.activate, blinkWhenStorageFull: "Grondstoffen knipperen wanneer de opslagplaats vol is", colors: "Kleurenschakering" }, incomingsTitle: "Binnenkomende aanvallen/ondersteuning links", incomingsEditLinks: "Linkdoelwit wijzigen", incomingsEditLinksTooltip: "De binnenkomende aanval/ondersteuning link wijzigen zodat de eerste 1000 bevelen getoond worden.", incomingsTrack: "Tijdchecker activeren", incomingsIndicator: "Tijdchecker tekst", incomingsIndicatorTooltip: "Gebruik {current} voor het huidig aantal binnenkomende aanvallen. " + "{difference} voor het aantal nieuwe aanvallen. " + "{saved} voor het laatst opgeslaan aantal aanvallen.", incomingsIndicatorTooltip2: "Tijdchecker tooltip", incomingsLastTimeCheckWarning: "Tijdchecker tooltip", incomingsLastTimeCheckWarningTooltip: "Gebruik {elapsed} voor de verstreken tijd. Gebruik {time} voor de laatste tijdcheck.", otherSettingsTitle: "Overige configuratie", visualizeFriends: "Aangeven welke vrienden momenteel online zijn", duplicateLogoffLink: "Voeg links onderaan een extra 'Afmelden' link toe.", colorsTitle: "Sangu achtergrondkleuren", colorsError: "Waarschuwingen", colorsNeutral: "Neutrale indicaties", colorsGood: "Positieve indicaties", colorsSpecial: "Speciale indicaties", jumperTitle: "Kaartspringer", jumperAutoOpen: "Het inputveld om coördinaten in te geven direct openen" }, incoming: { title: "De standaard TW binnenkomende aanvallen tagger", autoOpenTagger: "De tagger direct openen indien het bevel nog niet hernoemd is", forceOpenTagger: "De tagger altijd openen", renameInputTexbox: "De standaard hernoemde bevelnaam", 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.", invertSort: "De snelheid mogelijkheden sorteren", invertSortTooltip: "Vink dit aan om de traagste eenheid bovenaan te plaatsen" }, overviews: { addFancyImagesToOverviewLinks: "Icons toevoegen aan de overzichtslinks", command: { title: "Overzichtsscherm: Troepenoverzicht", titleOwnTroopsPage: "Pagina's 'Eigen' en 'In het dorp'", middleMouseClickDeletesRow: "Actie bij <img src='graphic/command/attack.png'>" + " aanklikken met de middelste muisknop: Aangevinkt=rij verwijderen. Uitgevinkt: rode rand rond de \"Opdracht\" cell.", middleMouseClickDeletesRowTooltip: "Dit werkt enkel in Opera. Vink dit NIET AAN in Firefox of Chrome!! (De rode rand werkt ook niet in Firefox)", titleDefensePage: "Pagina's 'Verdediging' en 'Ondersteuning'", changeTroopsOverviewLink: "Link wijzigen om direct 'Eigen troepen' te openen", filterMinPopulation: "De standaard ingevulde waarde om te filteren op populatie", filterOnUnitTypeSeperator: "Eigen/In het dorp: Filteren op aantal eenheden", filterMinDefaultType: "De eenheid om te filteren die standaard geselecteerd is", filterMinDefault: "Het aantal eenheden om te filteren dat standaard ingevuld is", filterMinDefaultTooltip: "Dit aantal wordt ingevuld wanneer de pagina opent. Bij het selecteren van een andere eenheid worden de waarden hieronder gebruikt.", filterMinOther: "De standaard waarde voor de overige eenheden", filterAutoSort: "De dorpenlijst automatisch sorteren na het ingeven van een doeldorp" }, troopsRestack: { title: "Alle pagina's: Stack BBCodes generatie", to: "Stack een dorp tot hoeveel populatie", requiredDifference: "Vereist verschil in huidige populatie in het dorp en de waarde hierboven", fieldsDistanceFilterDefault: "Het standaard ingevuld aantal velden waarop gefilterd wordt", filterReverse: "Aangevinkt: Rijen die voldoen aan de zoekopdracht tonen. Anders de rijen verbergen.", filterReverseTooltip: "Dit kan op de pagina zelf nog aangepast worden", defaultPopulationFilterAmount: "Het standaard ingevuld aantal voor de populatie filter", removeRowsWithoutSupport: "Bij het berekenen van de totalen dorpen zonder ondersteuning direct verbergen", autohideWithoutSupportAfterFilter: "Automatisch dorpen zonder overige ondersteuning wegfilteren na het toepassen van een filter", autohideWithoutSupportAfterFilterTooltip: "Bij de aanvalsfilter worden de dorpen die niet onder aanval zijn sowieso verborgen.", calculateDefTotalsAfterFilter: "Automatisch de totale ondersteuning per dorp berekenen na het toepassen van een filter", calculateDefTotalsAfterFilterTooltip: "Voor sommige filters moeten de totalen sowieso toch eerst berekend worden." }, commands: { title: "Overzichtsscherm: Bevelen", sumRow: "Een scheidingsrij tussen verschillende dorpen toevoegen", filterFakeMaxPop: "Een bevel met minder dan deze populatie is een fake aanval (en wordt verborgen)", requiredTroopAmount: "Bij de export naar BBCodes worden bevelen met minder dan deze populatie overgeslagen." }, resources: { title: "Overzichtsscherm: Productie", requiredResDefault: "Het aantal grondstoffen dat standaard in het invoerveld ingevuld is", requiredMerchants: "Het aantal handelaren dat standaard ingevuld is", filterMerchants: "Ook filteren op aantal beschikbare handelaren", filterRows: "Aanvinken om rijen te verbergen. Wanneer uitgevinkt wordt achtergrondkleur van de grondstoffen gewijzigd", 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", highlightColor: "De achtergrondkleur die gebruikt wordt om de grondstoffen aan te duiden die voldoen aan de filtercriteria" }, buildings: { title: "Overzichtsscherm: Gebouwen", minMaxTitle: "Geef de laagst en hoogst aanvaardbare levels voor je gebouwen", minLevel: "Min {building}", maxLevel: "Max {building}" }, incomings: { title: "Overzichtsscherm: Aankomend", attackIdTitle: "Groeperen op aanvalsid", minValueTooltip: "De te tonen tekst wanneer het verschil in aanvalsid tussen de vorige binnenkomende aanval meer is dan het aangegeven verschil", seperatorTitle: "Bij verschil < {minValue}", minValue: "Minimum verschil", text: "Tekst", attackIdHigherDescription: "Te tonen tekst bij groter verschil in aanvalsid" } }, place: { title: "Plaats: Speciale troepen invul links", titleCustom: "Plaats: Extra troepen invul links", linkText: "Link tekst", link: "Link: {name}", scoutTitle: "Verkenner links", scoutVillage: "Een dorp krijgt verkenner links als er meer verkenners zijn dan dit", scoutPlaceLinks: "Links om zoveel verkenners in te vullen", fakePlaceLinkTitle: "Fake troepen link", fakePlaceExcludeTroops: "Type troepen te negeren bij selecteren", fakePlaceExcludeTroopsTooltip: "Gebruik de namen: spear, sword, axe, archer, sword, spy, light, marcher, heavy, ram, catapult", noblePlaceLinkTitle: "Edel links", noblePlaceLinkFirstTitle: "Edel link met het meeste troepen", noblePlaceLinkFirstNameTooltip: "Er blijven genoeg troepen thuis om voor de resterende edels nog ondersteuning te kunnen sturen. Maak leeg om deze link niet te tonen.", noblePlaceLinkSupportTitle: "Edel link met minimale ondersteuning", noblePlaceLinksForceShow: "Ook tonen wanneer er slechts 1 edel in het dorp is", nobleSupportOffTitle: "Edel ondersteuning voor offensief dorp", nobleSupportDefTitle: "Edel ondersteuning voor defensief dorp", nobleSupportUnit: "Eenheid", nobleSupportAmount: "Aantal eenheden", noblePlaceLinkDivideTitle: "Edel link met gelijk verdeelde ondersteuning", noblePlaceLinkDivideAddRam: "Rammen mee selecteren", customPlaceLinksTitle: "Andere links", customPlaceOneTimeTooltip: "Vul een getal in om zoveel te sturen. Vul een negatief getal om zoveel te laten staan.", customPlaceSendAlong: "Meesturen tot", customPlaceSendAlongTooltip: "Indien er na selectie van bovenstaande troepen minder dan zoveel troepen in het dorp zou overblijven, selecteer dan alle troepen" }, profile: { title: "Verfraaien van het profiel van spelers en stammen", moveClaim: "Verplaats dorpsclaim zodat alle andere links op dezelfde plaats blijven staan", mapLink: { title: "Kaarteigenschappen van link naar TWMaps kaart generator", fill: "Achtergrondkleur", zoom: 'Inzoom niveau', grid: 'Continentlijnen', gridContinentNumbers: "Continent nummers", playerColor: 'Spelerskleur', tribeColor: 'Zijn stam kleur', centreX: "Centreren op X coördinaat", centreY: "Centreren op Y coördinaat", ownColor: 'Eigen kleur', markedOnly: "Alleen gemarkeerde", yourTribeColor: "Eigen stam kleur", bigMarkers: "Grotere aanduidingen" }, popup: { title: "Overnames popup", width: "Breedte van de popup", height: "Hoogte van de popup", left: "Horizontale positie", top: "Verticale positie" } }, mainTagger: { title: "Tagger op dorpsoverzicht", autoOpen: "De tagger automatisch openen bij binnenkomende aanvallen", inputBoxWidth: "De breedte van de bevel hernoemings inputvelden", defaultDescription: "De naam die standaard in het hernoemings inputveld geplaatst wordt", defaultDescriptionTooltip: "Gebruik {xy} voor de coordinaten van het herkomst dorp", autoOpenCommands: "De bevel hernoemings inputvelden direct tonen", minutesDisplayDodgeTimeOnMap: "Aantal minuten dat de laatste dodgetijd op de kaart getoond wordt", minutesDisplayDodgeTimeOnMapTooltip: "De laatste dodgetijd is de tijd van het laatste bevel, aangeduidt met gewijzigde achtergrondkleur na het herbenoemen van binnenkomende aanvallen.", minutesWithoutAttacksDottedLine: "Elke zoveel minuten zonder een tussenliggende binnenkomende aanval aanduiden met een stippelijn (180 = 3 uur)", colorSupport: "Binnenkomende ondersteuning een andere achtergrondkleur geven", keepReservedWords: "Tekst die vervangen wordt door een eenheid icon behouden bij hernoemen binnenkomende aanval", keepReservedWordsTooltip: "Bijvoorbeeld \"Verk.\" wordt vervangen door een verkenners icon", otherButtons: { title: "Andere hernoemings knoppen", renameTo: "Hernoemen naar", button: "Tekst knop", hitKey: "Sneltoets" } }, confirm: { title: "Bevel comfirmatie pagina", addExtraOkButton: "Links bovenaan de pagina een extra OK knop toevoegen", replaceNightBonus: "Nachtbonus melding verwerken in de pagina titel", replaceTribeClaim: "Dorpsclaim melding verwerken in de pagina titel", addCatapultImages: "Gebouws iconen tonen om snel het katapult doelwit te wijzigen" }, villageInfo: { title: "Extra links naar het troepenoverzicht", title2: "Twee extra links naar het troepenoverzicht op elke dorpsinformatie pagina toevoegen", icon: "Kies een icoon", off_title: "Extra link voor aanvallen", def_title: "Extra link voor verdedigen", linkName: "De link die toegevoegd wordt", group: "Binnen welk groep id openen (kies 0 voor alle groepen)", 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.", activateFilter: "Filter activeren", filter: { title: "Direct filteren", unit: "Eenheid", amount: "Minimale hoeveelheid" }, sort: "Dorpenlijst direct sorteren", changeSpeed: "Traagste eenheid snelheid wijzigen" }, other: { title: "Overige configuratie", proStyle: "Pro Style?", proStyleTooltip: "Met deze setting worden een heleboel kleinere features aan of uitgeschakeld", timeDisplayTitle: "Hoe looptijden weergeven", displayDays: "Dagen tonen wanneer de troepen langer dan 24 uur lopen?", displayDaysTooltip: "Voorbeeld: toon \"1.18:01:36\" wanneer aangevinkt, zoniet wordt die looptijd als \"42:01:36\" weergegeven", walkingTimeDisplay: "Te tonen tekst", walkingTimeDisplayTooltip: "Gebruik {duration} voor het aantal uren en {arrival} voor de aankomstdatum", calculateSnob: "Berekenen hoeveel edels direct kunnen geproduceerd worden", showPlayerProfileOnVillage: "Het uitgebreide spelersprofiel tonen op een dorpsinformatie pagina", farmLimitTitle: "Dorpstacks achtergrondkleuren", farmLimitStackColors: "Kleurenschakering", farmLimitAcceptableOverstack: "Acceptabele overstack voor elke kleurschakering", farmLimitAcceptableOverstackTooltip: "Boerderijlimiet: {farmlimit}", farmLimitUnlimitedStack: "Aantal populatie voor elke kleurschakering", ajaxSeperateSupport: "Dorpsoverzicht: Visualiseer het verschil tussen eigen en ondersteunende troepen in het dorpsoverzicht", canHideDiv: "Dorpsoverzicht: Een extra X icon toevoegen om een info kader volledig te verwijderen", commandRenamer: "Bevelen automatisch hernoemen", commandRenamerActive: "De verzonden troepen in de bevelnaam weergeven", commandRenamerAddHaul: "De buit aan de bevelnaam toevoegen" } }; //sangu_trans.de = {}; /*sangu_trans.en = { main: { title: "Main building", villageNames: "Village names:", villageNamesTooltip: "Add village names to the village headquarters to quickly edit the village name to a preset name.", villageNameClick: "Autoclick?", 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", ajaxLoyalty: "Show loyalty?", ajaxLoyaltyTooltip: "Get the loyalty at the building construction/destruction page" } };*/ return sangu_trans[game_data.market]; }()); /** * Configuration array containing the metadata for generating the different * property editor UIs */ var user_data_configs = (function() { /** * Debug bool */ var showConfigs = true, user_data_configs = [], sangu_saver = function() { pers.set('sangusettings', JSON.stringify(user_data)); trackEvent("ScriptUsage", "SettingEdit", "1"); }; if (showConfigs) { user_data_configs.push({ id: "global", title: sangu_trans.global.title, save: sangu_saver, properties: { twVersion: { label: sangu_trans.global.tw_version.replace("{version}", game_data.majorVersion), tooltip: sangu_trans.global.tw_versionTooltip, propUI: { getter: function() { return pers.get("forceCompatibility") !== '' && pers.get("forceCompatibility") === 'true'; }, setter: function(value) { pers.set("forceCompatibility", value); }, editor: "bool" } }, resourcesTitle: { type: "subtitle", label: sangu_trans.global.resources.title }, resourcesActivate: { label: sangu_trans.global.resources.activate, propUI: { getter: function() { return user_data.global.resources.active; }, setter: function(value) { user_data.global.resources.active = value; }, editor: "bool" } }, resourceColors: { label: sangu_trans.global.resources.colors, propUI: { getter: function() { return user_data.global.resources.backgroundColors; }, setter: function(value) { user_data.global.resources.backgroundColors = value; }, editor: "array|inline:color" } }, resourcesBlinkWhenFull: { label: sangu_trans.global.resources.blinkWhenStorageFull, propUI: { getter: function() { return user_data.global.resources.blinkWhenStorageFull; }, setter: function(value) { user_data.global.resources.blinkWhenStorageFull = value; }, editor: "bool" } }, incomingsTitle: { type: "subtitle", label: sangu_trans.global.incomingsTitle }, incomingsEditLinks: { label: sangu_trans.global.incomingsEditLinks, tooltip: sangu_trans.global.incomingsEditLinksTooltip, propUI: { getter: function() { return user_data.global.incomings.editLinks; }, setter: function(value) { user_data.global.incomings.editLinks = value; }, editor: "bool" } }, incomingsTrack: { label: sangu_trans.global.incomingsTrack, propUI: { getter: function() { return user_data.global.incomings.track; }, setter: function(value) { user_data.global.incomings.track = value; }, editor: "bool" } }, incomingsIndicator: { label: sangu_trans.global.incomingsIndicator, tooltip: sangu_trans.global.incomingsIndicatorTooltip, propUI: { getter: function() { return user_data.global.incomings.indicator; }, setter: function(value) { user_data.global.incomings.indicator = value; }, editor: "text" } }, incomingsIndicatorTooltip2: { label: sangu_trans.global.incomingsIndicatorTooltip2, propUI: { getter: function() { return user_data.global.incomings.indicatorTooltip; }, setter: function(value) { user_data.global.incomings.indicatorTooltip = value; }, editor: "text" } }, lastTimeCheckWarning: { label: sangu_trans.global.incomingsLastTimeCheckWarning, tooltip: sangu_trans.global.incomingsLastTimeCheckWarningTooltip, propUI: { getter: function() { return user_data.global.incomings.lastTimeCheckWarning; }, setter: function(value) { user_data.global.incomings.lastTimeCheckWarning = value; }, editor: "text" } }, jumperTitle: { type: "subtitle", label: sangu_trans.global.jumperTitle }, jumperActivate: { label: trans.sp.sp.settings.activate, propUI: { getter: function() { return user_data.jumper.enabled; }, setter: function(value) { user_data.jumper.enabled = value; }, editor: "bool" } }, jumperAutoOpen: { label: sangu_trans.global.jumperAutoOpen, propUI: { getter: function() { return user_data.jumper.autoShowInputbox; }, setter: function(value) { user_data.jumper.autoShowInputbox = value; }, editor: "bool" } }, colorsTitle: { type: "subtitle", label: sangu_trans.global.colorsTitle }, colorsError: { label: sangu_trans.global.colorsError, propUI: { getter: function() { return user_data.colors.error; }, setter: function(value) { user_data.colors.error = value; }, editor: "color" } }, colorsGood: { label: sangu_trans.global.colorsGood, propUI: { getter: function() { return user_data.colors.good; }, setter: function(value) { user_data.colors.good = value; }, editor: "color" } }, colorsNeutral: { label: sangu_trans.global.colorsNeutral, propUI: { getter: function() { return user_data.colors.neutral; }, setter: function(value) { user_data.colors.neutral = value; }, editor: "color" } }, colorsSpecial: { label: sangu_trans.global.colorsSpecial, propUI: { getter: function() { return user_data.colors.special; }, setter: function(value) { user_data.colors.special = value; }, editor: "color" } }, otherSettingsTitle: { type: "subtitle", label: sangu_trans.global.otherSettingsTitle }, visualizeFriends: { label: sangu_trans.global.visualizeFriends, propUI: { getter: function() { return user_data.global.visualizeFriends; }, setter: function(value) { user_data.global.visualizeFriends = value; }, editor: "bool" } }, duplicateLogoffLink: { label: sangu_trans.global.duplicateLogoffLink, propUI: { getter: function() { return user_data.global.duplicateLogoffLink; }, setter: function(value) { user_data.global.duplicateLogoffLink = value; }, editor: "bool" } } } }); } if (showConfigs) { user_data_configs.push({ id: "main", title: sangu_trans.main.title, save: sangu_saver, properties: { villageNames: { tooltip: sangu_trans.main.villageNamesTooltip, label: sangu_trans.main.villageNames, propUI: { getter: function() { return user_data.main.villageNames; }, setter: function(value) { user_data.main.villageNames = value; }, editor: "array|addNew:text|delete" } }, villageNameClick: { tooltip: sangu_trans.main.villageNameClickTooltip, label: sangu_trans.main.villageNameClick, propUI: { getter: function() { return user_data.main.villageNameClick; }, setter: function(value) { user_data.main.villageNameClick = value; }, editor: "bool" } }, ajaxLoyalty: { label: sangu_trans.main.ajaxLoyalty, show: server_settings.ajaxAllowed, propUI: { getter: function() { return user_data.main.ajaxLoyalty; }, setter: function(value) { user_data.main.ajaxLoyalty = value; }, editor: "bool" } } } }); } if (showConfigs) { user_data_configs.push({ id: "incoming", title: sangu_trans.incoming.title, save: sangu_saver, properties: { autoOpenTagger: { label: sangu_trans.incoming.autoOpenTagger, propUI: { getter: function() { return user_data.incoming.autoOpenTagger; }, setter: function(value) { user_data.incoming.autoOpenTagger = value; }, editor: "bool" } }, forceOpenTagger: { label: sangu_trans.incoming.forceOpenTagger, propUI: { getter: function() { return user_data.incoming.forceOpenTagger; }, setter: function(value) { user_data.incoming.forceOpenTagger = value; }, editor: "bool" } }, renameInputTexbox: { label: sangu_trans.incoming.renameInputTexbox, tooltip: sangu_trans.incoming.renameInputTexboxTooltip, propUI: { getter: function() { return user_data.incoming.renameInputTexbox; }, setter: function(value) { user_data.incoming.renameInputTexbox = value; }, editor: "text" } }, invertSort: { label: sangu_trans.incoming.invertSort, tooltip: sangu_trans.incoming.invertSortTooltip, propUI: { getter: function() { return user_data.incoming.invertSort; }, setter: function(value) { user_data.incoming.invertSort = value; }, editor: "bool" } } } }); } if (showConfigs) { (function() { var properties = { activate: { label: sangu_trans.global.resources.activate, propUI: { getter: function() { return user_data.mainTagger2.active; }, setter: function(value) { user_data.mainTagger2.active = value; }, editor: "bool" } }, autoOpen: { label: sangu_trans.mainTagger.autoOpen, propUI: { getter: function() { return user_data.mainTagger2.autoOpen; }, setter: function(value) { user_data.mainTagger2.autoOpen = value; }, editor: "bool" } }, inputBoxWidth: { label: sangu_trans.mainTagger.inputBoxWidth, propUI: { getter: function() { return user_data.mainTagger2.inputBoxWidth; }, setter: function(value) { user_data.mainTagger2.inputBoxWidth = value; }, editor: "number|step=5" } }, autoOpenCommands: { label: sangu_trans.mainTagger.autoOpenCommands, propUI: { getter: function() { return user_data.mainTagger2.autoOpenCommands; }, setter: function(value) { user_data.mainTagger2.autoOpenCommands = value; }, editor: "bool" } }, minutesDisplayDodgeTimeOnMap: { label: sangu_trans.mainTagger.minutesDisplayDodgeTimeOnMap, tooltip: sangu_trans.mainTagger.minutesDisplayDodgeTimeOnMapTooltip, propUI: { getter: function() { return user_data.mainTagger2.minutesDisplayDodgeTimeOnMap; }, setter: function(value) { user_data.mainTagger2.minutesDisplayDodgeTimeOnMap = value; }, editor: "number" } }, minutesWithoutAttacksDottedLine: { label: sangu_trans.mainTagger.minutesWithoutAttacksDottedLine, propUI: { getter: function() { return user_data.mainTagger2.minutesWithoutAttacksDottedLine; }, setter: function(value) { user_data.mainTagger2.minutesWithoutAttacksDottedLine = value; }, editor: "number|step=60" } }, colorSupport: { label: sangu_trans.mainTagger.colorSupport, propUI: { getter: function() { return user_data.mainTagger2.colorSupport; }, setter: function(value) { user_data.mainTagger2.colorSupport = value; }, editor: "color" } }, defaultDescription: { label: sangu_trans.mainTagger.defaultDescription, tooltip: sangu_trans.mainTagger.defaultDescriptionTooltip, propUI: { getter: function() { return user_data.mainTagger2.defaultDescription; }, setter: function(value) { user_data.mainTagger2.defaultDescription = value; }, editor: "text" } }, keepReservedWords: { label: sangu_trans.mainTagger.keepReservedWords, tooltip: sangu_trans.mainTagger.keepReservedWordsTooltip, propUI: { getter: function() { return user_data.mainTagger2.keepReservedWords; }, setter: function(value) { user_data.mainTagger2.keepReservedWords = value; }, editor: "bool" } }, otherButtonsTitle: { type: "subtitle", label: sangu_trans.mainTagger.otherButtons.title } }; for (var i = 0; i < user_data.mainTagger2.otherDescs.length; i++) { (function() { var otherDescription = user_data.mainTagger2.otherDescs[i]; properties['otherButton'+i] = { type: "subtitle", label: sangu_trans.mainTagger.otherButtons.title + ": " + otherDescription.name } properties['otherButtonActive'+i] = { label: sangu_trans.global.resources.activate, propUI: { getter: function() { return otherDescription.active; }, setter: function(value) { otherDescription.active = value; }, editor: "bool" } } properties['otherButtonName'+i] = { label: sangu_trans.mainTagger.otherButtons.button, propUI: { getter: function() { return otherDescription.name; }, setter: function(value) { otherDescription.name = value; }, editor: "text|width=10" } } properties['otherButtonHitKey'+i] = { label: sangu_trans.mainTagger.otherButtons.hitKey, propUI: { getter: function() { return otherDescription.hitKey; }, setter: function(value) { otherDescription.hitKey = value; }, editor: "text|width=4" } } properties['otherButtonDesc'+i] = { label: sangu_trans.mainTagger.otherButtons.renameTo, propUI: { getter: function() { return otherDescription.renameTo; }, setter: function(value) { otherDescription.renameTo = value; }, editor: "text|width=50" } } }()); } user_data_configs.push({ id: "mainTagger", title: sangu_trans.mainTagger.title, save: sangu_saver, properties: properties }); }()); } if (showConfigs) { user_data_configs.push({ id: "confirm", title: sangu_trans.confirm.title, save: sangu_saver, properties: { addExtraOkButton: { label: sangu_trans.confirm.addExtraOkButton, propUI: { getter: function() { return user_data.confirm.addExtraOkButton; }, setter: function(value) { user_data.confirm.addExtraOkButton = value; }, editor: "bool" } }, replaceNightBonus: { label: sangu_trans.confirm.replaceNightBonus, show: world_config.nightbonus.active, propUI: { getter: function() { return user_data.confirm.replaceNightBonus; }, setter: function(value) { user_data.confirm.replaceNightBonus = value; }, editor: "bool" } }, replaceTribeClaim: { label: sangu_trans.confirm.replaceTribeClaim, propUI: { getter: function() { return user_data.confirm.replaceTribeClaim; }, setter: function(value) { user_data.confirm.replaceTribeClaim = value; }, editor: "bool" } }, addCatapultImages: { label: sangu_trans.confirm.addCatapultImages, propUI: { getter: function() { return user_data.confirm.addCatapultImages; }, setter: function(value) { user_data.confirm.addCatapultImages = value; }, editor: "bool" } } } }); } if (showConfigs) { user_data_configs.push({ id: "profile", title: sangu_trans.profile.title, save: sangu_saver, properties: { show: { label: sangu_trans.global.resources.activate, propUI: { getter: function() { return user_data.profile.show; }, setter: function(value) { user_data.profile.show = value; }, editor: "bool" } }, moveClaim: { label: sangu_trans.profile.moveClaim, propUI: { getter: function() { return user_data.profile.moveClaim; }, setter: function(value) { user_data.profile.moveClaim = value; }, editor: "bool" } }, mapLink: { type: "subtitle", label: sangu_trans.profile.mapLink.title }, mapLinkShow: { label: sangu_trans.global.resources.activate, propUI: { getter: function() { return user_data.profile.mapLink.show; }, setter: function(value) { user_data.profile.mapLink.show = value; }, editor: "bool" } }, mapLinkFill: { label: sangu_trans.profile.mapLink.fill, propUI: { getter: function() { return user_data.profile.mapLink.fill; }, setter: function(value) { user_data.profile.mapLink.fill = value; }, editor: "color" } }, mapLinkZoom: { label: sangu_trans.profile.mapLink.zoom, propUI: { getter: function() { return user_data.profile.mapLink.zoom; }, setter: function(value) { user_data.profile.mapLink.zoom = value; }, editor: "number|step=10" } }, mapLinkGrid: { label: sangu_trans.profile.mapLink.grid, propUI: { getter: function() { return user_data.profile.mapLink.grid; }, setter: function(value) { user_data.profile.mapLink.grid = value; }, editor: "bool" } }, mapLinkGridContinentNumbers: { label: sangu_trans.profile.mapLink.gridContinentNumbers, propUI: { getter: function() { return user_data.profile.mapLink.gridContinentNumbers; }, setter: function(value) { user_data.profile.mapLink.gridContinentNumbers = value; }, editor: "bool" } }, mapLinkPlayerColor: { label: sangu_trans.profile.mapLink.playerColor, propUI: { getter: function() { return user_data.profile.mapLink.playerColor; }, setter: function(value) { user_data.profile.mapLink.playerColor = value; }, editor: "color" } }, mapLinkTribeColor: { label: sangu_trans.profile.mapLink.tribeColor, propUI: { getter: function() { return user_data.profile.mapLink.tribeColor; }, setter: function(value) { user_data.profile.mapLink.tribeColor = value; }, editor: "color" } }, mapLinkCentreX: { label: sangu_trans.profile.mapLink.centreX, propUI: { getter: function() { return user_data.profile.mapLink.centreX; }, setter: function(value) { user_data.profile.mapLink.centreX = value; }, editor: "number|step=10" } }, mapLinkCentreY: { label: sangu_trans.profile.mapLink.centreY, propUI: { getter: function() { return user_data.profile.mapLink.centreY; }, setter: function(value) { user_data.profile.mapLink.centreY = value; }, editor: "number|step=10" } }, mapLinkOwnColor: { label: sangu_trans.profile.mapLink.ownColor, propUI: { getter: function() { return user_data.profile.mapLink.ownColor; }, setter: function(value) { user_data.profile.mapLink.ownColor = value; }, editor: "color" } }, mapLinkMarkedOnly: { label: sangu_trans.profile.mapLink.markedOnly, propUI: { getter: function() { return user_data.profile.mapLink.markedOnly; }, setter: function(value) { user_data.profile.mapLink.markedOnly = value; }, editor: "bool" } }, mapLinkBigMarkers: { label: sangu_trans.profile.mapLink.bigMarkers, propUI: { getter: function() { return user_data.profile.mapLink.bigMarkers; }, setter: function(value) { user_data.profile.mapLink.bigMarkers = value; }, editor: "bool" } }, mapLinkYourTribeColor: { label: sangu_trans.profile.mapLink.yourTribeColor, propUI: { getter: function() { return user_data.profile.mapLink.yourTribeColor; }, setter: function(value) { user_data.profile.mapLink.yourTribeColor = value; }, editor: "color" } }, popup: { type: "subtitle", label: sangu_trans.profile.popup.title }, popupShow: { label: sangu_trans.global.resources.activate, propUI: { getter: function() { return user_data.profile.popup.show; }, setter: function(value) { user_data.profile.popup.show = value; }, editor: "bool" } }, popupTop: { label: sangu_trans.profile.popup.top, propUI: { getter: function() { return user_data.profile.popup.top; }, setter: function(value) { user_data.profile.popup.top = value; }, editor: "number|step=25" } }, popupLeft: { label: sangu_trans.profile.popup.left, propUI: { getter: function() { return user_data.profile.popup.left; }, setter: function(value) { user_data.profile.popup.left = value; }, editor: "number|step=25" } }, popupWidth: { label: sangu_trans.profile.popup.width, propUI: { getter: function() { return user_data.profile.popup.width; }, setter: function(value) { user_data.profile.popup.width = value; }, editor: "number|step=25" } }, popupHeight: { label: sangu_trans.profile.popup.height, propUI: { getter: function() { return user_data.profile.popup.height; }, setter: function(value) { user_data.profile.popup.height = value; }, editor: "number|step=25" } } } }); } if (showConfigs) { user_data_configs.push({ id: "placeLinks", title: sangu_trans.place.title, save: sangu_saver, properties: { scoutTitle: { type: "subtitle", label: sangu_trans.place.scoutTitle }, scoutPlaceLinksName: { label: sangu_trans.place.linkText, propUI: { getter: function() { return user_data.place.attackLinks.scoutPlaceLinksName; }, setter: function(value) { user_data.place.attackLinks.scoutPlaceLinksName = value; }, editor: "text|width=23" } }, scoutVillage: { label: sangu_trans.place.scoutVillage, propUI: { getter: function() { return user_data.place.attackLinks.scoutVillage; }, setter: function(value) { user_data.place.attackLinks.scoutVillage = value; }, editor: "number|step=10" } }, scoutPlaceLinks: { label: sangu_trans.place.scoutPlaceLinks, propUI: { getter: function() { return user_data.place.attackLinks.scoutPlaceLinks; }, setter: function(value) { user_data.place.attackLinks.scoutPlaceLinks = value; }, editor: "array|addNew:number|step=10|delete" } }, fakePlaceLinkTitle: { type: "subtitle", label: sangu_trans.place.fakePlaceLinkTitle }, fakePlaceLinkName: { label: sangu_trans.place.linkText, propUI: { getter: function() { return user_data.place.attackLinks.fakePlaceLinkName; }, setter: function(value) { user_data.place.attackLinks.fakePlaceLinkName = value; }, editor: "text|width=23" } }, fakePlaceLink: { label: sangu_trans.global.resources.activate, propUI: { getter: function() { return user_data.place.attackLinks.fakePlaceLink; }, setter: function(value) { user_data.place.attackLinks.fakePlaceLink = value; }, editor: "bool" } }, fakePlaceExcludeTroops: { label: sangu_trans.place.fakePlaceExcludeTroops, tooltip: sangu_trans.place.fakePlaceExcludeTroopsTooltip, propUI: { getter: function() { return user_data.place.attackLinks.fakePlaceExcludeTroops; }, setter: function(value) { user_data.place.attackLinks.fakePlaceExcludeTroops = value; }, editor: "array|addNew:text|delete|width=7" } }, noblePlaceLinkTitle: { type: "subtitle", label: sangu_trans.place.noblePlaceLinkTitle }, noblePlaceLinkDivideTitle: { type: "subtitle", label: sangu_trans.place.noblePlaceLinkDivideTitle }, noblePlaceLinkDivideName: { label: sangu_trans.place.linkText, propUI: { getter: function() { return user_data.place.attackLinks.noblePlaceLinkDivideName; }, setter: function(value) { user_data.place.attackLinks.noblePlaceLinkDivideName = value; }, editor: "text|width=23" } }, noblePlaceLink: { label: sangu_trans.global.resources.activate, propUI: { getter: function() { return user_data.place.attackLinks.noblePlaceLink; }, setter: function(value) { user_data.place.attackLinks.noblePlaceLink = value; }, editor: "bool" } }, noblePlaceLinkDivideAddRam: { label: sangu_trans.place.noblePlaceLinkDivideAddRam, propUI: { getter: function() { return user_data.place.attackLinks.noblePlaceLinkDivideAddRam; }, setter: function(value) { user_data.place.attackLinks.noblePlaceLinkDivideAddRam = value; }, editor: "bool" } }, noblePlaceLinkFirstTitle: { type: "subtitle", label: sangu_trans.place.noblePlaceLinkFirstTitle }, noblePlaceLinkFirstName: { label: sangu_trans.place.linkText, tooltip: sangu_trans.place.noblePlaceLinkFirstNameTooltip, propUI: { getter: function() { return user_data.place.attackLinks.noblePlaceLinkFirstName; }, setter: function(value) { user_data.place.attackLinks.noblePlaceLinkFirstName = value; }, editor: "text|width=23" } }, noblePlaceLinkSupportTitle: { type: "subtitle", label: sangu_trans.place.noblePlaceLinkSupportTitle }, noblePlaceLinkSupportName: { label: sangu_trans.place.linkText, propUI: { getter: function() { return user_data.place.attackLinks.noblePlaceLinkSupportName; }, setter: function(value) { user_data.place.attackLinks.noblePlaceLinkSupportName = value; }, editor: "text|width=23" } }, noblePlaceLinksForceShow: { label: sangu_trans.place.noblePlaceLinksForceShow, propUI: { getter: function() { return user_data.place.attackLinks.noblePlaceLinksForceShow; }, setter: function(value) { user_data.place.attackLinks.noblePlaceLinksForceShow = value; }, editor: "bool" } }, nobleSupportOffTitle: { type: "subtitle", label: sangu_trans.place.nobleSupportOffTitle }, nobleSupportOffUnit: { label: sangu_trans.place.nobleSupportUnit, propUI: { getter: function() { return user_data.place.attackLinks.nobleSupport[0].unit; }, setter: function(value) { user_data.place.attackLinks.nobleSupport[0].unit = value; }, editor: "unit" } }, nobleSupportOffAmount: { label: sangu_trans.place.nobleSupportAmount, propUI: { getter: function() { return user_data.place.attackLinks.nobleSupport[0].amount; }, setter: function(value) { user_data.place.attackLinks.nobleSupport[0].amount = value; }, editor: "number|step=50" } }, nobleSupportDefTitle: { type: "subtitle", label: sangu_trans.place.nobleSupportDefTitle }, nobleSupportDefUnit: { label: sangu_trans.place.nobleSupportUnit, propUI: { getter: function() { return user_data.place.attackLinks.nobleSupport[1].unit; }, setter: function(value) { user_data.place.attackLinks.nobleSupport[1].unit = value; }, editor: "unit" } }, nobleSupportDefAmount: { label: sangu_trans.place.nobleSupportAmount, propUI: { getter: function() { return user_data.place.attackLinks.nobleSupport[1].amount; }, setter: function(value) { user_data.place.attackLinks.nobleSupport[1].amount = value; }, editor: "number|step=50" } } } }); } if (showConfigs) { (function() { var i, properties = {}; for (i = 0; i < user_data.place.customPlaceLinks.length; i++) { (function() { var unitTypeIndex, customPlaceLink = user_data.place.customPlaceLinks[i], oneTimeTooltip = i == 0 ? sangu_trans.place.customPlaceOneTimeTooltip : undefined, oneTimeTooltipSendAlong = i == 0 ? sangu_trans.place.customPlaceSendAlongTooltip : undefined; properties['customPlaceLink'+i+'Title'] = { type: "subtitle", label: sangu_trans.place.link.replace("{name}", customPlaceLink.name) }; properties['customPlaceLink'+i+'Name'] = { label: sangu_trans.place.linkText, propUI: { getter: function() { return customPlaceLink.name; }, setter: function(value) { customPlaceLink.name = value; }, editor: "text|width=23" } }; properties['customPlaceLink'+i+'Active'] = { label: sangu_trans.global.resources.activate, propUI: { getter: function() { return customPlaceLink.active; }, setter: function(value) { customPlaceLink.active = value; }, editor: "bool" } }; for (unitTypeIndex = 0; unitTypeIndex < world_data.units.length; unitTypeIndex++) { (function() { var unit = world_data.units[unitTypeIndex], reallyOneTimeTooltip = unitTypeIndex == 0 && oneTimeTooltip ? oneTimeTooltip : undefined; properties['customPlaceLink'+i+unit] = { label: "<img src='graphic/unit/unit_"+unit+".png'/>", tooltip: reallyOneTimeTooltip, propUI: { getter: function() { return customPlaceLink[unit]; }, setter: function(value) { customPlaceLink[unit] = value; }, editor: "number|step=100" } }; })(); } properties['customPlaceLink'+i+'SendAlong'] = { label: sangu_trans.place.customPlaceSendAlong, tooltip: oneTimeTooltipSendAlong, propUI: { getter: function() { return customPlaceLink.sendAlong; }, setter: function(value) { customPlaceLink.sendAlong = value; }, editor: "number|step=100" } }; })(); } user_data_configs.push({ id: "placeLinksCustom", title: sangu_trans.place.titleCustom, save: sangu_saver, properties: properties }); }()); } if (showConfigs) { user_data_configs.push({ id: "overviewsTroops", title: sangu_trans.overviews.command.title, save: sangu_saver, properties: { changeTroopsOverviewLink: { label: sangu_trans.overviews.command.changeTroopsOverviewLink, propUI: { getter: function() { return user_data.command.changeTroopsOverviewLink; }, setter: function(value) { user_data.command.changeTroopsOverviewLink = value; }, editor: "bool" } }, defaultPopulationFilterAmount: { label: sangu_trans.overviews.troopsRestack.defaultPopulationFilterAmount, propUI: { getter: function() { return user_data.restack.defaultPopulationFilterAmount; }, setter: function(value) { user_data.restack.defaultPopulationFilterAmount = value; }, editor: "number|step=1000" } }, titleOwnTroopsPage: { type: "subtitle", label: sangu_trans.overviews.command.titleOwnTroopsPage }, middleMouseClickDeletesRow: { label: sangu_trans.overviews.command.middleMouseClickDeletesRow, tooltip: sangu_trans.overviews.command.middleMouseClickDeletesRowTooltip, propUI: { getter: function() { return user_data.command.middleMouseClickDeletesRow2; }, setter: function(value) { user_data.command.middleMouseClickDeletesRow2 = value; }, editor: "bool" } }, filterAutoSort: { label: sangu_trans.overviews.command.filterAutoSort, propUI: { getter: function() { return user_data.command.filterAutoSort; }, setter: function(value) { user_data.command.filterAutoSort = value; }, editor: "bool" } }, titleDefensePage: { type: "subtitle", label: sangu_trans.overviews.command.titleDefensePage }, fieldsDistanceFilterDefault: { label: sangu_trans.overviews.troopsRestack.fieldsDistanceFilterDefault, propUI: { getter: function() { return user_data.restack.fieldsDistanceFilterDefault; }, setter: function(value) { user_data.restack.fieldsDistanceFilterDefault = value; }, editor: "number" } }, filterReverse: { label: sangu_trans.overviews.troopsRestack.filterReverse, tooltip: sangu_trans.overviews.troopsRestack.filterReverseTooltip, propUI: { getter: function() { return user_data.restack.filterReverse; }, setter: function(value) { user_data.restack.filterReverse = value; }, editor: "bool" } }, filterMinPopulation: { label: sangu_trans.overviews.command.filterMinPopulation, propUI: { getter: function() { return user_data.command.filterMinPopulation; }, setter: function(value) { user_data.command.filterMinPopulation = value; }, editor: "number|step=1000" } }, removeRowsWithoutSupport: { label: sangu_trans.overviews.troopsRestack.removeRowsWithoutSupport, propUI: { getter: function() { return user_data.restack.removeRowsWithoutSupport; }, setter: function(value) { user_data.restack.removeRowsWithoutSupport = value; }, editor: "bool" } }, autohideWithoutSupportAfterFilter: { label: sangu_trans.overviews.troopsRestack.autohideWithoutSupportAfterFilter, tooltip: sangu_trans.overviews.troopsRestack.autohideWithoutSupportAfterFilterTooltip, propUI: { getter: function() { return user_data.restack.autohideWithoutSupportAfterFilter; }, setter: function(value) { user_data.restack.autohideWithoutSupportAfterFilter = value; }, editor: "bool" } }, calculateDefTotalsAfterFilter: { label: sangu_trans.overviews.troopsRestack.calculateDefTotalsAfterFilter, tooltip: sangu_trans.overviews.troopsRestack.calculateDefTotalsAfterFilterTooltip, propUI: { getter: function() { return user_data.restack.calculateDefTotalsAfterFilter; }, setter: function(value) { user_data.restack.calculateDefTotalsAfterFilter = value; }, editor: "bool" } }, commandTitle: { type: "subtitle", label: sangu_trans.overviews.command.filterOnUnitTypeSeperator }, filterMinDefaultType: { label: sangu_trans.overviews.command.filterMinDefaultType, propUI: { getter: function() { return user_data.command.filterMinDefaultType; }, setter: function(value) { user_data.command.filterMinDefaultType = value; }, editor: "unit" } }, filterMinDefault: { label: sangu_trans.overviews.command.filterMinDefault, tooltip: sangu_trans.overviews.command.filterMinDefaultTooltip, propUI: { getter: function() { return user_data.command.filterMinDefault; }, setter: function(value) { user_data.command.filterMinDefault = value; }, editor: "number|step=100" } }, filterMinSpear: { label: "<img src='graphic/unit/unit_spear.png' />", propUI: { getter: function() { return user_data.command.filterMin.spear; }, setter: function(value) { user_data.command.filterMin.spear = value; }, editor: "number|step=500" } }, filterMinSword: { label: "<img src='graphic/unit/unit_sword.png' />", propUI: { getter: function() { return user_data.command.filterMin.sword; }, setter: function(value) { user_data.command.filterMin.sword = value; }, editor: "number|step=500" } }, filterMinAxe: { label: "<img src='graphic/unit/unit_axe.png' />", propUI: { getter: function() { return user_data.command.filterMin.axe; }, setter: function(value) { user_data.command.filterMin.axe = value; }, editor: "number|step=500" } }, filterMinArcher: { label: "<img src='graphic/unit/unit_archer.png' />", show: world_config.hasArchers, propUI: { getter: function() { return user_data.command.filterMin.archer; }, setter: function(value) { user_data.command.filterMin.archer = value; }, editor: "number|step=500" } }, filterMinSpy: { label: "<img src='graphic/unit/unit_spy.png' />", propUI: { getter: function() { return user_data.command.filterMin.spy; }, setter: function(value) { user_data.command.filterMin.spy = value; }, editor: "number|step=100" } }, filterMinLight: { label: "<img src='graphic/unit/unit_light.png' />", propUI: { getter: function() { return user_data.command.filterMin.light; }, setter: function(value) { user_data.command.filterMin.light = value; }, editor: "number|step=100" } }, filterMinMarcher: { label: "<img src='graphic/unit/unit_marcher.png' />", show: world_config.hasArchers, propUI: { getter: function() { return user_data.command.filterMin.marcher; }, setter: function(value) { user_data.command.filterMin.marcher = value; }, editor: "number|step=100" } }, filterMinHeavy: { label: "<img src='graphic/unit/unit_heavy.png' />", propUI: { getter: function() { return user_data.command.filterMin.heavy; }, setter: function(value) { user_data.command.filterMin.heavy = value; }, editor: "number|step=100" } }, filterMinRam: { label: "<img src='graphic/unit/unit_ram.png' />", propUI: { getter: function() { return user_data.command.filterMin.ram; }, setter: function(value) { user_data.command.filterMin.ram = value; }, editor: "number|step=10" } }, filterMinCatapult: { label: "<img src='graphic/unit/unit_catapult.png' />", propUI: { getter: function() { return user_data.command.filterMin.catapult; }, setter: function(value) { user_data.command.filterMin.catapult = value; }, editor: "number|step=10" } }, filterMinSnob: { label: "<img src='graphic/unit/unit_snob.png' />", propUI: { getter: function() { return user_data.command.filterMin.snob; }, setter: function(value) { user_data.command.filterMin.snob = value; }, editor: "number" } }, filterMinOther: { label: sangu_trans.overviews.command.filterMinOther, propUI: { getter: function() { return user_data.command.filterMinOther; }, setter: function(value) { user_data.command.filterMinOther = value; }, editor: "number|step=500" } }, restackTitle: { type: "subtitle", label: sangu_trans.overviews.troopsRestack.title }, troopsRestackTo: { label: sangu_trans.overviews.troopsRestack.to, propUI: { getter: function() { return user_data.restack.to; }, setter: function(value) { user_data.restack.to = value; }, editor: "number|step=1000" } }, requiredDifference: { label: sangu_trans.overviews.troopsRestack.requiredDifference, propUI: { getter: function() { return user_data.restack.requiredDifference; }, setter: function(value) { user_data.restack.requiredDifference = value; }, editor: "number|step=500" } } } }); } if (showConfigs) { user_data_configs.push({ id: "overviewsCommands", title: sangu_trans.overviews.commands.title, save: sangu_saver, properties: { sumRow: { label: sangu_trans.overviews.commands.sumRow, propUI: { getter: function() { return user_data.command.sumRow; }, setter: function(value) { user_data.command.sumRow = value; }, editor: "bool" } }, filterFakeMaxPop: { label: sangu_trans.overviews.commands.filterFakeMaxPop, propUI: { getter: function() { return user_data.command.filterFakeMaxPop; }, setter: function(value) { user_data.command.filterFakeMaxPop = value; }, editor: "number|step=100" } }, requiredTroopAmount: { label: sangu_trans.overviews.commands.requiredTroopAmount, propUI: { getter: function() { return user_data.command.bbCodeExport.requiredTroopAmount; }, setter: function(value) { user_data.command.bbCodeExport.requiredTroopAmount = value; }, editor: "number|step=100" } } } }); } if (showConfigs) { user_data_configs.push({ id: "overviewsResources", title: sangu_trans.overviews.resources.title, save: sangu_saver, properties: { requiredResDefault: { label: sangu_trans.overviews.resources.requiredResDefault, propUI: { getter: function() { return user_data.resources.requiredResDefault; }, setter: function(value) { user_data.resources.requiredResDefault = value; }, editor: "number|step=10000" } }, requiredMerchants: { label: sangu_trans.overviews.resources.requiredMerchants, propUI: { getter: function() { return user_data.resources.requiredMerchants; }, setter: function(value) { user_data.resources.requiredMerchants = value; }, editor: "number|step=10" } }, filterMerchants: { label: sangu_trans.overviews.resources.filterMerchants, propUI: { getter: function() { return user_data.resources.filterMerchants; }, setter: function(value) { user_data.resources.filterMerchants = value; }, editor: "bool" } }, highlightColor: { label: sangu_trans.overviews.resources.highlightColor, propUI: { getter: function() { return user_data.resources.highlightColor; }, setter: function(value) { user_data.resources.highlightColor = value; }, editor: "color" } }, filterRows: { label: sangu_trans.overviews.resources.filterRows, propUI: { getter: function() { return user_data.resources.filterRows; }, setter: function(value) { user_data.resources.filterRows = value; }, editor: "bool" } }, bbcodeMinimumDiff: { label: sangu_trans.overviews.resources.bbcodeMinimumDiff, propUI: { getter: function() { return user_data.resources.bbcodeMinimumDiff; }, setter: function(value) { user_data.resources.bbcodeMinimumDiff = value; }, editor: "number|step=2000" } } } }); } if (showConfigs) { // Buildingsoverview: (function() { var properties = {}, i; for (i = 0; i < world_data.buildings.length; i++) { (function() { var captured_index = i, building_name = world_data.buildings[captured_index], buildingPrettyfier = function(building) { return "<img src='graphic/buildings/"+building+".png'>"; }; properties[building_name+'_min'] = { label: sangu_trans.overviews.buildings.minLevel.replace("{building}", buildingPrettyfier(building_name)), propUI: { getter: function() { return user_data.buildings[building_name][0]; }, setter: function(value) { user_data.buildings[building_name][0] = value; }, editor: "number" } }; properties[building_name+'_max'] = { label: sangu_trans.overviews.buildings.maxLevel.replace("{building}", buildingPrettyfier(building_name)), propUI: { getter: function() { return user_data.buildings[building_name][1]; }, setter: function(value) { user_data.buildings[building_name][1] = value; }, editor: "number" } }; })(); } user_data_configs.push({ id: "overviewsBuildings", title: sangu_trans.overviews.buildings.title, save: sangu_saver, properties: properties }); }()); } if (showConfigs) { // Incomingsoverview: (function() { var properties = {}, i; properties.attackIdTitle = { type: "subtitle", label: sangu_trans.overviews.incomings.attackIdTitle }; for (i = 0; i < user_data.incomings.attackIdDescriptions.length; i++) { (function() { var captured_index = i; properties['incomings_attackIdDesc'+captured_index+'_title'] = { type: "subtitle", label: sangu_trans.overviews.incomings.seperatorTitle.replace("{minValue}", user_data.incomings.attackIdDescriptions[captured_index].minValue) }; properties['incomings_attackIdDesc'+captured_index+'_minValue'] = { label: sangu_trans.overviews.incomings.minValue, tooltip: captured_index == 0 ? sangu_trans.overviews.incomings.minValueTooltip : undefined, propUI: { getter: function() { return user_data.incomings.attackIdDescriptions[captured_index].minValue; }, setter: function(value) { user_data.incomings.attackIdDescriptions[captured_index].minValue = value; }, editor: "number" } }; properties['incomings_attackIdDesc'+captured_index+'_text'] = { label: sangu_trans.overviews.incomings.text, propUI: { getter: function() { return user_data.incomings.attackIdDescriptions[captured_index].text; }, setter: function(value) { user_data.incomings.attackIdDescriptions[captured_index].text = value; }, editor: "text" } }; })(); } properties['incomings_attackIdDescMaxText'] = { label: sangu_trans.overviews.incomings.attackIdHigherDescription, propUI: { getter: function() { return user_data.incomings.attackIdHigherDescription; }, setter: function(value) { user_data.incomings.attackIdHigherDescription = value; }, editor: "text" } }; user_data_configs.push({ id: "overviewsIncomings", title: sangu_trans.overviews.incomings.title, save: sangu_saver, properties: properties }); }()); } if (showConfigs) { user_data_configs.push({ id: "other", title: sangu_trans.other.title, save: sangu_saver, properties: { fancyImages: { label: sangu_trans.overviews.addFancyImagesToOverviewLinks, propUI: { getter: function() { return user_data.overviews.addFancyImagesToOverviewLinks; }, setter: function(value) { user_data.overviews.addFancyImagesToOverviewLinks = value; }, editor: "bool" } }, proStyle: { tooltip: sangu_trans.other.proStyleTooltip, label: sangu_trans.other.proStyle, propUI: { getter: function() { return user_data.proStyle; }, setter: function(value) { user_data.proStyle = value; }, editor: "bool" } }, calculateSnob: { label: sangu_trans.other.calculateSnob, show: !world_config.coins, propUI: { getter: function() { return user_data.other.calculateSnob; }, setter: function(value) { user_data.other.calculateSnob = value; }, editor: "bool" } }, showPlayerProfileOnVillage: { label: sangu_trans.other.showPlayerProfileOnVillage, propUI: { getter: function() { return user_data.showPlayerProfileOnVillage; }, setter: function(value) { user_data.showPlayerProfileOnVillage = value; }, editor: "bool" } }, overviewAjaxSeperateSupport: { label: sangu_trans.other.ajaxSeperateSupport, show: server_settings.ajaxAllowed, propUI: { getter: function() { return user_data.overview.ajaxSeperateSupport; }, setter: function(value) { user_data.overview.ajaxSeperateSupport = value; }, editor: "bool" } }, canHideDiv: { label: sangu_trans.other.canHideDiv, propUI: { getter: function() { return user_data.overview.canHideDiv; }, setter: function(value) { user_data.overview.canHideDiv = value; }, editor: "bool" } }, timeDisplayTitle: { type: "subtitle", label: sangu_trans.other.timeDisplayTitle }, walkingTimeDisplay: { label: sangu_trans.other.walkingTimeDisplay, tooltip: sangu_trans.other.walkingTimeDisplayTooltip, propUI: { getter: function() { return user_data.walkingTimeDisplay; }, setter: function(value) { user_data.walkingTimeDisplay = value; }, editor: "text" } }, displayDays: { label: sangu_trans.other.displayDays, tooltip: sangu_trans.other.displayDaysTooltip, propUI: { getter: function() { return user_data.displayDays; }, setter: function(value) { user_data.displayDays = value; }, editor: "bool" } }, commandRenamerTitle: { type: "subtitle", label: sangu_trans.other.commandRenamer }, commandRenamerActive: { label: sangu_trans.other.commandRenamerActive, propUI: { getter: function() { return user_data.attackAutoRename.active; }, setter: function(value) { user_data.attackAutoRename.active = value; }, editor: "bool" } }, commandRenamerAddHaul: { label: sangu_trans.other.commandRenamerAddHaul, propUI: { getter: function() { return user_data.attackAutoRename.addHaul; }, setter: function(value) { user_data.attackAutoRename.addHaul = value; }, editor: "bool" } }, farmLimitTitle: { type: "subtitle", label: sangu_trans.other.farmLimitTitle }, farmLimitColors: { label: sangu_trans.other.farmLimitStackColors, propUI: { getter: function(propIndex) { return user_data.farmLimit.stackColors; }, setter: function(value, propIndex) { user_data.farmLimit.stackColors = value; }, editor: "array|addNew:color|delete" } }, farmLimitAcceptableOverstack: { label: sangu_trans.other.farmLimitAcceptableOverstack, tooltip: sangu_trans.other.farmLimitAcceptableOverstackTooltip.replace("{farmlimit}", 30 * world_config.farmLimit), show: world_config.farmLimit, propUI: { getter: function() { return user_data.farmLimit.acceptableOverstack; }, setter: function(value) { user_data.farmLimit.acceptableOverstack = value; }, editor: "array|addNew:float|delete|step=0.01" } }, farmLimitUnlimitedStack: { label: sangu_trans.other.farmLimitUnlimitedStack, show: !world_config.farmLimit, propUI: { getter: function() { return user_data.farmLimit.unlimitedStack; }, setter: function(value) { user_data.farmLimit.unlimitedStack = value; }, editor: "array|addNew:number|delete|step=1000" } } } }); } if (showConfigs) { // Extra links on village info to troop overview (function() { var properties = {}, i; function addSetting(properties, index, offDef, propName, label, editor, tooltip) { properties['infoPage_extra_link'+index+'_'+offDef+propName] = { label: label, tooltip: tooltip, propUI: { getter: function() { return user_data.villageInfo4[index][offDef][propName]; }, setter: function(value) { user_data.villageInfo4[index][offDef][propName] = value; }, editor: editor } }; } // hehe function addSetting2(properties, index, offDef, propName, label, editor, tooltip) { properties['infoPage_extra_link'+index+'_'+offDef+propName] = { label: label, tooltip: tooltip, propUI: { getter: function() { return user_data.villageInfo4[index][offDef].filter[propName]; }, setter: function(value) { user_data.villageInfo4[index][offDef].filter[propName] = value; }, editor: editor } }; } function add2Links(captured_index, offDef) { addSetting(properties, captured_index, offDef+"_link", "name", sangu_trans.villageInfo.linkName, "text"); addSetting(properties, captured_index, offDef+"_link", "icon", sangu_trans.villageInfo.icon, "text"); addSetting(properties, captured_index, offDef+"_link", "sort", sangu_trans.villageInfo.sort, "bool"); addSetting(properties, captured_index, offDef+"_link", "changeSpeed", sangu_trans.villageInfo.changeSpeed, "unit"); addSetting(properties, captured_index, offDef+"_link", "group", sangu_trans.villageInfo.group, "number", sangu_trans.villageInfo.groupTitle); properties['incomings_attackIdDesc'+captured_index+offDef+'_FilterTitle'] = { type: "subtitle", label: sangu_trans.villageInfo.filter.title }; addSetting2(properties, captured_index, offDef+"_link", "active", sangu_trans.villageInfo.filter.title, "bool"); addSetting2(properties, captured_index, offDef+"_link", "unit", sangu_trans.villageInfo.filter.unit, "unit"); addSetting2(properties, captured_index, offDef+"_link", "amount", sangu_trans.villageInfo.filter.amount, "number|step=100"); } for (i = 0; i < user_data.villageInfo4.length; i++) { (function() { var captured_index = i; properties['incomings_attackIdDesc'+captured_index+'_title'] = { type: "subtitle", label: sangu_trans.villageInfo.title2 + " " + (captured_index + 1) }; properties['infoPage_extra_link'+captured_index+'_activate'] = { label: sangu_trans.global.resources.activate, propUI: { getter: function() { return user_data.villageInfo4[captured_index].active; }, setter: function(value) { user_data.villageInfo4[captured_index].active = value; }, editor: "bool" } }; properties['incomings_attackIdDesc'+captured_index+"off"+'_title'] = { type: "subtitle", label: sangu_trans.villageInfo.off_title }; add2Links(captured_index, "off"); properties['incomings_attackIdDesc'+captured_index+"def"+'_title'] = { type: "subtitle", label: sangu_trans.villageInfo.def_title }; add2Links(captured_index, "def"); })(); } user_data_configs.push({ id: "villageInfoLinks", title: sangu_trans.villageInfo.title, save: sangu_saver, properties: properties }); }()); } return user_data_configs; }()); (function() { // contentPage is the place we will add the settings menu to var contentPage = $("table:first td:last", content_value).attr("width", "99%"), sanguTitle = "<h3 id='sanguConfigTitle'>" + trans.sp.sp.configuration.replace("{version}", sangu_version) + "</h3>"; function gimmeTheMoney() { function createButton(paypalCode, euroAmount, tooltip) { return '<div align="center">' + '<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">' + '<input type="hidden" name="cmd" value="_s-xclick">' + '<input type="hidden" name="hosted_button_id" value="' + paypalCode + '">' + '<input type="image" src="https://www.paypalobjects.com/nl_NL/BE/i/btn/btn_donate_SM.gif" border="0" name="submit" title="'+tooltip+'">' + '<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">' + '<br>' + trans.sp.sp.donate.buttonAmount.replace("{amount}", euroAmount) + '</form></div>'; } var html = "<h3>Contributors</h3>"; html += "Hebben aan het Sangu Package meegewerkt: <br><b>"; html += "De Goede Fee, Tjeerdo, cgrain, Hardcode93"; html += "</b>"; html += "<h3>"+trans.sp.sp.donate.title+"</h3>"; html += trans.sp.sp.donate.whyWouldI; html += "<br>" + trans.sp.sp.donate.books .replace("{abegin}", "<a target='_blank' href='http://www.amazon.com/wishlist/1RFQ21NSF4PAI/ref=cm_wl_prev_ret?_encoding=UTF8&reveal='>") .replace("{aend}", "</a>"); html += "<br><br>" + "<table width='100%'><tr>" + "<td>" + createButton("FA9MAMFAYKANL", 5, trans.sp.sp.donate.beer) + "</td>" + "<td>" + createButton("R9RX6XBCV6T4G", 10, trans.sp.sp.donate.food) + "</td>" + "<td>" + createButton("ELG8Y2GLSXAVA", 20, trans.sp.sp.donate.yaye) + "</td>" + "</tr>" + "</table>"; return html; } // Reset sangu settings links var resetForm = "<a href='#' id='resetSettings'>» " + trans.sp.sp.settings.reset + "</a>"; resetForm += "<br>"; resetForm += "<a href='#' id='resetAllSettings'>» " + trans.sp.sp.settings.resetAll + "</a>"; // skeleton injection contentPage.html(sanguTitle + "<div id='sanguSettingsForm'>" + resetForm + gimmeTheMoney() + "</div>"); gimmeTheMoney(); $("#sanguSettingsForm").append("<br><br>"); $("#resetSettings").click(function() { if (confirm(trans.sp.sp.settings.reset)) { pers.set('sangusettings', ''); location.reload(false); } return false; }); $("#resetAllSettings").click(function() { if (confirm(trans.sp.sp.settings.resetAll)) { pers.clear(); location.reload(false); } return false; }); (function() { var sanguSettingsForm, configIterator, settingFormTogglerHtml, settingsFormsOpenFromPersistence, adornButton = function(button) { $(button).css("background-color", user_data.colors.error); }; sanguSettingsForm = $("#sanguSettingsForm"); settingFormTogglerHtml = "<h3>" + trans.sp.sp.settings.configuration + "</h3>"; settingFormTogglerHtml += "<table class='vis' width='100%'><tr class='row_a'><th>" + trans.sp.sp.settings.configurationFormTogglerTooltip + "</th></tr><tr class='row_b'><td>"; for (configIterator = 0; configIterator < user_data_configs.length; configIterator++) { settingFormTogglerHtml += "<input type='button' value=\"" + user_data_configs[configIterator].title + "\" id='"+user_data_configs[configIterator].id + "_button' class='editFormToggler' /> "; } settingFormTogglerHtml += "</td></tr></table><br>"; sanguSettingsForm.append(settingFormTogglerHtml); $(".editFormToggler", sanguSettingsForm).click(function() { var openForms = "", linkedDiv = $("#" + this.id.replace("_button", "")); if (linkedDiv.is(":visible")) { linkedDiv.hide(); $(this).css("background-color", ""); } else { linkedDiv.fadeIn(); adornButton(this); } $(".propertyEditFormContainer", sanguSettingsForm).each(function() { if ($(this).is(":visible")) { openForms += this.id + "|"; } }); pers.set("settingsFormsOpen", openForms); }); // build the property handler editting form for (configIterator = 0; configIterator < user_data_configs.length; configIterator++) { buildConfigForm(sanguSettingsForm, user_data_configs[configIterator]); } settingsFormsOpenFromPersistence = pers.get("settingsFormsOpen"); $(".propertyEditFormContainer", sanguSettingsForm).each(function() { if (settingsFormsOpenFromPersistence.indexOf(this.id+"|") > -1) { adornButton($("#" + this.id + "_button")); $(this).show(); } }); $('input[id*="mainTagger_otherButtonHitKey"]').on('keydown', function(e){ e.preventDefault(); e.stopPropagation(); var TagNumber = $(this).attr("id").match(/\d+/); $(this).val(''); $(this).val(keyCodeMap[e.which].toUpperCase()); user_data.mainTagger2.otherDescs[TagNumber]["hitKey"] = $(this).val(); pers.set('sangusettings', JSON.stringify(user_data)); trackEvent("ScriptUsage", "SettingEdit", "1"); }) })(); // notable contributors (function() { var notableHtml = "<u>" + trans.sp.sp.donate.notable + "</u>"; notableHtml += "<br><br><b>sakeb</b>: Nogmaals bedankt voor 'JavaScript: The Good Parts'! :)"; notableHtml += "<br><b>Daniel Ivanov</b>"; notableHtml += "<br><br>"; $("#sanguSettingsForm").append(notableHtml); })(); })(); } break; case "place": /** * {spVillage} The current village */ var vilHome = getVillageFromCoords(game_data.village.coord); if ($("#attack_name").size() > 0) { // RALLYPOINT CONFIRM (function() { //console.time("confirm"); try { // reorder the page if (user_data.proStyle) { $("table:first", content_value).css("width", 500); // Merge nightbonus & tribe claim statements (for OK button placement) if (user_data.proStyle && (user_data.confirm.replaceTribeClaim || user_data.confirm.replaceNightBonus)) { var header = $("h2:first", content_value); var claim = $("h3.error:visible"); if (claim.size() != 0) { claim.each(function() { var $this = $(this); $this.hide(); header.addClass("error").text(header.text() + " - " + $this.text()); }); } } } // extra attack button (always on the same place) if (user_data.confirm.addExtraOkButton) { $("h2:first", content_value).prepend("<input type=submit style='font-size: 10pt' id=focusPlaceHolder value='" + $("#troop_confirm_go").val() + "'><br>"); $("#focusPlaceHolder").click(function () { $(this).attr("disabled", "disabled"); $("#troop_confirm_go").click(); }); } // Catapult building images if (user_data.confirm.addCatapultImages && $("#save_default_attack_building").length == 1) { var dropdown = $("select[name='building']"); var buildingImages = ""; dropdown.find("option").each(function(index, value) { buildingImages += "<img class='catapultSwitcher' title='" + trans.sp.command.catapultImageTitle + "' building='" + $(value).val() +"' src='https://www.tribalwars.vodka/graphic/buildings/" + $(value).val() + ".png'> "; }); dropdown.parent().parent().before("<tr><td colspan=4>"+buildingImages+"</td></tr>"); $("img.catapultSwitcher").click(function() { dropdown.val($(this).attr("building")); }); } var valueCells = $("table.vis:first td:odd", content_value); var targetVillage = valueCells.first().text(); // remember last attack // saved at the confirmation page so that we can't save // invalid coordinates var village = getVillageFromCoords(targetVillage); if (village.isValid) { pers.set("lastVil", village.coord); } var isAttack = $("input[name='attack']").val() == "true"; var isBarbarian = valueCells.eq(1).has("a").length === 0; var player = (isBarbarian ? '' : valueCells.eq(1).text()); var unitsSent = {}; $.each(world_data.units, function (i, val) { unitsSent[val] = parseInt($("input[name='" + val + "']", content_value).val(), 10); }); // compare runtime with dodgetime var unitsCalc = calcTroops(unitsSent); var dodgeCookie = pers.getCookie("sanguDodge" + getQueryStringParam("village")); if (dodgeCookie) { dodgeCookie = dodgeCookie.split("~"); var durationCell = $("table.vis:first td:contains('" + trans.tw.command.walkingTimeTitle + "')", content_value).next(); var attackRunTime = getTimeFromTW(durationCell.text()); var dodgeTime = getTimeFromTW(dodgeCookie[1]); var runtimeIsOk = attackRunTime.totalSecs >= dodgeTime.totalSecs; var diffSecs = (attackRunTime.totalSecs - dodgeTime.totalSecs); var dodgeCellText = "<table border=0 cellpadding=0 cellspacing=0 width='1%'><tr>"; dodgeCellText += "<td width='25%' align=center>" + durationCell.text() + "</td>"; dodgeCellText += "<td width='50%' align=center><b>" + (runtimeIsOk ? ">>>" : "<<<") + "</b></td>"; dodgeCellText += "<td width='25%' align=center nowrap>" + dodgeCookie[1] + " "; if (diffSecs > 0) { dodgeCellText += trans.sp.command.dodgeMinuteReturn.replace("{minutes}", prettyDate(diffSecs * 2000, true)); // 2000 = Method expects milliseconds and distance is walked 2 times! } dodgeCellText += "</td>"; dodgeCellText += "</tr></table>"; durationCell.html(dodgeCellText); if (!runtimeIsOk) { 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); } if (dodgeCookie[0] != "unit_" + unitsCalc.getSlowest()) { $("h2:first", content_value).css("background-color", user_data.colors.error); } } else { // If a dodgecookie is in use, nightbonus etc isn't relevant unitsCalc.colorIfNotRightAttackType($("h2:first", content_value), isAttack); var arrivalTime = getDateFromTodayTomorrowTW($.trim($("#date_arrival").text())); if (user_data.proStyle && user_data.confirm.replaceNightBonus && isDateInNightBonus(arrivalTime)) { $("#date_arrival").css("background-color", user_data.colors.error).css("font-weight", "bold"); } } if (user_data.attackAutoRename.active) { // rename attack command // cookie reading code in place.js var villageCoord = $("input[name='x']", content_value).val() + '|' + $("input[name='y']", content_value).val(); var sent = buildAttackString(villageCoord, unitsSent, player, !isAttack); document.title = game_data.village.coord + " -> " + sent; var twInitialCommandName = (isAttack ? trans.tw.command.attackOn : trans.tw.command.supportFor) + targetVillage; pers.setSession("attRen_" + game_data.village.id + '_' + twInitialCommandName, sent); } } catch (e) { handleException(e, "place-confirm"); } //console.timeEnd("confirm"); }()); } // RALLYPOINT UNITS THERE else if (current_page.mode === 'units' && location.href.indexOf('try=back') == -1) { (function() { //console.time("units_back"); try { var units_awayTable = $("#units_away").width("100%"); if (units_awayTable.size() != 0) { // Troops in other villages $("tr:first", units_awayTable).append( "<th>" + trans.sp.place.distance + "</th>" + "<th>" + trans.sp.place.backOn + "</th>"); units_awayTable.find("tr:gt(0):even").each(function() { var row = $(this), villageCoord = getVillageFromCoords(row.find("td:eq(1)").text()); if (!villageCoord.isValid) { row.append("<th> </th><th> </th>"); } else { var slowestUnit = null; var slowestUnitName = null; $.each(world_data.units, function (i, val) { var amount = $("td:eq(" + (i + 2) + "), th:eq(" + (i + 1) + ")", row).text(); if (amount != '0') { if (slowestUnit == null || slowestUnit < world_data.unitsSpeed['unit_' + val]) { slowestUnitName = val; slowestUnit = world_data.unitsSpeed['unit_' + val]; } } }); var fields = getDistance(vilHome.x, villageCoord.x, vilHome.y, villageCoord.y, slowestUnitName); var extraColumns = "<td align=right>" + parseInt(fields.fields, 10) + "</td>"; extraColumns += "<td>" + twDateFormat(fields.arrivalTime) + "</td>"; row.append(extraColumns); } }); } // Calculate distance and walkingtime to the villages var unitsTable = $("form table:first"); $("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>'); unitsTable.find("tr:gt(0)").each(function () { var pop = 0; var row = $(this); var slowestUnit = null; var slowestUnitName = null; $.each(world_data.units, function (i, val) { var amount = parseInt($("td:eq(" + (i + 1) + "), th:eq(" + (i + 1) + ")", row).text(), 10); if (amount !== 0) { pop += amount * world_data.unitsPositionSize[i]; if (slowestUnit == null || slowestUnit < world_data.unitsSpeed['unit_' + val]) { slowestUnitName = val; slowestUnit = world_data.unitsSpeed['unit_' + val]; } } }); var villageCoord = getVillageFromCoords(row.find("td:first").text()); var color = getStackColor(pop); if (color !== "") { $(this).append("<td align=right style='background-color: " + color + "'>" + formatNumber(pop) + "</td><td colspan=2> </td>"); } else { var extraColumns = '<td align=right>' + formatNumber(pop) + '</td>'; if (!villageCoord.isValid) { extraColumns += "<td colspan=2 align=right> </td>"; } else { //q(vilHome.x + ':' + slowestUnitName); var dist = getDistance(vilHome.x, villageCoord.x, vilHome.y, villageCoord.y, slowestUnitName), fields = parseInt(dist.fields, 10); extraColumns += "<td align=right>" + fields + "</td><td>" + twDateFormat(dist.arrivalTime) + "</td>"; $("td:first", this).append(" <b>" + trans.sp.all.fieldsSuffix.replace("{0}", fields) + "</b>"); $(this).addClass("toSort").attr("fields", fields); } $(this).append(extraColumns); } }); var checkboxAmount = $("input[type='checkbox']", unitsTable); if (checkboxAmount.size() == 1) { // village has just been taken over? auto check checkbox checkboxAmount.attr("checked", true); } // Sort on distance unitsTable.find("tr.toSort").sortElements(function (a, b) { return parseInt($(a).attr("fields"), 10) < parseInt($(b).attr("fields"), 10) ? 1 : -1; }); // are there incomings on the supporting villages? if (server_settings.ajaxAllowed) { unitsTable.find("tr.toSort").each(function() { var row = $(this); var villageUrl = $("a:first", this).attr("href"); ajax(villageUrl, function (villageDetails) { var villageOwner = $("table.vis:first tr:eq(4) a", villageDetails); if (villageOwner.text() != game_data.player.name) { $("td:first a", row).after(" [" + villageOwner.outerHTML() + "]"); } else { var incomingTable = $("table th:contains('" + trans.tw.overview.incomingTroops + "')", villageDetails); if (incomingTable.size() > 0) { incomingTable = incomingTable.parent().parent(); var incomingRows = $("tr:has(img[src*='attack'])", incomingTable); if (incomingRows.size() > 0) { var firstAttack = incomingRows.eq(0); var timeLeft = $("td:eq(2)", firstAttack).text(); var arrivalDate = $("td:eq(1)", firstAttack).text(); var lastAttack = incomingRows.last(); var timeLeftLast = $("td:eq(2)", lastAttack).text(); var arrivalDateLast = $("td:eq(1)", lastAttack).text(); var amount = incomingRows.size(); var attacksDesc; if (amount == 1) { attacksDesc = trans.sp.place.onlyAttack .replace("{timeLeftFirst}", timeLeft) .replace("{arrivalDateFirst}", arrivalDate); } else { attacksDesc = trans.sp.place.multipleAttack .replace("{timeLeftFirst}", timeLeft) .replace("{arrivalDateFirst}", arrivalDate) .replace("{timeLeftLast}", timeLeftLast) .replace("{arrivalDateLast}", arrivalDateLast) .replace("{amount}", amount); } $("td:first input", row).after(" <img src='graphic/command/attack.png' title='" + attacksDesc + "'>"); } } } }); }); } } catch (e) { handleException(e, "place-units_back"); } //console.timeEnd("units_back"); }()); } // RALLY POINT (DEFAULT) else { (function() { //console.time("place-place"); try { // Auto rename attacks if (user_data.attackAutoRename.active) { // Less than ideal solution: // Does not work properly when sending many attacks (ie snobtrain) // In confirm.js the cookies are saved var hasAttackRenamingCookieNeedle = pers.getWorldKey('attRen_' + game_data.village.id + '_'); for (var i = 0; i < sessionStorage.length; i++) { var key = sessionStorage.key(i); if (key.indexOf(hasAttackRenamingCookieNeedle) == 0) { var twInitialCommandName = key.substr(hasAttackRenamingCookieNeedle.length); //q("found:" + hasAttackRenamingCookieNeedle + " -> " + twInitialCommandName); // ' is an invalid village name character so we don't need to escape var commandLabel = $('.quickedit-label:contains("' + twInitialCommandName + '")'); if (commandLabel.length > 0 && server_settings.ajaxAllowed) { var sanguCommandName = sessionStorage.getItem(key); // Open the rename command form: commandLabel.parent().next().click(); // Fill in new command name and click rename button var commandWrapper = commandLabel.parent().parent().parent(), commandForm = commandWrapper.find(".quickedit-edit"); commandForm.find("input:first").val(sanguCommandName); commandForm.find("input:last").click(); pers.removeSessionItem(key); if (commandLabel.closest("table").find("tr").length > 2) { commandLabel.closest("td").addClass("selected"); } } } } } $("#inputx,#inputy").focus(function() { $(this).select(); }); // fill in coordinates? (links from troops overview page) if (server_settings.autoFillCoordinatesAllowed && window.location.search.indexOf("&sanguX=") != -1) { var match = window.location.search.match(/sanguX=(\d+)&sanguY=(\d+)/); if (typeof match[1] !== "undefined") { $("#inputx").val(match[1]); $("#inputy").val(match[2]); } } // Spice up rally point: var speedCookie = spSpeedCookie(); (function() { try { // Show current selected speed + ability to change active speed $(".unit_link img", content_value).each(function() { $(this).attr("title", trans.sp.place.changeSpeedImageTooltips.replace("{originalTitle}", $(this).attr("title"))); }); $("#command-data-form a img").click(function () { var unit = this.src; unit = unit.substr(unit.lastIndexOf('/') + 1); unit = unit.substr(0, unit.lastIndexOf('.')); speedCookie = spSpeedCookie(unit); $("#command-data-form a img").css("border", "0px").filter("img[src*='" + unit + "']").css("border", "3px red solid"); // lastvil var coord = getVillageFromCoords(pers.get("lastVil")); if (coord.isValid) { var dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, speedCookie); $("#lastVilTime")[0].innerHTML = dist.html; } // targetVillage coord = getVillageFromCoords(spTargetVillageCookie()); if (coord.isValid) { dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, speedCookie); $("#targetVilTime")[0].innerHTML = dist.html; } }).filter("img[src*='" + speedCookie + "']").css("border", "3px red solid"); } catch (e) { handleException(e, "place-activespeed"); } }()); (function() { try { // sangupackage last village var cookie = pers.get("lastVil"), coord = getVillageFromCoords(cookie), dist; if (coord.isValid) { dist = getDistance(coord.x, vilHome.x, coord.y, vilHome.y, speedCookie); var htmlStr = printCoord(coord, "» " + trans.sp.all.last + ": " + coord.x + "|" + coord.y); htmlStr += " <span id=lastVilTime>" + dist.html + "</span>"; $("#command-data-form").append(htmlStr); } // Add target village var targetVillage = getVillageFromCoords(spTargetVillageCookie()); if (targetVillage.isValid) { dist = getDistance(targetVillage.x, vilHome.x, targetVillage.y, vilHome.y, speedCookie); $("#command-data-form").append("<br>" + printCoord(targetVillage, "» " + trans.sp.all.target + ": " + targetVillage.x + "|" + targetVillage.y) + " <span id=targetVilTime>" + dist.html + "</span>"); } } catch (e) { handleException(e, "place-lastandtargetvillage"); } }()); (function() { try { // Read troops available var units = []; units.total = 0; $("#command-data-form .unitsInput").each(function () { var amount = $(this).next().text().substr(1); units[this.name] = parseInt(amount.replace(")", ""), 10); units.total += units[this.name] * world_data.unitsSize['unit_'+this.name]; }); // Add extra links next to "All troops" function createRallyPointScript(linksContainer, unitLoop, name, min, checkFunction, tag) { send = {}; $.each(unitLoop, function (i, v) { if (units[v] >= min) { send[v] = checkFunction(units[v], v, tag); } }); linksContainer.append(" <a href='#' onclick='" + fillRallyPoint(send) + "; return false'>" + name + "</a>"); } var villageType = calcTroops(units); var linksContainer = $('#selectAllUnits').parent().attr("colspan", 4); // add fake attack var minFake = 0; if (world_config.hasMinFakeLimit) { minFake = getBuildingPoints(); minFake *= world_config.minFake; if (units.ram > 0) { minFake -= world_data.unitsSize['unit_ram']; } } if (user_data.place.attackLinks.fakePlaceLink && units['total'] >= minFake) { createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.fakePlaceLinkName, 0, function (amount, v, tag) { if ((v == 'ram' || v == 'catapult') && !tag.rammed && amount > 0) { tag.rammed = true; return 1; } if (v == 'snob' || tag.toSend <= 0 || amount == 0) { return 0; } if (user_data.place.attackLinks.fakePlaceExcludeTroops.indexOf(v) > -1) { return 0; } var farmSize = world_data.unitsSize['unit_' + v]; if (amount * farmSize > tag.toSend) { amount = Math.ceil(tag.toSend / farmSize); } tag.toSend -= amount * farmSize; if (v == 'sword' && amount > 0) { tag.toSend++; amount--; } return amount; }, { toSend: minFake, rammed: false }); } if (units['total'] > 0) $.each(user_data.place.customPlaceLinks, function (i, v) { if (v.active && villageType.isMatch(v.type)) { // villageType: off, def, all if (v.required == undefined || units[v.required[0]] >= v.required[1]) { // requires certain amount of troops if (v.totalPop == undefined) { // work with absolute numbers createRallyPointScript(linksContainer, world_data.units, v.name, 0, function (amount, unitVal, tag) { //q(v + ' - SEND:' + tag[v] + '; amount=' + amount + ';'); var send = tag[unitVal]; if (send != undefined && amount > 0) { //q("send: " + send + " // amount: " + amount + " // unitVal: " + unitVal); if (send < 0) { send = amount + send; if (send < 0) { send = 1; } } if ((amount - send) * world_data.unitsSize['unit_' + unitVal] < tag.sendAlong) { send = amount; } if (send > 0 && !tag.ignoreNobles) { $.each(user_data.place.attackLinks.nobleSupport, function (i, val) { if (unitVal == val.unit && villageType.isMatch(val.villageType)) { send -= Math.ceil(units.snob * val.amount); } }); } //if (unitVal == 'light') q(send); if (send > amount) { return amount; } if (send > 0) { return send; } } return 0; }, v); } else { // do automatic calculation which division of troops to select ////{ active: true, type: 'def', name: 'HelftZc', totalPop: 10000, divideOver: ['spear', 'heavy'] }, // TODO this doesn't yet work, does it? // Probably not active... var totalPop = 0; $.each(v.divideOver, function (i, val) { totalPop += units[val] * world_data.unitsSize['unit_' + val]; }); createRallyPointScript(linksContainer, world_data.units, v.name, 0, function (amount, unitVal, tag) { if ($.inArray(unitVal, tag.divideOver) == -1) { return 0; } if (totalPop < tag.totalPop) { return amount; } var currentUnitPercentage = (amount * world_data.unitsSize['unit_' + unitVal]) / totalPop; return Math.floor(amount * currentUnitPercentage); }, v); } } } }); if (units.spy >= user_data.place.attackLinks.scoutVillage && user_data.place.attackLinks.scoutPlaceLinks != null && user_data.place.attackLinks.scoutPlaceLinks.length > 0) { $.each(user_data.place.attackLinks.scoutPlaceLinks, function (i, v) { if (units.spy >= v) { createRallyPointScript(linksContainer, ["spy"], user_data.place.attackLinks.scoutPlaceLinksName.replace("{amount}", v), 0, function (amount, v, tag) { return tag; }, v); } }); } if (units.snob > 0 && user_data.place.attackLinks.noblePlaceLink) { if (user_data.place.attackLinks.noblePlaceLinkFirstName) { createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.noblePlaceLinkFirstName, 0, function (amount, v, tag) { if (v == 'snob') { return 1; } if (tag > 0) { var returned = null; $.each(user_data.place.attackLinks.nobleSupport, function (i, val) { if (v == val.unit && villageType.isMatch(val.villageType)) { returned = amount - Math.ceil((tag - 1) * val.amount); } }); if (returned != null) { return returned; } } return amount; }, units.snob); } if (user_data.place.attackLinks.noblePlaceLinkSupportName && (units.snob > 1 || user_data.place.attackLinks.noblePlaceLinksForceShow)) { createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.noblePlaceLinkSupportName, 0, function (amount, v, tag) { if (v == 'snob') { return 1; } var returned = 0; $.each(user_data.place.attackLinks.nobleSupport, function (i, val) { if (v == val.unit && villageType.isMatch(val.villageType)) { returned = Math.ceil(1 * val.amount); } }); return returned; }); } if (units.snob > 0 && user_data.place.attackLinks.noblePlaceLinkDivideName) { createRallyPointScript(linksContainer, world_data.units, user_data.place.attackLinks.noblePlaceLinkDivideName, 0, function (amount, v, tag) { if (v == 'snob') { return 1; } if (v == 'catapult') { return 0; } if (v == 'ram' && !user_data.place.attackLinks.noblePlaceLinkDivideAddRam) { return 0; } return Math.floor(amount / units.snob); }); } } } catch (e) { handleException(e, "place-extratrooplinks"); } }()); } catch (e) { handleException(e, "place-place"); } //console.timeEnd("place-place"); }()); } break; case "overview_villages": break; } // USERPROFIEL++ // INFO_ ALLY/PLAYER if ((current_page.screen === 'info_ally' || current_page.screen === 'info_player' || current_page.screen === 'info_village') || (current_page.screen === "ally" && current_page.mode === "profile")) { (function() { try { var tables = $('table.vis', content_value), villageInfoTable = tables.first(), commandsTable = villageInfoTable.next('table'), profile = user_data.profile, i; if (game_data.player.premium && location.href.indexOf('screen=info_village') > -1) { // extra links on the village overview page var createFilterLink = function(baseLink, settings) { var link = baseLink + "&group=" + settings.group + "&sort=" + settings.sort + "&changeSpeed=" + settings.changeSpeed; if (settings.filter.active) { link += "&unit=" + settings.filter.unit + "&amount=" + settings.filter.amount; } var fancyIcon = settings.icon ? "<img src='" + settings.icon + "'>" : ""; return "<a href='" + link + "'>" + fancyIcon + settings.name + "</a>"; }; for (i = 0; i < user_data.villageInfo4.length; i++) { var currentPairInfo = user_data.villageInfo4[i]; if (currentPairInfo.active) { var id = villageInfoTable.find("td:eq(2)").text(), link = getUrlString( "&screen=overview_villages&type=own_home&mode=units&page=-1&targetvillage=" + id.substr(id.lastIndexOf("=") + 1)); commandsTable.find("tbody:first").append( "<tr><td>" + createFilterLink(link, currentPairInfo.off_link) + "</td>" + "<td>" + createFilterLink(link, currentPairInfo.def_link) + "</td><tr>"); } } } if (user_data.profile.show && (location.href.indexOf('screen=info_village') == -1 || user_data.showPlayerProfileOnVillage)) { var screen; var mapProfile = user_data.profile.mapLink; var isVillage = false; if (current_page.screen !== 'info_ally' && current_page.screen !== "ally") { // player and village info page // Extra links and info in table at the left top screen = "player"; if (user_data.proStyle) { $("td:first", content_value).closest('table').hasClass('modemenu') ? $(content_value).find('table:has("#villages_list") td:first').css("width", "40%").next().css("width", "60%") : $("td:first", content_value).css("width", "40%").next().css("width", "60%"); } if (current_page.screen === 'info_player') { // player info page id = commandsTable.find("a[href*='screen=mail']").attr("href"); if (id == undefined) { id = game_data.player.id; } else { id = id.substr(id.indexOf("&player=") + 8); //alert(id); if (id.indexOf("&") > -1) { id = id.substr(0, id.indexOf("&")); } } } else { // village info page isVillage = true; commandsTable = $("table.vis:first", content_value); id = commandsTable.find("tr:eq(3) a"); //assert(id.size() == 1, "player id not found on info_village page"); if (id.size() > 0) { id = id.attr("href").match(/id=(\d+)/)[1]; assert(!!id, "player id href is not set"); } else { id = 0; } } // Direct link to TW Stats map if (id > 0 && profile.mapLink.show) { var link = "https://" + game_data.market + ".twstats.com/" + game_data.world + "/index.php?page=map"; var tribeId = commandsTable.prev('table').find("td:eq(8) a"); //assert(tribeId.size() == 1, "tribe id not found"); // Not everyone is in a tribe if (tribeId.size() == 1) { tribeId = tribeId.attr("href").match(/id=(\d+)/)[1]; assert(!isNaN(tribeId), "tribe id is not a number"); } else tribeId = 0; if (mapProfile.tribeColor != null) { link += "&tribe_0_id=" + tribeId + "&tribe_0_colour=" + mapProfile.tribeColor.substr(1); } if (mapProfile.yourTribeColor != null && game_data.player.ally_id != tribeId && game_data.player.ally_id > 0) { link += "&tribe_1_id=" + game_data.player.ally_id + "&tribe_1_colour=" + mapProfile.yourTribeColor.substr(1); } link += "&player_0_id=" + id + "&player_0_colour=" + mapProfile.playerColor.substr(1); link += "&grid=" + (mapProfile.grid ? 1 : 0) + "&fill=" + mapProfile.fill.substr(1) + "&zoom=" + mapProfile.zoom + "¢rex=" + mapProfile.centreX + "¢rey=" + mapProfile.centreY; if (mapProfile.markedOnly) { link += "&nocache=1"; } if (mapProfile.bigMarkers) { link += "&bm=1"; } if (mapProfile.gridContinentNumbers) { link += "&kn=1"; } if (mapProfile.ownColor != null && game_data.player.id != id) { link += "&player_1_id=" + game_data.player.id + "&player_1_colour=" + mapProfile.ownColor.substr(1); } commandsTable.find("tr:last").after("<tr><td colspan=2><a href='" + link + "' target='_blank'>» " + trans.sp.profile.twStatsMap + "</a> " + trans.sp.profile.externalPage + "</td></tr>"); } if (!isVillage) { // Amount of villages if (user_data.proStyle) { // always show villagename on one line var colWidth = $("table:eq(2) th", content_value); colWidth.first().css("width", "98%"); colWidth.eq(1).css("width", "1%"); colWidth.eq(2).css("width", "1%"); } var amountOfVillages = tables.eq(2).find("th:first").text(); amountOfVillages = amountOfVillages.substr(amountOfVillages.indexOf("(") + 1); amountOfVillages = amountOfVillages.substr(0, amountOfVillages.length - 1); commandsTable.prev('table').find("tr:eq(2)").after("<tr><td>" + trans.sp.profile.villages + "</td><td>" + formatNumber(amountOfVillages) + "</td></tr>"); } } else { screen = "tribe"; if (current_page.screen === 'info_ally') { commandsTable = tables.eq(0); } id = commandsTable.find("a"); id = id.last().attr("href").match(/&id=(\d+)/)[1]; var link = "https://" + game_data.market + ".twstats.com/" + game_data.world + "/index.php?page=map"; link += "&tribe_0_id=" + id + "&tribe_0_colour=" + mapProfile.tribeColor.substr(1); link += "¢rex=" + mapProfile.centreX + "¢rey=" + mapProfile.centreY; if (mapProfile.yourTribeColor != null && game_data.player.ally_id != id) { link += "&tribe_1_id=" + game_data.player.ally_id + "&tribe_1_colour=" + mapProfile.yourTribeColor.substr(1); } link += "&grid=" + (mapProfile.grid ? 1 : 0) + "&fill=" + mapProfile.fill.substr(1) + "&zoom=" + mapProfile.zoom if (mapProfile.markedOnly) { link += "&nocache=1"; } if (mapProfile.bigMarkers) { link += "&bm=1"; } if (mapProfile.gridContinentNumbers) { link += "&kn=1"; } if (mapProfile.ownColor != null) { link += "&player_0_id=" + game_data.player.id + "&player_0_colour=" + mapProfile.ownColor.substr(1); } commandsTable.find("tr:last").before("<tr><td colspan=2><a href='" + link + "' target='_blank'>» " + trans.sp.profile.twStatsMap + "</a> " + trans.sp.profile.externalPage + "</td></tr>"); } // Build graphs if (id > 0) { var html = ""; // TWMap graphs var twMapGraphs; if (screen == "tribe") { twMapGraphs = [["tribe", trans.sp.profile.graphTWMap], ["p_tribe", trans.sp.profile.graphPoints], ["oda_tribe", trans.sp.profile.graphODA], ["odd_tribe", trans.sp.profile.graphODD]]; } else { 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]]; } for (var i = 0; i < twMapGraphs.length; i++) { var graphDetails = screen == "tribe" ? profile.twMapTribeGraph[twMapGraphs[i][0]] : profile.twMapPlayerGraph[twMapGraphs[i][0]]; if (graphDetails[0]) { 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]); } } // TWStats graphs 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]]; if (screen == "tribe") { graphs.push(["members", trans.sp.profile.graphMembers]); } var toShow = screen == "tribe" ? profile.tribeGraph : profile.playerGraph; for (var i = 0; i < graphs.length; i++) { if (toShow[i][1]) { var graphType = toShow[i][1] == 'big' ? 'ss' : ''; 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); } } // Show graphs if (html.length > 0) { var pictureTable; if (screen == 'player' || (isVillage && user_data.showPlayerProfileOnVillage)) { pictureTable = $(content_value).find('table:has("th:first:contains(Profiel)")'); // TODO: untranslated resource Profiel if (isVillage || pictureTable.html() == null) { // With no info nor personal text pictureTable = $("<table class='vis' width='100%'><tr><th colspan='2'>" + trans.tw.profile.title + "</th></tr></table>"); $("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); } else if (pictureTable.find("th").text() != trans.tw.profile.title) { // TODO: There is a ; after the IF, is that the intention??? if (pictureTable.find("th:first").text() == trans.tw.profile.awardsWon); pictureTable = pictureTable.parent(); // If there is only the node "Personal info" var temp = $("<table class='vis' width='100%'><tr><th colspan='2'>" + trans.tw.profile.title + "</th></tr></table>"); pictureTable.prepend(temp); pictureTable = temp; } if (pictureTable.find("td[colspan=2]").size() > 0) { pictureTable.find("tr:last").before("<tr><td colspan=2>" + html + "</td></tr>"); } else { pictureTable.find("tr:last").after("<tr><td colspan=2>" + html + "</td></tr>"); } } else { commandsTable.after("<table class=vis width='100%'><tr><th>" + trans.tw.profile.title + "</th></tr><tr><td>" + html + "</td></tr></table>"); } } } // Conquers (intern) if (id > 0 && profile.popup.show) { 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='; var conquers = "<tr><td colspan=2><a href=\"\" id='conquers'>» " + trans.sp.profile.conquers + "</a> " + trans.sp.profile.internalPage + "</td></tr>"; if (screen == 'tribe') { commandsTable.find("tr:last").before(conquers); } else { commandsTable.find("tr:last").after(conquers); } var popupWidth = profile.popup.width; var popupHeight = profile.popup.height; commandsTable.after('<div class="messagepop pop" id="popup" style="display: none"><iframe src=' + twLink + ' width=' + popupWidth + ' height=' + popupHeight + '></div>'); $("#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" }); $(function () { $("#conquers").on('click', function (event) { if ($(this).hasClass('selected')) { $("#conquers").removeClass("selected"); } else { $(this).addClass("selected"); } $("#popup").toggle(); return false; }); $("#popup").on('click', function () { $("#popup").hide(); $("#conquers").removeClass("selected"); return false; }); }); } } if (current_page.screen === 'info_village' && user_data.proStyle && profile.moveClaim) { // move claim to a position that does not interfere with more important links (2-click behavior) if ($("td:eq(8)", commandsTable).text() == trans.tw.profile.claimedBy) { commandsTable.append($("tr:eq(5),tr:eq(6)", commandsTable)); } } } catch (e) { handleException(e, "info_villageplayertribe"); } }()); } if (current_page.screen === 'info_village') { //Written by hardcode (function() { var show = true; var head = $(".vis:contains('Aankomend')", content_value).find("tr:first"); var text = $("th:contains('Aankomst:')", content_value).html('Aankomend: <img src="https://www.tribalwars.vodka/graphic/minus.png" style=" float: right;">'); head.on("click", function () { if(show === true) { $(".no_ignored_command").hide(); text.html('Verborgen: <img src="https://www.tribalwars.vodka/graphic/plus.png" style=" float: right;">'); show = false; }else{ $(".no_ignored_command").show(); text.html('Aankomend: <img src="https://www.tribalwars.vodka/graphic/minus.png" style=" float: right;">'); show = true; } }); }()); } // ALL OVERVIEW PAGES if (current_page.screen === 'overview_villages') { var overviewTable; //tableHandler.overviewTable var tableHandler; (function (tableHandler) { function init(id, options) { tableHandler.overviewTableName = id; tableHandler.overviewTable = $("#" + id); tableHandler.settings = { hasBottomTotalRow: false }; tableHandler.settings = $.extend({}, tableHandler.settings, options || {}); // do stuff on page load ajaxLoadNextPageSetup(); } tableHandler.init = init; function getReplacedVillageRows(page) { var overviewTable = typeof page === 'undefined' ? tableHandler.overviewTable : $("#"+tableHandler.overviewTableName, page); if (typeof tableHandler.settings.rowReplacer === "function") { var newTable = ""; var villageRows = selectVillageRows(overviewTable); villageRows.each(function () { var row = $(this); newTable += tableHandler.settings.rowReplacer(row); }); return newTable; } else { return selectVillageRows(overviewTable); } } tableHandler.getReplacedVillageRows = getReplacedVillageRows; function selectVillageRows(page) { //q(tableHandler.overviewTableName); //q("grrrr:"+page.find("tr").not(":first").length); var villageRows = page.find("tr").not(":first"); if (tableHandler.settings.hasBottomTotalRow) { villageRows = villageRows.not(":last"); } //q(villageRows); return villageRows; } function ajaxLoadNextPageSetup() { if (server_settings.ajaxAllowed) { var nextPageLink = $("#paged_view_content a.paged-nav-item").first(); if (nextPageLink.length !== 0) { // find all pages we can still add to the current table var currentPageLabel = nextPageLink.parent().find("strong"); var nextPageLinks = []; currentPageLabel = currentPageLabel.next(); while (currentPageLabel.text().match(/\d/)) { nextPageLinks.push(currentPageLabel); currentPageLabel = currentPageLabel.next(); } if (nextPageLinks.length > 0) { nextPageLink.parent().append(" <a href=# id=loadNextPage>"+trans.sp.overviews.loadNextPage+"</a>"); $("#loadNextPage").click(function() { // Get next page or remove link var nextPageUrl = nextPageLinks[0]; if (nextPageLinks.length == 1) { $(this).replaceWith("<strong>"+trans.sp.overviews.loadNextPage+"</strong>"); } nextPageLinks.shift(); // Fetch and insert next page ajax(nextPageUrl.attr("href"), function (page) { var nextPageRows = getReplacedVillageRows($(page)); if (tableHandler.settings.hasBottomTotalRow) { tableHandler.overviewTable.find("tr:last").before(nextPageRows); } else { tableHandler.overviewTable.append(nextPageRows); } nextPageUrl.replaceWith("<strong>"+nextPageUrl.text()+"</strong>"); }); }); } } } } })(tableHandler || (tableHandler = {})); // PRODUCTION OVERVIEW if (location.href.indexOf('mode=prod') > -1) { (function() { //console.time("overview-prod"); try { overviewTable = $("#production_table"); tableHandler.init("production_table"); // Filter full storage rooms var resTable = $("#production_table"); var menu = "<table class='vis' width='100%'>"; menu += "<tr><th width='99%'>"; menu += " <input type=checkbox id=resFilter " + (user_data.resources.filterRows ? "checked" : "") + "> " + trans.sp.prodOverview.filter + " "; menu += " <input type=button id=resStorageFull value='" + trans.sp.prodOverview.filterFullGS + "' title=''> "; menu += "<select id=resAmountType><option value=1>" + trans.sp.all.more + "</option>"; menu += "<option value=-1>" + trans.sp.all.less + "</option></select>"; menu += "<input type=text id=resAmount size=6 value=" + user_data.resources.requiredResDefault + ">"; 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>"; menu += " " + trans.sp.all.withText + " <input type=checkbox id=resMerchant " + (user_data.resources.filterMerchants ? "checked" : "") + " title='" + trans.sp.prodOverview.merchantTooltip + "'>"; menu += "<input type=text id=resMerchantAmount size=2 value=" + user_data.resources.requiredMerchants + " title='" + trans.sp.prodOverview.merchantAmountTooltip + "'> " + trans.sp.all.merchants + " "; menu += "</th><th width='1%' nowrap>"; menu += "<input type=button id=resBBCode value='" + trans.sp.prodOverview.bbCodes + "'> " + "<input type=checkbox id=resBBCodeImages> " + trans.sp.prodOverview.bbCodesInfo + " "; menu += "</th></tr></table>"; resTable.before(menu); $("#resFilter").change(function () { var isCheck = $(this).is(":checked"); $("#resFilter").attr("title", isCheck ? trans.sp.prodOverview.filterTooltip : trans.sp.prodOverview.filterTooltipReverse); $("#resStorageFull").attr("title", isCheck ? trans.sp.prodOverview.filterFullGSTooltip : trans.sp.prodOverview.filterFullGSTooltipReverse); $(".resFilter").each(function (index, value) { if (index == 3) { $(value).attr("title", isCheck ? trans.sp.prodOverview.filterAllTooltip : trans.sp.prodOverview.filterAllTooltipReverse); } else { $(value).attr("title", isCheck ? trans.sp.prodOverview.filter1Tooltip.replace("{0}", $(value).attr("value")) : trans.sp.prodOverview.filter1TooltipReverse.replace("{0}", $(value).attr("value"))); } }); }); $("#resFilter").change(); $("#resStorageFull").click(function () { trackClickEvent("FilterFullRes"); filterRes('full', $("#resFilter").is(":checked")); }); $("#resBBCode").click(function () { trackClickEvent("BBCodeOutput"); var bbs = filterRes("bbcode", false), reverse = $("#resAmountType").val() == "-1", bbCodesTitle = reverse ? trans.sp.prodOverview.tooLittleText : trans.sp.prodOverview.tooMuchText; bbCodesTitle = bbCodesTitle .replace("{diff}", parseInt(user_data.resources.bbcodeMinimumDiff / 1000, 10)) .replace("{min}", parseInt(parseInt($("#resAmount").val(), 10) / 1000, 10)); if ($("#textsArea").size() == 0) { $(this).parent().parent().parent().append("<tr><td colspan=2 id=textsArea></td></tr>"); } else { $("#textsArea").html(""); } $("#textsArea").append("<b>" + bbCodesTitle + "</b>" + trans.sp.prodOverview.bbCodeExtraInfo + "<br><textarea id=bbcodeArea cols=50 rows=10 wrap=off>"); $("#bbcodeArea").val(bbs); $("#textsArea").append("<br><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>"); $("#closeTextsArea").click(function() { $("#textsArea").parent().remove(); }); }); function filterRes(resourceIndex, hideRows) { var resCode = [trans.tw.all.wood, trans.tw.all.stone, trans.tw.all.iron]; var bbcodes = ''; var goners = $(); var stayers = $(); var filterMerchants = $("#resMerchant").is(":checked"); var filterMerchantsAmount = parseInt($("#resMerchantAmount").val(), 10); var minAmount = parseInt($("#resAmount").val(), 10); var reverse = $("#resAmountType").val() == "-1"; var bbCodeImages = $("#resBBCodeImages").is(":checked"); var minDif = user_data.resources.bbcodeMinimumDiff; var bbCodesTitle; if (reverse) { bbcodes = trans.sp.prodOverview.tooLittle + "\n"; bbCodesTitle = trans.sp.prodOverview.tooLittleText; } else { bbcodes = trans.sp.prodOverview.tooMuch + "\n"; bbCodesTitle = trans.sp.prodOverview.tooMuchText; } bbCodesTitle = bbCodesTitle.replace("{min}", minDif).replace("{diff}", minAmount); function doResource(resCell, resArray, resIndex, reverse, minAmount) { var resAmount = parseInt(resArray[resIndex], 10); if ((!reverse && resAmount > minAmount) || (reverse && resAmount < minAmount)) { $("span[title]:eq(" + resIndex + ")", resCell).css("font-weight", "bold") return false; } return true; } var hasNotes = $("th:first", resTable).text().indexOf(trans.tw.overview.village) == -1; resTable.find("tr:gt(0)").each(function () { var isOk = true; var resCell; if (hasNotes) { resCell = $(this).find("td:eq(3)"); } else { resCell = $(this).find("td:eq(2)"); } var resources = $.trim(resCell.text()).replace(/\./gi, "").split(" "); if (resourceIndex == 'bbcode') { // All resources var villageBBCode = ''; for (var i = 0; i < 3; i++) { if ((!reverse && resources[i] - minDif > minAmount) || (reverse && parseInt(resources[i], 10) + parseInt(minDif, 10) < minAmount)) { if (bbCodeImages) { villageBBCode += "[img]https://www.tribalwars.nl/graphic/" + world_data.resources[i] + ".png[/img] "; } else { villageBBCode += resCode[i] + " "; } villageBBCode += parseInt(Math.abs(resources[i] - minAmount) / 1000, 10) + "k "; } } if (villageBBCode.length > 0) { var villageCell = $("td:eq(" + (hasNotes ? "1" : "0") + ") span:eq(1)", this); bbcodes += "[village]" + getVillageFromCoords(villageCell.text()).coord + "[/village] " + villageBBCode + "\n"; } } else if (resourceIndex == 'full') { // full storage rooms if ($(".warn", this).size() > 0) { resCell.css("background-color", user_data.resources.highlightColor); isOk = false; } } else { // One specific resource $("span[title]", resCell).css("font-weight", "normal"); if (resourceIndex == "-1") { isOk = isOk && !(!doResource(resCell, resources, 0, reverse, minAmount) | !doResource(resCell, resources, 1, reverse, minAmount) | !doResource(resCell, resources, 2, reverse, minAmount)); } else { isOk = isOk && doResource(resCell, resources, resourceIndex, reverse, minAmount); } if (!isOk) { resCell.css("background-color", user_data.resources.highlightColor); } else { resCell.css("background-color", ""); } if (filterMerchants) { resCell = $(this).find("td:eq(4)"); if (hasNotes) { resCell = resCell.next(); } var merchants = resCell.text(); merchants = merchants.substr(0, merchants.indexOf("/")); if (merchants < filterMerchantsAmount) { resCell.css("background-color", user_data.colors.error); } else { resCell.css("background-color", ""); } } } if (hideRows && isOk) { goners = goners.add($(this)); // Village rename script will not rename villages if the hidden rename inputfield is on a hidden row // --> People were using our script to filter the village list and then use a mass village renamer which also renamed the hidden village rows $("input:first", $(this)).val(""); } else if (!$(this).is(":visible")) { stayers = stayers.add($(this)); } }); if (hideRows) { goners.remove(); var amountOfVillagesCell = $("tr:first th", resTable).eq(hasNotes ? 1 : 0); amountOfVillagesCell.text(amountOfVillagesCell.text().replace(/\d+/, $("tr", resTable).size() - 1)); } else { stayers.show(); goners.hide(); } return bbcodes; } $(".resFilter").click(function () { trackClickEvent("FilterResource"); filterRes($(this).attr("resIndex"), $("#resFilter").is(":checked")); }); } catch (e) { handleException(e, "overview-prod"); } //console.timeEnd("overview-prod"); }()); } // TROOPS OVERVIEW else if (location.href.indexOf('mode=units') > -1 && (location.href.indexOf('type=own_home') > -1 || location.href.indexOf('type=there') > -1)) { (function() { //console.time("overview-thereownhome"); try { var villageCounter = 0; var rowSize = world_data.units.length + 1; if (world_config.hasMilitia) { rowSize++; } var overviewMenuRowFilter = "tr:gt(0)", /** * Page speed can be overruled by the querystring */ currentPageSpeed = spSpeedCookie(), /** * {village} object from target cookie (or by url querystring set) */ target; /** * Do initial filter? (based on querystring) */ var doFilter = false, unitIndex = world_data.units.indexOf(user_data.command.filterMinDefaultType), unitAmount = user_data.command.filterMinDefault, sort = false, changeSpeed = false, i; var search = window.location.search.substring(1).split("&"); for (i = 0; i < search.length; i++) { var item = search[i].split("="); switch (item[0]) { case 'unit': doFilter = true; unitIndex = world_data.units.indexOf(item[1]); break; case 'amount': doFilter = true; unitAmount = parseInt(item[1], 10); break; case 'changeSpeed': changeSpeed = item[1]; if (changeSpeed != false) { //spSpeedCookie(changeSpeed); currentPageSpeed = changeSpeed; } break; case 'targetvillage': var newTargetVillage = getVillageFromCoords(item[1]); spTargetVillageCookie(newTargetVillage.coord); break; case 'sort': sort = item[1] == "true"; break; } } // Sangu package menu is also built in reinitialize_table /** * Creates a select box with all unit types in this world * @param {string} id the DOM ID * @param {string} select the currently selected unit */ function makeUnitBox(id, select) { var box = "<select id=" + id + ">"; $.each(world_data.units, function (i, v) { box += "<option value=" + i + (v == select ? " selected" : "") + ">" + trans.tw.units.names[v] + "</option>"; }); box += "</select>"; return box; } var menu = "<table width='100%' class='vis'>"; menu += "<tr>"; menu += "<th nowrap width='1%'>"; menu += "<input type=text size=5 id=filterAxeValue value='" + user_data.command.filterMinDefault + "'>"; menu += makeUnitBox("filterAxeType", user_data.command.filterMinDefaultType); menu += "<input type=button id=filterAxe value='" + trans.sp.troopOverview.filterTroops + "'"; menu += " title='" + trans.sp.troopOverview.filterTroopsTooltip + "'> "; menu += "</th><th nowrap width='1%'>"; menu += "<select id=filterPopValueType><option value=1>" + trans.sp.all.more + "</option>"; menu += "<option value=-1>" + trans.sp.all.less + "</option></select>"; menu += "<input type=text size=5 id=filterPopValue value='" + user_data.command.filterMinPopulation + "'>"; menu += "<input type=button id=filterPop value='" + trans.sp.troopOverview.filterPopulation + "' title='" + trans.sp.troopOverview.filterPopulationTooltip + "'> "; menu += "</th><th nowrap width='1%'>"; menu += "<input type=text size=5 id=filterWalkingTimeValue>"; menu += "<input type=button id=filterWalkingTime value='" + trans.sp.troopOverview.filterWalkingTime + "' title='" + trans.sp.troopOverview.filterWalkingTimeTooltip + "'> "; menu += "</th><th width='95%'>"; menu += "<input type=button id=snobFilter value='" + trans.sp.troopOverview.filterNoble + "' title='" + trans.sp.troopOverview.filterNobleTooltip + "'> "; menu += "<input type=button id=attackFilter value='" + trans.sp.troopOverview.filterUnderAttack + "' title='" + trans.sp.troopOverview.filterUnderAttackTooltip + "'> "; menu += "</th><th width='1%'>"; menu += "<input type=button id=calculateStack value='" + trans.sp.troopOverview.calcStack + "' title='" + trans.sp.troopOverview.calcStackTooltip + "'>"; menu += "</th>"; menu += "</tr></table>"; // second row menu += "<table><tr><th width='1%' nowrap>"; menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": "; menu += "</th><th width='1%' nowrap>"; menu += "<input type=text size=12 id=defFilterTextValue value=''>"; menu += "<input type=button id=defFilterText value='" + trans.sp.commands.freeTextFilter + "'>"; menu += "</th><th width='97%' nowrap>"; menu += "<input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>"; menu += "</th>"; if (location.href.indexOf('type=there') > -1) { menu += "<th width='1%'><input type=button id=defRestack value='" + trans.sp.troopOverview.restack + "'></th>"; } menu += "<th nowrap width='1%' style='padding-right: 8px; padding-top: 3px;'>"; menu += "<input type=checkbox id=sortIt title='" + trans.sp.troopOverview.sortTooltip + "'" + (user_data.command.filterAutoSort ? " checked" : "") + "> " + trans.sp.troopOverview.sort; menu += "</th></tr>"; menu += "</table>"; // Sangu filter menu var sanguMenu = menu; // Overview table menu menu = "<tr id=units_table_header>"; menu += "<th>" + trans.sp.troopOverview.village + "</th>"; menu += "<th>" + trans.sp.troopOverview.nightBonus + "</th>"; $.each(world_data.units, function (i, v) { 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>"; }); if (world_config.hasMilitia) { menu += "<th><img src='/graphic/unit/unit_militia.png' title='" + trans.tw.units.militia + "' alt='' id=militia /></th>"; } menu += "<th>" + trans.sp.troopOverview.commandTitle + "</th>"; target = getVillageFromCoords(spTargetVillageCookie()); menu += "<th nowrap>" + trans.sp.all.targetEx + " <input type=text id=targetVillage name=targetVillage size=8 value='" + (target.isValid ? target.coord : "") + "'>" + "<input type=button class='btn' id=targetVillageButton value='" + trans.sp.troopOverview.setTargetVillageButton + "'></th>"; menu += "</tr>"; // function to replace the village rows tableHandler.init("units_table", { rowReplacer: function (row) { //q($(row).html()); var mod = "row_a"; var newRow = ""; var finalRow = ""; var addThisRow = true; var cells = $("td:gt(0)", row); var units = {}; var villageCell = $("td:first", row); var villageId = $("span.quickedit-vn", villageCell).attr("data-id"); cells.each(function (index, element) { if (doFilter && index - 1 == unitIndex && parseInt(this.innerHTML, 10) < unitAmount) { //q("index:" + index + ' == '+ unitIndex + " : " + row.html() + ' * 1 < ' + unitAmount); addThisRow = false; return false; } else if (index == rowSize) { //q(index + "==" + rowSize); newRow += "<td>"; newRow += "<img src='/graphic/dots/red.png' title='" + trans.sp.troopOverview.removeVillage + "' style='margin-bottom: 2px' /> "; //newRow += "<img src='https://www.tribalwars.vodka/graphic/delete_small.png' style='margin-bottom: 3px; position: relative' title='" + trans.sp.troopOverview.removeVillage + "' /> "; newRow += "<a href='" + $("a", element).attr('href').replace("mode=units", "") + "&sanguX=0&sanguY=0' class='attackLinks'>"; newRow += "<img src='/graphic/command/attack.png' title='" + trans.sp.troopOverview.toThePlace + "' style='margin-bottom: 1px' />"; // Works only with leftclick onclick='this.src=\"/graphic/command/return.png\";' newRow += "</a>"; newRow += "</td>"; } else { //q("units:" + world_data.units[index - 1]); var cellDisplay = this.innerHTML; if (cellDisplay === "0") { cellDisplay = " "; } else if (cellDisplay.indexOf('="has_tooltip"') > -1) { cellDisplay = cellDisplay.replace('="has_tooltip"', '="has_tooltip" title="'+trans.sp.troopOverview.cheapNobles+'"'); } newRow += "<td>" + cellDisplay + "</td>"; if (index > 0) { units[world_data.units[index - 1]] = parseInt(element.innerHTML, 10); } // innerHTML can contain a + sign for the nobles: "+" indicates nobles can be rebuild cheaply // The snobs are not important here } }); if (addThisRow) { var villageType = calcTroops(units); if (doFilter) { mod = villageCounter % 2 == 0 ? "row_a" : "row_b"; } else { mod = !villageType.isDef ? "row_a" : "row_b"; } var coord = getVillageFromCoords(villageCell.text()); //finalRow += "<tbody>"; finalRow += "<tr arrival='0' data-coord-x='" + coord.x + "' data-coord-y='" + coord.y + "' " + " class='row_marker " + mod + (game_data.village.id == villageId ? " selected" : "") + "'>"; finalRow += "<td>" + villageCell.html() + "</td>"; finalRow += newRow; finalRow += "<td></td></tr>"; //finalRow += "</tbody>"; villageCounter++; return finalRow; } return ""; } }); var newTable = tableHandler.getReplacedVillageRows(); $("#units_table") .html("<table width='100%' class='vis' id='units_table' target='false'>" + menu + newTable + "</table>") .before(sanguMenu); // Tooltips $("#defReverseFilter").change( function () { var isChecked = $(this).is(":checked"); var defTrans = trans.sp.troopOverview; $("#defFilterContinent").attr("title", isChecked ? defTrans.continentFilterTooltip : defTrans.continentFilterTooltipReverse); $("#defFilterText").attr("title", defTrans.freeTextFilterTooltip.replace("{filterType}", isChecked ? defTrans.freeTextFilterTooltipFilterTypeWith : defTrans.freeTextFilterTooltipFilterTypeWithout)); }); $("#defReverseFilter").change(); // Initial focus on target inputbox $('#targetVillage').click(function () { $(this).focus().select(); }); // "Attacks per page" -> change to # villages in the list var pageSize = $("input[name='page_size']"); var villageAmountCell = $("#units_table tr:first th:first"); //assert(villageAmountCell.length === 1, "village cell Dorp (xxx) niet gevonden"); villageAmountCell.text(villageAmountCell.text() + " (0)"); function setVillageCount(amount) { pageSize.val(amount); villageAmountCell.text(villageAmountCell.text().replace(/\d+/, amount)); } pageSize.parent().prev().text(trans.sp.overviews.totalVillages); setVillageCount(villageCounter); // Recalculate arrival times as the target village changes $("#targetVillageButton").click(function () { trackClickEvent("TargetVillageSet"); var targetMatch = getVillageFromCoords($('#targetVillage').val(), true); $("#units_table").attr("target", targetMatch.isValid); if (!targetMatch.isValid) { spTargetVillageCookie(""); alert(trans.sp.troopOverview.setTargetVillageButtonAlert); $("#targetVillage").focus(); } else { $(".attackLinks", tableHandler.overviewTable).each(function() { // add target coordinates to attack image href which are read in place var hrefWithVillageCoords = $(this).attr("href"); hrefWithVillageCoords = hrefWithVillageCoords.replace(/sanguX=(\d+)&sanguY=(\d+)/, "sanguX="+targetMatch.x+"&sanguY="+targetMatch.y); $(this).attr("href", hrefWithVillageCoords); }); spTargetVillageCookie(targetMatch.coord); $("#units_table").find(overviewMenuRowFilter).each(function () { var unitRow = $(this), dist = getDistance(targetMatch.x, unitRow.attr("data-coord-x"), targetMatch.y, unitRow.attr("data-coord-y"), currentPageSpeed); $("td:last", unitRow).html(dist.html); $(this).attr("arrival", dist.travelTime); if (dist.isNightBonus) { $("td:eq(1)", unitRow).css("background-color", user_data.colors.error); } else { $("td:eq(1)", unitRow).css("background-color", ''); } }); if ($("#sortIt").is(":checked")) { $("#units_table").find(overviewMenuRowFilter).sortElements(function (a, b) { return parseInt($(a).attr("arrival"), 10) > parseInt($(b).attr("arrival"), 10) ? 1 : -1; }); } } }); // sort can be set with the querystring if (sort) { $("#targetVillageButton").click(); } // delete a table row $("#units_table").mouseup(function (e) { if (e.target.nodeName === 'IMG') { if (e.target.title == trans.sp.troopOverview.removeVillage) { setVillageCount(parseInt(pageSize.val(), 10) - 1); $(e.target).parent().parent().remove(); } } }); // remove row or add border to command cell when middle mouse click (open in new tab) $(tableHandler.overviewTable).on("mousedown",".attackLinks", function(e) { if (e.which == 2) { var cell = $(e.target).parent().parent(); if (user_data.command.middleMouseClickDeletesRow2) { cell.parent().remove(); } else { cell.css("border", (parseInt(cell.css("border-width").substr(0, 1), 10) + 1) + "px red solid"); } } }); // Change active speed by clicking on a unit icon // ATTN: border style duplicated in trans.troopOverview.help $('#' + currentPageSpeed).parent().css("border", "2px green dotted"); $('#' + spSpeedCookie()).parent().css("border", "3px red solid"); $("#units_table_header").click(function (e) { if (e.target.nodeName === 'IMG' && e.target.id !== "militia") { currentPageSpeed = e.target.id; $("img", this).parent().css("border", "0px"); $('#' + currentPageSpeed).parent().css("border", "2px green dotted"); $('#' + spSpeedCookie()).parent().css("border", "3px red solid"); $("#targetVillageButton").click(); } }); $("#units_table_header").dblclick(function (e) { if (e.target.nodeName === 'IMG' && e.target.id !== "militia") { currentPageSpeed = e.target.id; spSpeedCookie(e.target.id); $("img", this).parent().css("border", "0px"); $('#' + currentPageSpeed).parent().css("border", "2px green dotted"); $('#' + spSpeedCookie()).parent().css("border", "3px red solid"); $("#targetVillageButton").click(); } }); function filterVillageRows(filterStrategy, options) { // return true to hidethe row; false keep row visible (without reverse filter checkbox) options = options || { allowFilter: true }; var reverseFilter = options.allowFilter && $("#defReverseFilter").is(":checked"), goners = $(), villageCounter = 0; $("#units_table").find(overviewMenuRowFilter).each(function () { var self = $(this); if (!reverseFilter != !filterStrategy(self)) { goners = goners.add(self); $("input:eq(1)", self).val(""); } else { villageCounter++; } }); goners.remove(); // Show totals setVillageCount(villageCounter); } // CONTINENT FILTER $("#defFilterContinent").click(function () { trackClickEvent("FilterContinent"); var continent = parseInt($("#defFilterContinentText").val(), 10); if (!isNaN(continent)) { filterVillageRows(function (row) { var village = getVillageFromCoords(row.find("td:first").text()); if (!village.isValid ) { return true; } return village.continent() != continent; }); } }); // TEXT FILTER $("#defFilterText").click(function () { trackClickEvent("FilterText"); var compareTo = $("#defFilterTextValue").val().toLowerCase(); if (compareTo.length > 0) { filterVillageRows(function (row) { return row.text().toLowerCase().indexOf(compareTo) == -1; }); } }); // WALKINGTIME FILTER $("#filterWalkingTime").click(function () { var minWalkingTime = parseInt($("#filterWalkingTimeValue").val(), 10) * 60; if (!isNaN(minWalkingTime)) { trackClickEvent("WalkingTime"); filterVillageRows( function (row) { return parseInt(row.attr("arrival"), 10) < minWalkingTime; }, { allowFilter: false } ); } else { alert(trans.sp.troopOverview.filterWalkingTimeTooltip); } }); // Filter rows with less than x axemen (or another unit) $("#filterAxe").click(function () { trackClickEvent("FilterUnitAmount"); var villageCounter = 0; var goners = $(); var minAxeValue = parseInt($("#filterAxeValue").val(), 10); var unit = parseInt($('#filterAxeType').val(), 10); $("#units_table").find(overviewMenuRowFilter).each(function () { var val = $("td:eq(" + (unit + 2) + ")", this).html(); if (val == ' ' || parseInt(val, 10) < minAxeValue) { goners = goners.add($(this)); $("input:first", $(this)).val(""); } else villageCounter++; }); goners.remove(); setVillageCount(villageCounter); }); // change by default selected unit the filter will be active for $("#filterAxeType").change(function () { var unit = world_data.units[$(this).val()]; if (typeof user_data.command.filterMin[unit] !== 'undefined') { $("#filterAxeValue").val(user_data.command.filterMin[unit]); } else { $("#filterAxeValue").val(user_data.command.filterMinOther); } }); // Filter rows without snobs/nobles $("#snobFilter").click(function () { trackClickEvent("FilterSnob"); var villageCounter = 0; var goners = $(); $("#units_table").find(overviewMenuRowFilter).each(function () { if ($.trim($("td:eq(" + (world_data.unitsPositionSize.length + 1) + ")", this).text()) === '') { goners = goners.add($(this)); $("input:first", $(this)).val(""); } else villageCounter++; }); goners.remove(); setVillageCount(villageCounter); }); // hide rows not under attack $("#attackFilter").click(function () { trackClickEvent("FilterUnderAttack"); var villageCounter = 0; var goners = $(); $("#units_table").find(overviewMenuRowFilter).each(function () { //q("'" + $(this).html() + "'"); //q("---------------------------------------------------"); if ($('td:first:not(:has(img[title=\'' + trans.tw.command.attack + '\']))', this).size() != 0) { goners = goners.add($(this)); $("input:first", $(this)).val(""); } else { villageCounter++; } }); goners.remove(); setVillageCount(villageCounter); }); // filter rows with less then x population $("#filterPop").click(function () { trackClickEvent("FilterFarm"); $("#calculateStack").click(); var villageCounter = 0; var goners = $(); var min = parseInt($("#filterPopValue").val(), 10); var reverseFilter = $("#filterPopValueType").val() == "-1"; $("#units_table").find(overviewMenuRowFilter).each(function () { var line = $(this); $("td:eq(1)", this).each(function () { var amount = parseInt($(this).text().replace('.', ''), 10); if ((!reverseFilter && amount < min) || (reverseFilter && amount > min)) { goners = goners.add(line); $("input:first", line).val(""); } else villageCounter++; }); }); goners.remove(); setVillageCount(villageCounter); }); // One time help display (function() { if ($("#targetVillageButton").length === 0) { // group without villages return; } var position = $("#targetVillageButton").position(), options = { left: position.left - 300, top: position.top + 35 }, content = { title: trans.sp.troopOverview.helpTitle, body: trans.sp.troopOverview.help.replace("{unitIcon}", "<img src='graphic/unit/unit_ram.png'>, <img src='graphic/unit/unit_spear.png'>, ...") }; createFixedTooltip("troopOverviewTooltip", content, options); }()); // Calculate stack $("#calculateStack").click(function () { trackClickEvent("CalculateStack"); if (!this.disabled) { this.disabled = true; $("#units_table").find(overviewMenuRowFilter).each(function () { var total = 0; $("td:gt(1)", this).each(function (i) { if (!($.trim(this.innerHTML) == '' || this.innerHTML == ' ' || i >= world_data.unitsPositionSize.length)) { total += this.innerHTML * world_data.unitsPositionSize[i]; } }); $("td:eq(1)", this).text(formatNumber(total)).css("background-color", getStackColor(total)); }); } }); // Calculate Restack BB codes if (location.href.indexOf('type=there') > -1) { $("#defRestack").click(function () { trackClickEvent("BBCodeOutput"); $("#calculateStack").click(); var request = ""; $("#units_table").find(overviewMenuRowFilter).each(function () { var total = parseInt($("td:eq(1)", $(this)).text().replace(/\./, ''), 10); if (user_data.restack.to - total > user_data.restack.requiredDifference) { var villageDesc = $(this).find("td:first span[data-text]").text(), villageCoord = getVillageFromCoords(villageDesc); request += "[village]" + villageCoord.coord + "[/village] (" + parseInt((user_data.restack.to - total) / 1000, 10) + "k)\n"; } }); if ($("#textsArea").size() == 0) { $(this).parent().parent().parent().append("<tr><td id=textsArea colspan=5></td></tr>"); } else { $("#textsArea").html(""); } var title = trans.sp.troopOverview.restackTitle .replace("{to}", parseInt(user_data.restack.to / 1000, 10)) .replace("{requiredDiff}", parseInt(user_data.restack.requiredDifference / 1000, 10)); $("#textsArea").append(title + "<br><textarea cols=35 rows=10 id=defRestackArea>" + request + "</textarea>"); $("#textsArea").append("<br><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>"); $("#closeTextsArea").click(function() { $("#textsArea").parent().remove(); }); }); } } catch (e) { handleException(e, "overview-thereownhome"); } //console.timeEnd("overview-thereownhome"); }()); } // BUILDINGS OVERVIEW else if (location.href.indexOf('mode=buildings') > -1) { (function() { //console.time("overview-buildings"); try { // Highlight everything not conform overviewTable = $("#buildings_table"); tableHandler.init("buildings_table"); var menu = "<table class='vis' width='100%'>"; menu += "<tr><th>"; menu += "<input type=checkbox id=buildingOpti> " + trans.sp.buildOverview.optimistic + " "; menu += "<input type=button id=buildingHighlight value='" + trans.sp.buildOverview.mark + "'>"; menu += "<input type=button id=buildingFilter value='" + trans.sp.buildOverview.filter + "'>"; menu += "</th></tr></table>"; overviewTable.before(menu); function filterBuildings(cellAction, hideRows) { var buildings = []; overviewTable.find("tr:first img").each(function (i, v) { buildings[i] = this.src.substr(this.src.lastIndexOf('/') + 1); buildings[i] = buildings[i].substr(0, buildings[i].indexOf('.')); }); var goners = $(); var opti = $("#buildingOpti").is(":checked"); overviewTable.find("tr:gt(0)").each(function () { var isOk = true; $(this).find("td:gt(3)").each(function (i, v) { var range = user_data.buildings[buildings[i]]; if (range != undefined) { var text = parseInt($(this).text(), 10); if (text < range[0]) { $(this).css("background-color", user_data.colors.error); isOk = false; } else if (text > range[1] && !opti) { $(this).css("background-color", user_data.colors.good); isOk = false; } else $(this).css("background-color", ""); } }); if (hideRows && isOk) { goners = goners.add($(this)); $("input:first", $(this)).val(""); } }); goners.remove(); } $("#buildingHighlight").click(function () { trackClickEvent("TableHighlight"); filterBuildings(function (cell, isOk) { cell.css("background-color", isOk ? "" : user_data.colors.neutral); }, false); }); $("#buildingFilter").click(function () { trackClickEvent("TableRemove"); filterBuildings(function (cell, isOk) { cell.css("background-color", isOk ? "" : user_data.colors.neutral); }, true); }); } catch (e) { handleException(e, "overview-buildings"); } //console.timeEnd("overview-buildings"); }()); } // TECHS OVERVIEW // SMEDERIJ OVERVIEW // SMITHY OVERVIEW else if (location.href.indexOf('mode=tech') > -1) { (function() { //console.time("overview-techs"); try { overviewTable = $("#techs_table"); tableHandler.init("techs_table"); // Highlight everything not conform usersettings if (world_config.smithyLevels) { var menu = "<table class='vis' width='100%'>"; menu += "<tr><th>"; menu += "<select id='groupType'>"; $.each(user_data.smithy, function (i, v) { menu += "<option value=" + i + ">" + v[0] + "</option>"; }); menu += "</select>"; menu += "<input type=checkbox id=buildingOpti> " + trans.sp.smithOverview.optimistic + " "; menu += "<input type=button id=smithyHighlight value='" + trans.sp.smithOverview.mark + "'>"; menu += "<input type=button id=smithyFilter value='" + trans.sp.smithOverview.filter + "'>"; menu += "</th></tr></table>"; $("#techs_table").before(menu); function filterTechs(cellAction, hideRows) { var goners = $(); var opti = $("#buildingOpti").is(":checked"); var def = user_data.smithy[$("#groupType").val()][1]; $("#techs_table").find("tr:gt(0)").each(function () { var isOk = true; $(this).find("td:gt(2)").each(function (i, v) { var range = def[world_data.units[i]]; if (i < world_data.units.length && range != undefined) { var text = parseInt($(this).text(), 10); if (text == '') { text = 0; } if (text < range[0]) { $(this).css("background-color", user_data.colors.error); isOk = false; } else if (text > range[1] && !opti) { $(this).css("background-color", user_data.colors.good); isOk = false; } else { $(this).css("background-color", ""); } } }); if (hideRows && isOk) { goners = goners.add($(this)); $("input:first", $(this)).val(""); } }); goners.remove(); } $("#smithyHighlight").click(function () { trackClickEvent("TableHighlight"); filterTechs(function (cell, isOk) { cell.css("background-color", isOk ? "" : user_data.colors.neutral); }, false); }); $("#smithyFilter").click(function () { trackClickEvent("TableRemove"); filterTechs(function (cell, isOk) { cell.css("background-color", isOk ? "" : user_data.colors.neutral); }, true); }); } } catch (e) { handleException(e, "overview-techs"); } //console.timeEnd("overview-techs"); }()); } // GROUPS OVERVIEW else if (location.href.indexOf('mode=groups') > -1) { (function() { //console.time("overview-groups"); try { overviewTable = $("#group_assign_table"); tableHandler.init("group_assign_table", { hasBottomTotalRow: true }); // TODO: edit groups: make div floatable and remember position var menu = ""; menu += "<table class=vis width='100%'><tr><th>"; menu += trans.sp.defOverview.village + " <input type=text size=5 id=defFilterDistVillage value=''>"; menu += "<select id=defFilterDistType>"; menu += "<option value=1 selected>" + trans.sp.all.closer + "</option><option value=-1>" + trans.sp.all.further + "</option></select>"; menu += " F <input type=text size=3 id=defFilterDistFields value=" + user_data.restack.fieldsDistanceFilterDefault + ">"; menu += "<input type=button id=defFilterDist value='" + trans.sp.defOverview.distFilter + "' title='" + trans.sp.defOverview.distFilterTooltip + "'>"; menu += " | "; menu += "<input type=button id=attackFilter value='" + trans.sp.defOverview.filterUnderAttack + "'>"; menu += "<br>"; menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": "; menu += " <input type=text size=12 id=defFilterTextValue value=''>"; menu += "<input type=button id=defFilterText value='" + trans.sp.groups.villageFilter + "'>"; menu += " <input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>"; menu += " <input type=textbox size=3 id=defFilterAmountText maxlength=2><input type=button id=defFilterAmount value='" + trans.sp.groups.amountFilter + "'>"; menu += " <input type=textbox size=4 id=defFilterPointsText maxlength=5><input type=button id=defFilterPoints value='" + trans.sp.groups.pointsFilter + "'>"; menu += " <input type=textbox size=5 id=defFilterFarmText maxlength=6><input type=button id=defFilterFarm value='" + trans.tw.all.farm + "'>"; menu += " <input type=text size=12 id=defFilterGroupValue value=''>"; menu += "<input type=button id=defFilterGroup value='" + trans.sp.groups.groupNameFilter + "'>"; menu += "</th></tr></table>"; var selectAllRow = $("#group_assign_table tr:last"); $("#group_assign_table").before(menu).after("<table class=vis width='100%'><tr><th><input type=checkbox id=selectAllVisible> " + selectAllRow.text() + "</th></tr></table>"); selectAllRow.remove(); // Select all checkbox behavior $("#selectAllVisible").change(function () { var isChecked = $(this).is(":checked"); $("#group_assign_table input:checked").prop("checked", false); if (isChecked) { $("#group_assign_table input[type='checkbox']").not(":hidden").prop("checked", true); } //$("#group_assign_table input:hidden").prop("checked", false); //$("#group_assign_table input:visible").prop("checked", isChecked); }); // Change tooltips when clicking the reverse filter checkbox $("#defReverseFilter").change(function () { var isChecked = $(this).is(":checked"); var defTrans = trans.sp.groups; $("#defFilterText").attr("title", isChecked ? defTrans.villageFilterTitle : defTrans.villageFilterTitleRev); $("#defFilterContinent").attr("title", isChecked ? trans.sp.commands.continentFilterTooltip : trans.sp.commands.continentFilterTooltipReverse); $("#defFilterAmount").attr("title", isChecked ? defTrans.amountFilterTitle : defTrans.amountFilterTitleRev); $("#defFilterPoints").attr("title", isChecked ? defTrans.pointsFilterTitle : defTrans.pointsFilterTitleRev); $("#defFilterFarm").attr("title", isChecked ? defTrans.farmFilterTitle : defTrans.farmFilterTitleRev); $("#defFilterGroup").attr("title", isChecked ? defTrans.groupNameFilterTitle : defTrans.groupNameFilterTitleRev); }); $("#defReverseFilter").change(); /** * Perform a filter on the groups table rows * @param {function} filterStrategy jQuery object with the row is the first parameter * @param {boolean} reverseFilter * @param {function} [keepRowStrategy] * @param {*} [tag] passed as second param to filterStrategy and keepRowStrategy */ function filterGroupRows(filterStrategy, reverseFilter, keepRowStrategy, tag) { if (typeof reverseFilter === "undefined") { reverseFilter = !$("#defReverseFilter").is(":checked"); } var goners = $(); var totalVisible = 0; $("#group_assign_table tr:gt(0)").each(function () { var row = $(this); if (row.is(":visible")) { if (!reverseFilter != !filterStrategy(row, tag)) { goners = goners.add(row); //$("input:eq(1)", row).val(""); } else { totalVisible++; if (keepRowStrategy != null) { keepRowStrategy(row, tag); } } } }); goners.remove(); var firstHeaderCell = $("#group_assign_table th:first"); var firstHeaderCellHtml = firstHeaderCell.html(); firstHeaderCell.html(firstHeaderCellHtml.substr(0, firstHeaderCellHtml.lastIndexOf(" ")) + " (" + totalVisible + ")"); } // Filter on distance to given village $("#defFilterDist").click(function () { var targetVillage = getVillageFromCoords($("#defFilterDistVillage").val(), true); if (!targetVillage.isValid) { alert(trans.sp.defOverview.distanceToVillageNoneEntered); return; } trackClickEvent("FilterDistance"); var reverseFilter = !($("#defFilterDistType").val() != "-1"); var maxDistance = parseInt($("#defFilterDistFields").val(), 10); var isAlreadyVisible = $("#filterContext").size() == 1; var distanceHeader = trans.sp.defOverview.distanceToVillage.replace( "{0}", "<a href='" + getUrlString("&screen=map&x=" + targetVillage.x + "&y=" + targetVillage.y + "'>") + targetVillage.coord + "</a>"); if (isAlreadyVisible) { $("#filterContext").html(distanceHeader); } else { $("#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>"); $(".sortDistance").click(function () { if ($(this).attr("direction") == "up") { $("#group_assign_table").find("tr:gt(0)").filter(":visible").sortElements(function (a, b) { return parseInt($(a).attr("fieldAmount"), 10) > parseInt($(b).attr("fieldAmount"), 10) ? 1 : -1; }); } else { $("#group_assign_table").find("tr:gt(0)").filter(":visible").sortElements(function (a, b) { return parseInt($(a).attr("fieldAmount"), 10) < parseInt($(b).attr("fieldAmount"), 10) ? 1 : -1; }); } }); } filterGroupRows( function (row, tag) { var compareVillage = getVillageFromCoords(row.find("td:first").text()); tag.distance = getDistance(targetVillage.x, compareVillage.x, targetVillage.y, compareVillage.y, 'ram').fields; return tag.distance > maxDistance; }, reverseFilter, function (mainRow, tag) { mainRow.attr("fieldAmount", tag.distance); if (!isAlreadyVisible) { mainRow.find("td:first").after("<td><b>" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + "</b></td>"); } else { mainRow.find("td:eq(1)").html("<b>" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + "</b>"); } }, { distance: 0 }); }); // Filter on incoming attacks $("#attackFilter").click(function () { trackClickEvent("FilterUnderAttack"); filterGroupRows(function (row) { return $('td:first:not(:has(img[title=\'' + trans.tw.command.attack + '\']))', row).size() == 0; }); }); // filter on village name $("#defFilterText").click(function () { trackClickEvent("FilterText"); var compareTo = $("#defFilterTextValue").val().toLowerCase(); if (compareTo.length > 0) { filterGroupRows(function (row) { return row.find("td:first").text().toLowerCase().indexOf(compareTo) != -1; }); } }); // filter on group names $("#defFilterGroup").click(function () { trackClickEvent("FilterGroupName"); var compareTo = $("#defFilterGroupValue").val().toLowerCase(); if (compareTo.length > 0) { filterGroupRows(function (row) { return row.find("td:eq(4)").text().toLowerCase().indexOf(compareTo) != -1; }); } }); $("#defFilterContinent").click(function () { trackClickEvent("FilterContinent"); var compareTo = parseInt($("#defFilterContinentText").val(), 10); if (compareTo >= 0) { compareTo = compareTo.toString(); filterGroupRows(function (row) { var villageContinent = $.trim(row.find("td:first").text()), continentStart = villageContinent.lastIndexOf(trans.tw.all.continentPrefix); return villageContinent.substr(continentStart + 1) === compareTo; }); } }); // filter on # groups $("#defFilterAmount").click(function (){ trackClickEvent("FilterGroupCount"); var compareTo = parseInt($("#defFilterAmountText").val(), 10); if (compareTo >= 0) { if (!$("#defReverseFilter").is(":checked")) { filterGroupRows( function (row) { return parseInt(row.find("td:eq(1)").text(), 10) > compareTo; }, false); } else { filterGroupRows( function (row) { return parseInt(row.find("td:eq(1)").text(), 10) < compareTo; }, false); } } }); $("#defFilterPoints").click(function () { trackClickEvent("FilterPoints"); var compareTo = parseInt($("#defFilterPointsText").val(), 10); if (compareTo >= 0) { filterGroupRows(function (row) { return parseInt(row.find("td:eq(2)").text().replace(".", ""), 10) < compareTo; }); } }); $("#defFilterFarm").click(function () { trackClickEvent("FilterFarm"); var compareTo = parseInt($("#defFilterFarmText").val(), 10); if (compareTo >= 0) { filterGroupRows(function (row) { var farmValue = row.find("td:eq(3)").text(); farmValue = parseInt(farmValue.substr(0, farmValue.indexOf("/")), 10); return farmValue < compareTo; }); } }); } catch (e) { handleException(e, "overview-groups"); } //console.timeEnd("overview-groups"); }()); } // SUPPORT OVERVIEW else if (location.href.indexOf('type=support_detail') > -1 || location.href.indexOf('type=away_detail') > -1) { (function() { //console.time("overview-supportdetail"); try { overviewTable = $("#units_table"); tableHandler.init("units_table", { hasBottomTotalRow: true }); /** * true: we're on the support_detail page. false: away_detail page * @type {boolean} */ var isSupport = location.href.indexOf('type=support_detail') > -1; /** * Sets the correct rowcount in the first header cell */ function setTotalCount() { $("th:first", overviewTable).text( trans.sp.defOverview.totalVillages.replace( "{0}", $("tr.units_away", overviewTable).size())); } var menu = "<table class='vis' width='100%'>"; menu += "<tr><th width='1%' nowrap>"; menu += "<input type=button id=defTotals value='" + trans.sp.defOverview.stackButton + "' title='" + trans.sp.defOverview.stackTooltip + "'>"; menu += "<input type=button id=defHideEmpty value='" + trans.sp.defOverview.filterNoSupport + "' title='" + trans.sp.defOverview.filterNoSupportTooltip + "'> "; menu += "</th><th width='96%' nowrap>"; menu += "<input type=button id=attackFilter value='" + trans.sp.defOverview.filterUnderAttack + "'>"; if (!isSupport) { menu += " <input type=button id=defFilterBarbarian value='" + trans.sp.defOverview.barbarianFilter + "' title='" + trans.sp.defOverview.barbarianFilterTooltip + "'>"; } else { menu += "</th><th width='1%' nowrap>"; menu += "<input type=text size=8 id=defFilterTotalPopValue value='" + user_data.restack.defaultPopulationFilterAmount + "'>"; menu += "<select id=defFilterTotalPopComparer>"; menu += "<option value=-1>" + trans.sp.all.less + "</option><option value=1 selected>" + trans.sp.all.more + "</option></select>"; menu += "<input type=button id=defFilterTotalPop value='" + trans.sp.defOverview.stackFilter + "' title='" + trans.sp.defOverview.stackFilterTooltip + "'>"; menu += "</th><th width='1%' nowrap>"; menu += trans.sp.defOverview.village + " <input type=text size=5 id=defFilterDistVillage value=''>"; menu += "<select id=defFilterDistType>"; menu += "<option value=1 selected>" + trans.sp.all.closer + "</option><option value=-1>" + trans.sp.all.further + "</option></select>"; // TODO: untranslated F(ields) menu += " F <input type=text size=3 id=defFilterDistanceValue value=" + user_data.restack.fieldsDistanceFilterDefault + ">"; menu += "<input type=button id=defFilterDist value='" + trans.sp.defOverview.distFilter + "' title='" + trans.sp.defOverview.distFilterTooltip + "'>"; menu += "</th><th width='1%' nowrap>"; 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 + "'>"; //menu += "</th></tr></table>"; } menu += "</th></tr></table>"; menu += "<table class='vis' width='100%'><tr><th width='1%' nowrap>"; menu += isSupport ? trans.sp.defOverview.extraFiltersSupport : trans.sp.defOverview.extraFiltersDefense; menu += "</th><th width='1%' nowrap>"; menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.defOverview.extraFiltersReverse + "'" + (user_data.restack.filterReverse ? " checked" : "") + "> " + trans.sp.defOverview.extraFiltersInfo; menu += "</th><th width='1%' nowrap>"; menu += "<input type=text size=3 id=defFilterDistanceValue value=" + user_data.restack.fieldsDistanceFilterDefault + "> <input type=button id=defFilterDistance value='" + trans.sp.defOverview.distFilter2 + "'>"; menu += "</th><th width='1%' nowrap>"; menu += " <span style='background-color: #ecd19a; border: 1px solid black' id='unitFilterBox'>"; menu += " <img src='graphic/unit/unit_snob.png' id=filtersnob> <img src='graphic/unit/unit_spy.png' id=filterspy>"; menu += " <img src='graphic/buildings/barracks.png' id=filterAttack> <img src='graphic/unit/def.png' id=filterDefense> <img id=filterSupport src='graphic/command/support.png'> "; menu += "</span> "; menu += "</th><th width='96%' nowrap>"; menu += "<input type=text size=12 id=defFilterTextValue value=''>"; menu += "<input type=button id=defFilterText value='" + trans.sp.defOverview.freeTextFilter + "'>"; menu += "</th></tr></table>"; overviewTable.before(menu); $("#defReverseFilter").change(function () { var isChecked = $(this).is(":checked"); var defTrans = trans.sp.defOverview; $("#unitFilterBox").find("img:eq(0)").attr("title", isChecked ? defTrans.nobleFilter : defTrans.nobleFilterRev); $("#unitFilterBox").find("img:eq(1)").attr("title", isChecked ? defTrans.spyFilter : defTrans.spyFilterRev); $("#unitFilterBox").find("img:eq(2)").attr("title", isChecked ? defTrans.attackFilter : defTrans.attackFilterRev); $("#unitFilterBox").find("img:eq(3)").attr("title", isChecked ? defTrans.supportFilter : defTrans.supportFilterRev); $("#unitFilterBox").find("img:eq(4)").attr("title", (isSupport ? defTrans.otherPlayerFilterFrom : defTrans.otherPlayerFilterTo).replace("{action}", isChecked ? defTrans.otherPlayerFilterShow : defTrans.otherPlayerFilterHide)); $("#defFilterText").attr("title", defTrans.freeTextFilterTooltip.replace("{villageType}", isSupport ? defTrans.filterTooltipVillageTypeSupporting : defTrans.filterTooltipVillageTypeSupported).replace("{filterType}", isChecked ? defTrans.freeTextFilterTooltipFilterTypeWith : defTrans.freeTextFilterTooltipFilterTypeWithout)); $("#defFilterDistance").attr("title", defTrans.distanceFilterTooltip.replace("{villageType}", isSupport ? defTrans.filterTooltipVillageTypeSupporting : defTrans.filterTooltipVillageTypeSupported).replace("{filterType}", !isChecked ? defTrans.distanceFilterTooltipFilterTypeCloser : defTrans.distanceFilterTooltipFilterTypeFurther)); }); $("#defReverseFilter").change(); // This file contains the filters on the FIRST row of the menu // UNDER ATTACK FILTER $("#attackFilter").click(function () { trackClickEvent("FilterAttack"); var reverseFilter = true; // never reverse this filter! var filterStrategy = function (row) { return $('td:first:not(:has(img[title=\'' + trans.tw.command.attack + '\']))', row).size() == 0; }; var lastRow = $("tr:last", overviewTable).get(0); var goners = $(); $("tr.units_away", overviewTable).each(function () { var self = $(this); if (!reverseFilter != !filterStrategy(self)) { goners = goners.add(self); var nextRow = self.next(); while (!nextRow.hasClass("units_away") && nextRow.get(0) !== lastRow) { goners = goners.add(nextRow); nextRow = nextRow.next(); } } }); goners.remove(); setTotalCount(); // this is already done in the code above :) //$("#defHideEmpty").click(); if (user_data.restack.calculateDefTotalsAfterFilter && !$("#defTotals").is(":disabled")) { $("#defTotals").click(); } }); /** * Performs a filter on the OWN villages (ie not the villages supporting the OWN villages) * The 'row' parameter are the rows with class grandTotal. These are the rows that get added after (below) all * supporting os rows when the total def is being calculated. * @param {function} filterStrategy return a boolean to filter all rows for the OWN away. first parameter is the (jQuery) row with the OWN village * @param {boolean} reverseFilter reverse the above strategy * @param {function} [survivorRowStrategy] execute on all rows that are not being removed (gets passed the row and optional tag) * @param {*} [tag] this value is passed onto filterStrategy and survivorRowStrategy as the second parameter (row is the first param) */ function filterMainRows(filterStrategy, reverseFilter, survivorRowStrategy, tag) { if (!$("#defTotals").is(":disabled")) { $("#defTotals").click(); } /*var goners = $(); $("tr.grandTotal", overviewTable).each(function () { var self = $(this), prev; if (!reverseFilter != !filterStrategy(self, tag)) { goners = goners.add(self).add(self.next()); prev = self.prev(); while (!prev.hasClass("units_away")) { goners = goners.add(prev); prev = prev.prev(); } goners = goners.add(prev); } else if (survivorRowStrategy != null) { prev = self.prev(); while (!prev.hasClass("units_away")) { prev = prev.prev(); } survivorRowStrategy(prev, tag); } }); goners.remove(); setTotalCount();*/ var lastRow = $("tr:last", overviewTable).get(0); var goners = $(); $("tr.units_away", overviewTable).each(function () { var self = $(this); if (!reverseFilter != !filterStrategy(self, tag)) { goners = goners.add(self); var nextRow = self.next(); while (!nextRow.hasClass("units_away") && nextRow.get(0) !== lastRow) { goners = goners.add(nextRow); nextRow = nextRow.next(); } } else if (survivorRowStrategy != null) { /*prev = self.prev(); while (!prev.hasClass("units_away")) { prev = prev.prev(); }*/ survivorRowStrategy(self, tag); } }); goners.remove(); setTotalCount(); } // filter the OWN villages on less/more population (requires total calculation) $("#defFilterTotalPop").click(function () { trackClickEvent("FilterFarm"); var reverseFilter = $("#defFilterTotalPopComparer").val() != "-1"; var compareTo = parseInt($("#defFilterTotalPopValue").val(), 10); filterMainRows( //q(row.attr("village") + "is:" + row.attr("population")); function (row) { return (parseInt(row.attr("population"), 10) > compareTo); }, reverseFilter); }); // filter the OWN villages on less/more distance to given coordinates (requires total calculation) $("#defFilterDist").click(function () { var targetVillage = getVillageFromCoords($("#defFilterDistVillage").val(), true); if (!targetVillage.isValid) { alert(trans.sp.defOverview.distanceToVillageNoneEntered); return; } trackClickEvent("FilterDistanceToX"); var reverseFilter = !($("#defFilterDistType").val() != "-1"); var maxDistance = parseInt($("#defFilterDistanceValue").val(), 10); // Change text of th cell to 'distance to ' + given village overviewTable.find("th:eq(1)").html( trans.sp.defOverview.distanceToVillage.replace( "{0}", "<a href='" + getUrlString("&screen=map&x=" + targetVillage.x + "&y=" + targetVillage.y + "'>") + targetVillage.coord + "</a>")); filterMainRows( function (row, tag) { var compareVillage = getVillageFromCoords(row.attr("village")); tag.distance = getDistance(targetVillage.x, compareVillage.x, targetVillage.y, compareVillage.y, 'ram').fields; return tag.distance > maxDistance; }, reverseFilter, function (mainRow, tag) { // Adds the distance between OWN village and the user given coordinates mainRow.find("td:eq(1)").html("<b>" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + "</b>"); }, { distance: 0 }); }); // Calculate villages that don't have x population defense // and create BBcodes textarea for it $("#defRestack").click(function () { trackClickEvent("BBCodeOutput"); if (!$("#defTotals").attr("disabled")) { $("#defTotals").click(); } var restackTo = parseInt($("#defRestackTo").val(), 10); var counter = 0; var request = ""; $("tr.grandTotal", overviewTable).each(function () { var self = $(this); var total = parseInt(self.attr('population'), 10); if (restackTo - total > user_data.restack.requiredDifference) { var villageCoords = self.attr("village"); counter++; request += counter + "[village]" + villageCoords + "[/village] (" + parseInt((restackTo - total) / 1000, 10) + trans.sp.defOverview.thousandSuffix + ")\n"; } }); if ($("#textsArea").size() == 0) { $(this).parent().parent().parent().parent().after( "<table class='vis' width='100%'><tr>" + "<td id=textsArea width='50%' valign='top'></td>" + "<td id='extraTextsArea' width='50%' valign='top'>" + trans.sp.defOverview.freeText + "<br><textarea cols=50 rows=9></textarea></td>" + "</tr></table>"); $("#textsArea").parent().after("<tr><td colspan='2'><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea></td></tr>"); } else { $("#textsArea").html(""); } var title = trans.sp.troopOverview.restackTitle .replace("{to}", parseInt(restackTo / 1000, 10)) .replace("{requiredDiff}", parseInt(user_data.restack.requiredDifference / 1000, 10)); $("#textsArea").append(title + "<br><textarea cols=50 rows=10 id=restackArea>" + request + "</textarea>"); $("#closeTextsArea").click(function() { $("#textsArea").parent().parent().remove(); }); }); // Check all villages checkbox replacement $("input.selectAll").replaceWith("<input type=checkbox id=selectAllVisible>"); $("#selectAllVisible").change(function () { var isChecked = $(this).is(":checked"); $("input.village_checkbox:hidden", overviewTable).prop("checked", false); $("input.village_checkbox:visible", overviewTable).prop("checked", isChecked); }); // Hide all OWN rows/villages that don't have any support rows anymore $("#defHideEmpty").click(function () { trackClickEvent("FilterEmpty"); var goners = $(); if ($("#defTotals").is(":disabled")) { $("tr.units_away", overviewTable).each(function () { var mainRow = $(this), nextRow = mainRow.next(); if (nextRow.hasClass("grandTotal")) { goners = goners.add(mainRow).add(nextRow.next()).add(nextRow); } else if (nextRow.hasClass("units_away")) { goners = goners.add(mainRow); } }); } else { $("tr.units_away", overviewTable).each(function () { var mainRow = $(this), nextRow = mainRow.next(); if (nextRow.hasClass("units_away")) { goners = goners.add(mainRow); } }); } goners.remove(); setTotalCount(); }); // Calculate the amount of def in each village // Give sensible background row colors // Add attributes to the grandTotal class rows 'village' (coords) and 'population' // Add attribute 'distance' the distance between OWN and supporting villages, in fields $("#defTotals").click(function () { trackClickEvent("FilterTotalDef"); $(this).attr("disabled", true); var rowColor = 0; var goners = $(); overviewTable.find("tr.units_away").each(function () { var self = $(this); var firstCell = self.find("td:first"); var villageCoord = getVillageFromCoords(firstCell.text().replace(firstCell.find(".quickedit-label").attr("data-text"), "")); // ensure row color swapping for each own village rowColor++; if (rowColor % 2 == 1) { self.removeClass("row_a").addClass("row_b"); } else { self.removeClass("row_b").addClass("row_a"); } // village attribute both to .units_away and .grandTotal rows ;) self.attr("village", villageCoord.coord); var nextRow = self.next(); if (nextRow.hasClass("units_away")) { if (user_data.restack.removeRowsWithoutSupport) { goners = goners.add(self); } } else { // calculate total support var grandTotal = 0; var totals = []; while (nextRow.hasClass("row_a") || nextRow.hasClass("row_b")) { // supporting rows loop var total = 0; $("td:gt(0)", nextRow).each(function (i) { // total support per supporting village var cellSelf = $(this); var cellContent = $.trim(cellSelf.text()); if (!(cellContent == '0' || i >= world_data.unitsPositionSize.length)) { total += cellContent * world_data.unitsPositionSize[i]; if (totals[i] == undefined) { totals[i] = parseInt(cellContent, 10); } else { totals[i] += parseInt(cellContent, 10); } } }); grandTotal += total; $("td:eq(" + (world_data.unitsPositionSize.length + 1) + ")", nextRow).text(formatNumber(total)); // print distance between own village var supportedCell = $("td:first", nextRow); var supportedVillage = getVillageFromCoords(supportedCell.text()); var distance = parseInt(getDistance(supportedVillage.x, villageCoord.x, supportedVillage.y, villageCoord.y, 'ram').fields, 10); //supportedCell.html(supportedCell.html() + ' <b>' + trans.sp.all.fieldsSuffix.replace("{0}", distance) + '</b>'); supportedCell.append(' <b>' + trans.sp.all.fieldsSuffix.replace("{0}", distance) + '</b>'); nextRow.attr("distance", distance); if (rowColor % 2 == 1) { nextRow.removeClass("row_a").addClass("row_b"); } else { nextRow.removeClass("row_b").addClass("row_a"); } nextRow = nextRow.next(); } // row colors for the support villages if (rowColor % 2 == 1) { nextRow.removeClass("row_a").addClass("row_b"); } else { nextRow.removeClass("row_b").addClass("row_a"); } var troopCells = ""; for (var i = 0; i < world_data.unitsPositionSize.length; i++) { if (typeof totals[i] !== 'undefined') { troopCells += "<td>" + formatNumber(totals[i]) + "</td>"; } else { troopCells += "<td><span class=hidden>0</span></td>"; } } self.attr("population", grandTotal); var color = getStackColor(grandTotal); color = "<td style='background-color: " + color + "; border:1px solid black'>" + formatNumber(grandTotal) + "</td>"; nextRow.before("<tr class='grandTotal " + (rowColor % 2 == 1 ? "row_b" : "row_a") + "' village='" + villageCoord.coord + "' population='" + grandTotal + "'><td> </td><td>" + (isSupport ? trans.sp.defOverview.totalFromOtherVillages : trans.sp.defOverview.totalInOtherVillages) + "</td>" + troopCells + color + "</tr><tr height=10></tr>"); } }); goners.remove(); }); // This file contains the filters on the SECOND row of the menu /** * Loops over all supporting rows and removes the rows that fail the filterStrategy predicate. Where the * filterMainRows function loops over the OWN villages, this one loops over all the others. * @param {Function} filterStrategy gets each jQuery row that represents a supporting village passed as parameter * @param {string=after} [calcDefTotalsTime] is "before" or "after". before if it uses row attributes set by #defTotals */ function filterTable(filterStrategy, calcDefTotalsTime) { if (typeof calcDefTotalsTime === 'undefined') { calcDefTotalsTime = "after"; } if (calcDefTotalsTime === "before" && !$("#defTotals").is(":disabled")) { $("#defTotals").click(); } var totalDefCalced = $("#defTotals").is(":disabled"); var reverseFilter = $("#defReverseFilter").is(":checked"); var goners = $(); $("tr", overviewTable).slice(1).each(function () { var self = $(this); if ((totalDefCalced && self.attr("distance")) || (!totalDefCalced && (self.hasClass("row_a") || self.hasClass("row_b")))) { if (!reverseFilter != !filterStrategy(self)) { goners = goners.add(self); } } }); goners.remove(); setTotalCount(); if (user_data.restack.autohideWithoutSupportAfterFilter) { $("#defHideEmpty").click(); } if (user_data.restack.calculateDefTotalsAfterFilter && calcDefTotalsTime === "after" && !$("#defTotals").is(":disabled")) { $("#defTotals").click(); } } // NOBLES and SCOUTS $("#filtersnob, #filterspy").click( function () { trackClickEvent("FilterSnobOrSpy"); var position = $.inArray($(this).attr("id").substr(6), world_data.units) + 1; filterTable(function (row) { return row.find("td").eq(position).text() != "0"; }); }); // OTHER PLAYERS SUPPORT $("#filterSupport").click( function () { trackClickEvent("FilterSupport"); filterTable(function (row) { return row.find("td:first a").length != 2; }); }); // DEFENSIVE & OFFENSIVE UNITS $("#filterAttack, #filterDefense").click( function () { trackClickEvent("FilterOffOrDef"); var unitArray = $(this).attr('id') == "filterDefense" ? world_data.units_def : world_data.units_off; filterTable(function (row) { var hideRow = false; $("td:gt(0)", row).each(function (i) { if (world_data.units[i] != undefined && world_data.units[i] != "heavy" && parseInt($(this).text(), 10) > 0 && $.inArray(world_data.units[i], unitArray) > -1) { hideRow = true; return false; } }); return hideRow; }); }); /// BARBARIAN VILLAGES filter $("#defFilterBarbarian").click( function () { trackClickEvent("FilterBarbarian"); filterTable(function (row) { var text = row.find("td:first").text(); return text.match(/\(---\)\s+\(F\d+\)$/); // Unlocalized F(ields) string }); }); // TEXT FILTER $("#defFilterText").click( function () { trackClickEvent("FilterText"); var compareTo = $("#defFilterTextValue").val().toLowerCase(); if (compareTo.length > 0) filterTable(function (row) { return row.text().toLowerCase().indexOf(compareTo) == -1; }); }); // DISTANCE between OWN and supporting village $("#defFilterDistance").click(function () { trackClickEvent("FilterDistance"); var maxDistance = $("#defFilterDistanceValue").val(); filterTable( function (row) { var distance = $(row).attr("distance"); return (distance != '' && parseInt(distance, 10) < maxDistance); }, "before"); }); } catch (e) { handleException(e, "overview-supportdetail"); } //console.timeEnd("overview-supportdetail"); }()); } // COMMANDS OVERVIEW else if (location.href.indexOf('mode=commands') > -1) { (function() { //console.time("overview-commands"); try { overviewTable = $("#commands_table"); tableHandler.init("commands_table", { hasBottomTotalRow: true }); var commandListType = getQueryStringParam("type"); var menu = ""; menu += "<table class=vis width='100%'>"; menu += "<tr>"; if (location.href.indexOf('type=all') > -1 || location.href.indexOf('&type=') == -1) { menu += "<th width='1%'>"; menu += "<input type=button id=filterReturning value='" + trans.sp.commands.filterReturn + "' title=\"" + trans.sp.commands.filterReturnTooltip + "\">"; menu += "</th>"; } menu += "<th width='1%' nowrap>"; menu += "<input type=checkbox id=sortSum " + (user_data.command.sumRow ? "checked" : "") + "> " + trans.sp.commands.totalRows + " "; var isSupport = location.href.indexOf('type=support') > -1; menu += "<input type=button id=sortIt value='" + trans.sp.commands.group + "'>"; menu += "</th><th width='98%'>"; menu += "<input type=button id=BBCodeOutput value='" + trans.sp.commands.bbCodeExport + "' title='" + trans.sp.commands.bbCodeExportTooltip + "'>"; if (commandListType !== "attack" && commandListType !== "return") { menu += " "; menu += "<input type=text id=supportPlayerName size=> "; menu += "<input type=button id=supportPlayerExport value='" + trans.sp.commands.supportPlayerExport + "' title='" + trans.sp.commands.supportPlayerExportTooltip + "'>"; } menu += "</th></tr></table>"; // second row menu += "<table><tr><th width='1%' nowrap>"; menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": "; menu += "</th><th width='1%' nowrap>"; menu += "<span style='background-color: #ecd19a; border: 1px solid black' id='unitFilterBox'>"; menu += " <img src='graphic/unit/unit_snob.png' id=filtersnob> <img src='graphic/unit/unit_spy.png' id=filterspy> <img src='graphic/face.png' id=filterFake> "; menu += " </span>"; menu += "</th><th width='1%' nowrap>"; menu += "<input type=text size=12 id=defFilterTextValue value=''>"; menu += "<input type=button id=defFilterText value='" + trans.sp.commands.freeTextFilter + "'>"; menu += "</th><th width='97%' nowrap>"; menu += "<input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>"; menu += "</th></tr>"; menu += "</table>"; $("#commands_table").before(menu); $("#select_all").replaceWith("<input type='checkbox' id='selectAll'>"); var selectAllCheckboxes = function() { var isChecked = $("#selectAll").is(":checked"); $("#commands_table tr:visible").find(":checkbox").prop("checked", isChecked); }; $("#selectAll").change(selectAllCheckboxes); var offsetToUnits = 3; $("#defReverseFilter").change( function () { var isChecked = $(this).is(":checked"); var defTrans = trans.sp.commands; $("#unitFilterBox").find("img:eq(0)").attr("title", !isChecked ? defTrans.nobleFilter : defTrans.nobleFilterRev); $("#unitFilterBox").find("img:eq(1)").attr("title", isChecked ? defTrans.spyFilter : defTrans.spyFilterRev); $("#unitFilterBox").find("img:eq(2)").attr("title", !isChecked ? defTrans.fakeFilter : defTrans.fakeFilterRev); $("#defFilterContinent").attr("title", isChecked ? defTrans.continentFilterTooltip : defTrans.continentFilterTooltipReverse); $("#defFilterText").attr("title", defTrans.freeTextFilterTooltip.replace("{filterType}", isChecked ? defTrans.freeTextFilterTooltipFilterTypeWith : defTrans.freeTextFilterTooltipFilterTypeWithout)); }); $("#defReverseFilter").change(); var hasGrouped = false; // generate bb code or JSON (for player os) export $("#BBCodeOutput,#supportPlayerExport").click(function () { trackClickEvent($(this).attr("id")); var villages = []; var request = {}; var filter = hasGrouped ? "tr.command" : "tr:gt(0)"; $("#commands_table " + filter).filter(":visible").each(function () { var row = $(this); var cells = $("td", row); var firstCell = cells.first(); var commandType = firstCell.find("img:first").attr("src"); if (typeof commandType !== 'undefined' && commandType.indexOf("command/cancel.png") == -1 && commandType.indexOf("command/other_back.png") == -1 && commandType.indexOf("command/back.png") == -1 && commandType.indexOf("command/return.png") == -1) { // We get the village coords from the description of the command // Meaning if the user changes the name to "blabla" that we can't parse it var village = getVillageFromCoords($.trim(firstCell.text())); //assert(village.isValid, $.trim(firstCell.text()) + " could not be converted to village"); if (village.isValid) { if (request[village.coord] == undefined) { request[village.coord] = { village: village.coord, attacks: [], hasSupport: false }; villages.push(village.coord); } var unitsSent = {}; $.each(world_data.units, function (i, val) { unitsSent[val] = parseInt(cells.eq(offsetToUnits + i).text(), 10); }); var isSupport = false; if (commandListType == "support") { isSupport = true; } else if (commandListType == "attack") { isSupport = false; } else { isSupport = cells.first().has("img[src*='command/support.png']").size() == 1; } request[village.coord].hasSupport = isSupport; request[village.coord].attacks.push({ isSupport: isSupport, units: unitsSent, unitsString: buildAttackString(null, unitsSent, null, isSupport, user_data.command.bbCodeExport.requiredTroopAmount), commandName: isSupport ? $.trim(firstCell.text()) : "", commandId: isSupport ? firstCell.find(":checkbox").attr("value") : null, arrivalDate: getDateFromTodayTomorrowTW(cells.eq(2).text()) }); } } }); var exportWidgets = []; if ($(this).attr("id") === "BBCodeOutput") { var requestsPer500 = [""]; var requestComposed = ""; for (var i = 0; i < villages.length; i++) { var currentVillage = request[villages[i]]; var currentText = ""; currentText += "[spoiler][code]"; var attackCount = 0; var supportCount = 0; var lastAttack = null; var largestAttack = 0; var totalPop = 0; for (var attackId = 0; attackId < currentVillage.attacks.length; attackId++) { var currentAttack = currentVillage.attacks[attackId]; if (currentAttack.isSupport) { supportCount++; $.each(world_data.units, function (i, val) { totalPop += currentAttack.units[val] * world_data.unitsPositionSize[i]; }); } else { attackCount++; if (lastAttack == null || lastAttack < currentAttack.arrivalDate) { lastAttack = currentAttack.arrivalDate; } } if (largestAttack < currentAttack.unitsString.length) { largestAttack = currentAttack.unitsString.length; } } for (var attackId = 0; attackId < currentVillage.attacks.length; attackId++) { var currentAttack = currentVillage.attacks[attackId]; currentText += currentAttack.unitsString; var extraTabs = (largestAttack - currentAttack.unitsString.length) / 1; if (Math.ceil(extraTabs) == extraTabs) { extraTabs = Math.ceil(extraTabs); } for (var tabs = 0; tabs < extraTabs + 1; tabs++) { currentText += " "; } currentText += "\t" + twDateFormat(currentAttack.arrivalDate, true) + "\n"; } currentText += "[/code][/spoiler]\n"; var headerTemplate; if (!currentVillage.hasSupport && attackCount !== 0) { headerTemplate = trans.sp.commands.exportAttackHeader; } else if (currentVillage.hasSupport && attackCount === 0) { headerTemplate = trans.sp.commands.exportDefenseHeader; } else { headerTemplate = trans.sp.commands.exportCompleteHeader; } requestComposed += headerTemplate .replace("{#}", attackCount) .replace("{support#}", supportCount) .replace("{totalStack}", formatNumber(totalPop)) .replace("{lastAttack}", lastAttack !== null ? twDateFormat(lastAttack, true) : "") .replace("{village}", "[village]" + villages[i] + "[/village]") + "\n " + currentText; // splits per 500 [ characters (limit in TW) var amountBracket = requestsPer500[requestsPer500.length - 1].match(/\[/g); if (amountBracket != null && (requestComposed.match(/\[/g).length + amountBracket.length > server_settings.allowedSquareBrackets)) { requestsPer500.push(""); } requestsPer500[requestsPer500.length - 1] += requestComposed; requestComposed = ""; } for (i = 0; i < requestsPer500.length; i++) { exportWidgets.push("<textarea cols=80 rows=10 class=restackArea>" + requestsPer500[i] + "</textarea>"); } } else { // JSON export for player support var exportAttacks = [], playerName = $.trim($("#supportPlayerName").val()), filter = playerName.length === 0 ? function(attackString) { return true; } : function(attackString) { return attackString.indexOf(playerName) !== -1 }; for (var i = 0; i < villages.length; i++) { var currentVillage = request[villages[i]]; if (currentVillage.hasSupport) { for (var attackId = 0; attackId < currentVillage.attacks.length; attackId++) { var currentAttack = currentVillage.attacks[attackId]; if (currentAttack.isSupport && filter(currentAttack.commandName)) { exportAttacks.push({ commandName: currentAttack.commandName, commandId: currentAttack.commandId }); /*q(villages[i]); q(currentVillage) q(currentAttack); q("---------------------");*/ } } } } if (exportAttacks.length > 0) { exportWidgets.push("<textarea style='width: 96%' rows=10 class=restackArea>" + JSON.stringify(exportAttacks, null, 4) + "</textarea>"); } else { alert(trans.sp.commands.exportNone); } } if (exportWidgets.length > 0) { if ($("#textsArea").size() == 0) { $(this).parent().parent().parent().append("<tr><td id=textsArea colspan=3></td></tr>"); } else { $("#textsArea").html(""); } for (var i = 0; i < exportWidgets.length; i++) { $("#textsArea").append(exportWidgets[i]); } $("#textsArea").append("<br><input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>"); $("#closeTextsArea").click(function() { $("#textsArea").parent().remove(); }); } }); function filterCommandRows(filterStrategy) { // return true to hidethe row; false keep row visible (without reverse filter checkbox) var reverseFilter = $("#defReverseFilter").is(":checked"); var goners = $(); var filter = hasGrouped ? "tr.command" : "tr:gt(0)"; $("#commands_table " + filter).filter(":visible").each(function () { if ($("th", this).size() != 0) { // don't do anything anymore when on the total row return; } if (!reverseFilter != !filterStrategy($(this))) { goners = goners.add($(this)); $("input:eq(1)", this).val(""); } }); goners.remove(); // Show totals var amountOfCommandos = $("#commands_table " + filter).size(); if (hasGrouped) { $("#commands_table tr.sumLine").hide(); } else { amountOfCommandos--; } $("#commands_table th:first").text(trans.sp.commands.tableTotal.replace("{0}", amountOfCommandos)); $("#amountOfAttacks").text(amountOfCommandos); if ($("#amountOfAttacks").size() == 1) { $("#amountOfTargets").val("???"); } $("#commands_table tr").not(":visible").find(":checkbox").prop("checked", false); } // Filter sent back, returning and cancelled commands $("#filterReturning").click(function () { $(this).attr("disabled", "disabled"); trackClickEvent("FilterReturning"); filterCommandRows( function (row) { var firstCellImage = $("td:first img:first", row).attr("src"); return firstCellImage.indexOf("command/other_back.png") != -1 || firstCellImage.indexOf("command/back.png") != -1 || firstCellImage.indexOf("command/return.png") != -1 || firstCellImage.indexOf("command/cancel.png") != -1; }); }); $("#defFilterText").click(function () { trackClickEvent("FilterText"); var compareTo = $("#defFilterTextValue").val().toLowerCase(); if (compareTo.length > 0) { filterCommandRows(function (row) { return row.text().toLowerCase().indexOf(compareTo) == -1; }); } }); $("#filterspy").click(function () { trackClickEvent("FilterSpy"); var position = $.inArray($(this).attr("id").substr(6), world_data.units); filterCommandRows(function (row) { if (row.find("td").eq(position + offsetToUnits).text() == "0") { return false; } var totalScout = row.find("td").eq(position + offsetToUnits).text(); var cell = row.find("td:eq(" + (offsetToUnits - 1) + ")"); for (var i = 0; i < world_data.units.length; i++) { cell = cell.next(); if (totalScout < cell.text()) { return false; } } return true; }); }); $("#filtersnob").click(function () { trackClickEvent("FilterSnob"); var position = $.inArray($(this).attr("id").substr(6), world_data.units) + offsetToUnits; filterCommandRows(function (row) { return row.find("td").eq(position).text() == "0"; }); }); $("#filterFake").click(function () { trackClickEvent("FilterFake"); var maxPop = user_data.command.filterFakeMaxPop; filterCommandRows(function (row) { var total = 0; var cell = row.find("td:eq(" + (offsetToUnits - 1) + ")"); for (var i = 0; i < world_data.units.length; i++) { cell = cell.next(); total += parseInt(cell.text(), 10); // An attack with a noble is (almost) never a fake: if (i == world_data.units.length - 1 && cell.text() != "0") { return false; } if (total > maxPop) { return false; } } return true; }); }); $("#defFilterContinent").click(function () { trackClickEvent("FilterContinent"); var continent = parseInt($("#defFilterContinentText").val(), 10); if (!isNaN(continent)) { filterCommandRows(function (row) { var village = getVillageFromCoords(row.find("td:first").text()); var village2 = getVillageFromCoords(row.find("td:eq(1)").text()); if (!village.isValid || !village2.isValid) { return true; } return village.continent() != continent && village2.continent() != continent; }); } }); // Sort/group incoming attacks $("#sortIt").click(function () { trackClickEvent("Sort"); hasGrouped = true; var newTable = ""; var targets = []; var amountOfCommandos = 0; var sum = $('#sortSum').is(':checked'); $("#filterReturning").attr("disabled", true); $("#commands_table").find("tr:gt(0)").filter(":visible").each(function () { var target = $.trim($(".quickedit-label", this).text()); var village = getVillageFromCoords(target); if (village.isValid) { amountOfCommandos++; if (targets[village.coord] == undefined) { targets.push(village.coord); targets[village.coord] = new Array(); } targets[village.coord].push($(this)); } }); var mod = 0; if (isSupport) { $.each(targets, function (i, v) { mod++; var amount = 0; var totalDef = new Array(); totalDef['pop'] = 0; $.each(world_data.units, function (index, value) { totalDef[value] = 0; }); $.each(targets[v], function (index, value) { var villageId = $("td:eq(1) a:first", value).attr("href").match(/id=(\d+)/)[1]; newTable += "<tr class='command nowrap row_" + (mod % 2 == 0 ? 'b' : 'a') + (villageId == game_data.village.id ? " selected" : "") + "'>" + value.html() + "</tr>"; amount++; var unitAmounts = $("td:gt(2)", value); $.each(world_data.units, function (iUnit, vUnit) { var amount = parseInt(unitAmounts.eq(iUnit).html(), 10); if (amount == 1) { totalDef[vUnit] = amount; } else { totalDef[vUnit] += amount; } totalDef['pop'] += amount * world_data.unitsSize['unit_' + vUnit]; }); }); if (sum) { newTable += "<tr class='sumLine'><td align=right colspan=3><b>" + trans.sp.commands.totalRowsText.replace("{0}", amount).replace("{1}", formatNumber(totalDef['pop'])) + " </b></td>"; $.each(world_data.units, function (iUnit, vUnit) { newTable += "<td>" + (totalDef[vUnit] == 0 ? " " : formatNumber(totalDef[vUnit])) + "</td>"; }); newTable += "</tr>"; } }); } else { // attacks (meaning: no support commands) $.each(targets, function (i, v) { mod++; var amount = 0; var lastArrival = ''; $.each(targets[v], function (index, value) { var villageId = $("td:eq(1) a:first", value).attr("href").match(/id=(\d+)/)[1]; var currentArrival = $(value).find("td:eq(2)").text(); if (lastArrival == currentArrival) { // Don't show when it's on the same second // Only practical on full second worlds really newTable += "<tr class='command nowrap row_" + (mod % 2 == 0 ? 'b' : 'a') + (villageId == game_data.village.id ? " selected" : "") + "'>"; $(this).find("td").each(function (i) { if (i == 2) { newTable += "<td> </td>"; } else if ($(this).text() == 0) { newTable += "<td class=hidden>0</td>"; } else { newTable += "<td>" + $(this).html() + "</td>"; } }); newTable += "</tr>"; } else { newTable += "<tr class='command nowrap row_" + (mod % 2 == 0 ? 'b' : 'a') + (villageId == game_data.village.id ? " selected" : "") + "'>" + value.html() + "</tr>"; } lastArrival = currentArrival; amount++; }); if (sum) { newTable += "<tr class='sumLine'><td align=right colspan=" + (3 + world_data.units.length) + ">" + amount + " </td></tr>"; } }); } var menu = $("#commands_table tr").first().html(), totalRow = $("#commands_table tr:last"); $("#commands_table").html("<table id='commands_table' class='vis'>" + menu + newTable + totalRow.outerHTML() + "</table>"); $("#selectAll").change(selectAllCheckboxes); // total number of attacks if ($("#amountOfAttacks").size() == 0) { var totalDesc = (isSupport ? trans.sp.commands.totalSupport : trans.sp.commands.totalAttack); var totalVillagesDesc = isSupport ? trans.sp.commands.totalVillagesSupport : trans.sp.commands.totalVillagesAttack; var pageSize = $("input[name='page_size']"); if (pageSize.size() == 0) { pageSize = $("input[type='submit']:last"); 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>"); } else { pageSize[0].id = "amountOfTargets"; pageSize.parent().prev().text(totalVillagesDesc); pageSize = pageSize.val(targets.length).parent().parent().parent(); pageSize.append('<tr><th colspan=2>' + totalDesc + ':</th><td id="amountOfAttacks">' + amountOfCommandos + '</td></tr>'); } } else { $("#amountOfTargets").val(targets.length); $("#amountOfAttacks").text(amountOfCommandos); } }); } catch (e) { handleException(e, "overview-commands"); } //console.timeEnd("overview-commands"); }()); } // INCOMINGS OVERVIEW else if (location.href.indexOf('mode=incomings') > -1) { (function() { //console.time("overview-incomings"); try { overviewTable = $("#incomings_table"); tableHandler.init("incomings_table", { hasBottomTotalRow: getQueryStringParam("subtype") !== "supports" }); var table = { /** * Quick sort adds extra rows with the .total class */ hasTotalRows: false, /** * Some buttons add extra columns */ newColumns: { before: 0, after: 0 }, getColspan: function() { return 7 + this.newColumns.before + this.newColumns.after; }, /** * Remove the total rows so that other filters can operate again */ fixTable: function() { if (this.hasTotalRows === true) { overviewTable.find("tr.total").remove(); this.hasTotalRows = false; } }, getVillageRows: function() { var rows = overviewTable.find("tr:gt(0)"); if (tableHandler.settings.hasBottomTotalRow) { rows = rows.not("tr:last"); } return rows; }, /** * Set the table total rows count correctly * @param {number} rowCount * @param {number} [villagesTargeted] */ setTotals: function(rowCount, villagesTargeted) { var amountOfCommandsHeaderCell = $("tr:first", overviewTable).find("th:first"), amountOfRows = $("#amountOfRows"); assert(amountOfCommandsHeaderCell.length === 1, "couldn't find the command headercell"); amountOfCommandsHeaderCell.html(amountOfCommandsHeaderCell.html().replace(/\(\d+\)/, "(" + rowCount + ")")); if (typeof villagesTargeted !== "undefined") { if (amountOfRows.size() === 0) { var pageSize = $("input[name='page_size']"); pageSize.parent().prev().text(trans.sp.commands.totalVillagesAttack); pageSize = pageSize.attr("id", "villagesTargeted").parent().parent().parent(); pageSize.append('<tr><th colspan=2>' + trans.sp.incomings.amount + '</th><td id="amountOfRows">' + rowCount + '</td></tr>'); } else { $("#amountOfRows").text(villagesTargeted); $("#villagesTargeted").val(villagesTargeted); } } } }; var columnsToFilterCount = 5; // build sangu menu var menu = ""; menu += "<table width='100%' class='vis' id='sangu_menu'>"; menu += "<tr><th width='1%'>"; menu += "<input type=button id=sortIt value='" + trans.sp.incomings.dynamicGrouping + "' title='" + trans.sp.incomings.dynamicGroupingTooltip + "'>"; menu += "</th><th width='1%' nowrap>"; menu += "<input type=checkbox id=sortShowTotalRow " + (user_data.command.sumRow ? "checked" : "") + "> " + trans.sp.incomings.summation + " "; menu += "<input type=button id=sortQuick value='" + trans.sp.incomings.fastGrouping + "' title='" + trans.sp.incomings.fastGroupingTooltip + "'>"; menu += "</th><th width='1%'>"; menu += "<input type=button id=sortByAttackId value='" + trans.sp.incomings.sortByAttackId + "' title='" + trans.sp.incomings.sortByAttackIdTooltip + "'>"; menu += "</th><th width='96%'>"; menu += "<input type=button id=filterAttack value='" + trans.sp.incomings.showNewIncomings + "'>"; menu += "</th><th width='1%' nowrap>"; menu += "<input type=button id=commandsImport value='" + trans.sp.incomings.commandsImport + "' title='" + trans.sp.incomings.commandsImportTooltip + "'>"; menu += "</th></tr>"; menu += "</table>"; // second row menu += "<table width='100%' class=vis>"; menu += "<tr><th width='1%' nowrap>"; menu += "<input type=checkbox id=defReverseFilter title='" + trans.sp.commands.filtersReverse + "'> " + trans.sp.commands.filtersReverseInfo + ": "; menu += "</th>"; // generate one input field/button filter with a select for the first cells var defaultColumnFilters = (function() { var headerCells = $("tr:first th", overviewTable), cols = [], headerCellText; for (i = 0; i < columnsToFilterCount; i++) { headerCellText = headerCells.eq(i).text(); if (headerCellText.indexOf(" ") !== -1) { headerCellText = $.trim(headerCellText.substr(0, headerCellText.indexOf(" "))); } cols.push(headerCellText); } return cols; }()); /** * builds a textinput+select+button filter that filters rows based on table column index */ function buildColumnFilter() { var i, defualtIndex = pers.get("incomingsColumnFilterIndex"), menu = "<th width='99%' nowrap>"; menu += "<input type='text' size='20' id='filterColumnValue'>"; menu += "<select id='filterColumnIndex'>"; for (i = 0; i < defaultColumnFilters.length; i++) { menu += "<option value='" + i + "'" + (defualtIndex == i ? " selected" : "") + ">" + defaultColumnFilters[i] + "</option>"; } menu += "</select>"; menu += "<input type='button' id='filterColumn' value='" + trans.sp.incomings.filterColumnButton + "'" + "'>"; menu += "</th>"; return menu; } menu += buildColumnFilter(); //menu += "<th width='97%' nowrap>"; //menu += "<input type=textbox size=3 id=defFilterContinentText maxlength=2><input type=button id=defFilterContinent value='" + trans.sp.commands.continentFilter + "'>"; //menu += "</th></tr>"; menu += "</table>"; overviewTable.before(menu); $("#filterColumnIndex").change(function() { pers.set("incomingsColumnFilterIndex", $("#filterColumnIndex").val()); }); // switch tooltips on reverse filter checkbox change $("#defReverseFilter").change( function () { var isChecked = $(this).is(":checked"), overviewTrans = trans.sp.incomings; //$("#").attr("title", isChecked ? overviewTrans.continentFilterTooltip : overviewTrans.continentFilterTooltipReverse); $("#filterColumn").attr( "title", overviewTrans.filterColumnButtonTooltip.replace( "{type}", isChecked ? overviewTrans.filterColumnButtonTooltipHide : overviewTrans.filterColumnButtonTooltipShow)); }).change(); // select all checkbox $("#select_all").replaceWith("<input type='checkbox' id='selectAll'>"); $("#selectAll").change(function() { var isChecked = $("#selectAll").is(":checked"); $("tr", overviewTable).find(":checkbox").prop("checked", isChecked); }); // IMPORT os exported by other player $("#commandsImport").click(function() { if ($("#textsArea").size() == 0) { $(this).parent().parent().parent().append("<tr><td id=textsArea colspan=5></td></tr>"); $("#textsArea").append( "<textarea cols=80 rows=10 id=commandImportText></textarea>" + "<br>" + "<input type=button value='" + trans.sp.incomings.commandsImport + "' id=commandsImportReal>" + "<input type=button value='" + trans.sp.all.close + "' id=closeTextsArea>"); $("#closeTextsArea").click(function() { $("#textsArea").parent().remove(); }); $("#commandsImportReal").click(function() { var commandsToImport; try { commandsToImport = JSON.parse($("#commandImportText").val()); var test = commandsToImport[0].commandName; } catch (e) { alert(trans.sp.incomings.commandsImportError); } var amountReplaced = 0, commandsSent = [], i; for (i = 0; i < commandsToImport.length; i++) { commandsSent[commandsToImport[i].commandId] = commandsToImport[i].commandName; } table.getVillageRows().each(function () { var firstCell = $("td:first", this), commandId = firstCell.find(":input:first").attr("name"); //q("inputfield: " + firstCell.find(":input:first").length); //q("commandId = " + commandId + " in cell: " + firstCell.text()); //assert(commandId, "couldn't find command id inputfield"); //assert(commandId.indexOf("command_ids") === 0, "inputfields have been renamed"); commandId = parseInt(commandId.match(/\d+/)[0], 10); if (typeof commandsSent[commandId] !== 'undefined') { var inputField = $(':input[id^="editInput"]', firstCell); //assert(inputField.length === 1, "couldn't find the inputfield"); inputField.val(commandsSent[commandId]); inputField.next().click(); amountReplaced++; } }); alert(trans.sp.incomings.commandsImportSuccess .replace("{replaced}", amountReplaced) .replace("{total}", commandsToImport.length)); }); } }); // Sort by attack id (and add extra column) $("#sortByAttackId").click(function() { $(this).attr("disabled", true); table.fixTable(); table.newColumns.after += 2; var diffGroups = user_data.incomings.attackIdDescriptions; function getFancyAttackIdDiffDescription(diff) { var i; for (i = 0; i < diffGroups.length; i++) { if (diff < diffGroups[i].minValue) { return diffGroups[i].text; } } return user_data.incomings.attackIdHigherDescription; } // new column in header tableHandler.overviewTable.find("tr:first").append("<th>"+trans.sp.incomings.attackId+"</th><th>"+trans.sp.incomings.attackIdDifference+"</th>"); var rows = table.getVillageRows(); rows.sortElements(function (rowA, rowB) { var a = $("input:first", rowA).attr("name").match(/\d+/)[0]; var b = $("input:first", rowB).attr("name").match(/\d+/)[0]; //q($("input:first", rowA).attr("name") + "=>" + a); return parseInt(a, 10) > parseInt(b, 10) ? 1 : -1; }); var previousRowAttackId = 0; rows.each(function() { var attackId = parseInt($(this).find("input:first").attr("name").match(/\d+/)[0], 10), diff = 0, diffDescription = " "; if (previousRowAttackId != 0) { diff = Math.abs(attackId - previousRowAttackId); diffDescription = getFancyAttackIdDiffDescription(diff); } previousRowAttackId = attackId; $(this).append("<td align=right>"+attackId+"</td><td>"+diffDescription+"</td>"); }); }); // QUICK sort: performs faster but also freezes the screen (ie no countdowns) // --> This might also be good in case the page is refreshing too often otherwise $("#sortQuick").click(function () { trackClickEvent("SortQuick"); table.fixTable(); table.hasTotalRows = true; var newTable = ""; var targets = []; var commandCounter = 0; var addTotalRow = $('#sortShowTotalRow').is(':checked'); table.getVillageRows().each(function () { var target = $("td:eq(1)", this).text(); var village = getVillageFromCoords(target); if (village.isValid) { commandCounter++; if (targets[village.coord] == undefined) { targets.push(village.coord); targets[village.coord] = []; } targets[village.coord].push($(this)); } }); var mod = 0; $.each(targets, function (i, v) { mod++; var rowColor = "row_" + (mod % 2 == 0 ? 'b' : 'a'); var amount = 0; $.each(targets[v], function (index, row) { var villageId = row.find("td:eq(1) a:first").attr("href").match(/village=(\d+)/)[1]; newTable += "<tr class='nowrap " + rowColor + "'" + (villageId == game_data.village.id ? " selected" : "") + ">" + row.html() + "</tr>"; amount++; }); if (addTotalRow) { if (amount === 1) { newTable += "<tr class='" + rowColor + " total'><td align=right colspan=" + table.getColspan() + "> </td></tr>"; } else { newTable += "<tr class='" + rowColor + " total'><td align=right colspan=" + table.getColspan() + "><b>" + trans.sp.incomings.amount + " " + amount + "</b> </td></tr>"; } } }); var menu = $("tr:first", overviewTable).html(); var totalRow = $("tr:last", overviewTable).html(); overviewTable.html("<table id='incomings_table' class='vis'>" + menu + newTable + totalRow + "</table>"); table.setTotals(commandCounter, targets.length); }); // DYNAMIC sort incoming attacks $("#sortIt").click(function () { table.fixTable(); trackClickEvent("Sort"); var rows = table.getVillageRows(); rows.sortElements(function (a, b) { a = getVillageFromCoords($("td:eq(1)", a).text()); b = getVillageFromCoords($("td:eq(1)", b).text()); return (a.x * 1000 + a.y) > (b.x * 1000 + b.y) ? 1 : -1; }); var amountOfVillages = 0; var current = ""; rows.each(function () { var village = $("td:eq(1)", this); if (current != village.text()) { current = village.text(); amountOfVillages++; } var type = amountOfVillages % 2 == 0 ? 'row_a' : 'row_b'; var villageId = village.find("a:first").attr("href").match(/village=(\d+)/)[1]; this.className = "nowrap " + type + (villageId == game_data.village.id ? " selected" : ""); }); table.setTotals(rows.size(), amountOfVillages); }); /** * * @param {function} filterStrategy return true to hidethe row; false keep row visible (without reverse filter checkbox) * @param {Object} options */ function filterVillageRows(filterStrategy, options) { options = $.extend({}, { checkboxReverses: true }, options); var reverseFilter = options.checkboxReverses && $("#defReverseFilter").is(":checked"), goners = $(), villageCounter = 0; trackClickEvent(options.gaEventName); table.fixTable(); table.getVillageRows().each(function () { var self = $(this); if (!reverseFilter != !filterStrategy(self)) { goners = goners.add(self); } else { villageCounter++; } }); goners.remove(); // Show totals table.setTotals(villageCounter); } // Show new attacks only $("#filterAttack").click(function () { var strategy = function(row) { return $.trim($("td:first", row).text()) != trans.tw.command.attack; }; filterVillageRows(strategy, { gaEventName: "FilterNewAttacks", checkboxReverses: false }); }); // Filter rows on column 0 - 3 (command, target, origin, player) $("#filterColumn").click(function() { var filter = { index: $("#filterColumnIndex").val(), searchText: $.trim($("#filterColumnValue").val()).toLowerCase() }; var filterStrategy = function(row) { return row.find("td").eq(filter.index).text().toLowerCase().indexOf(filter.searchText) === -1; }; filterVillageRows(filterStrategy, { gaEventName: "column-" + $("#filterColumnIndex").text() }); }); } catch (e) { handleException(e, "overview-incomings"); } //console.timeEnd("overview-incomings"); }()); } // make the editting groups box less wide // and add alternating row colors $("#edit_group_href").click(function () { var groupTable = $("#group_list"); groupTable.width(300); groupTable.find("th:first").attr("colspan", "3"); var mod = 0; groupTable.find("tr:gt(0)").each(function () { mod++; $(this).addClass("row_" + (mod % 2 == 0 ? "a" : "b")); }); }); // change troops overview link to active sangu page if (user_data.command.changeTroopsOverviewLink) { var troopsOverviewLink = $("#overview_menu a[href*='mode=units']"); troopsOverviewLink.attr("href", troopsOverviewLink.attr("href") + "&type=own_home"); } if (user_data.overviews.addFancyImagesToOverviewLinks) { var overviewLinks = $("#overview_menu a"); overviewLinks.each(function(index) { var overviewLink = $(this), imageToAdd = ""; switch (index) { case 0: // overviewLink.parent() // .css("background-image", 'url("https://www.tribalwars.vodka/graphic/icons/header.png")') // .css("background-repeat", "no-repeat") // .css("background-position", "-324px 0px") // .css("background-size", "200px Auto"); // // overviewLink.prepend(" "); break; case 1: imageToAdd = "graphic/buildings/storage.png"; break; case 2: imageToAdd = "graphic/buildings/market.png"; break; case 3: if (overviewLink.parent().hasClass("selected")) { $("table.modemenu:last a", content_value).each(function(index) { imageToAdd = ""; switch (index) { case 1: imageToAdd = "graphic/buildings/place.png"; break; case 2: imageToAdd = "graphic/pfeil.png"; break; case 3: case 4: $(this).css("opacity", "0.5"); break; case 5: imageToAdd = "graphic/command/support.png"; break; case 6: imageToAdd = "graphic/rechts.png"; break; } if (imageToAdd !== "") { $(this).prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text() + " > " + $(this).text()+"' /> "); } }); } imageToAdd = "graphic/unit/unit_knight.png"; break; case 4: if (overviewLink.parent().hasClass("selected")) { $("table.modemenu:last a", content_value).each(function(index) { imageToAdd = ""; switch (index) { case 1: imageToAdd = "graphic/command/attack.png"; break; case 2: imageToAdd = "graphic/command/support.png"; break; case 3: imageToAdd = "graphic/command/return.png"; break; } if (imageToAdd !== "") { $(this).prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text() + " > " + $(this).text()+"' /> "); } }); } imageToAdd = "graphic/command/attack.png"; break; case 5: if (overviewLink.parent().hasClass("selected")) { $("table.modemenu:last a", content_value).each(function(index) { imageToAdd = ""; switch (index) { case 1: imageToAdd = "graphic/command/attack.png"; break; case 2: imageToAdd = "graphic/command/support.png"; break; } if (imageToAdd !== "") { $(this).prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text() + " > " + $(this).text()+"' /> "); } }); } imageToAdd = "graphic/unit/att.png"; break; case 6: imageToAdd = "graphic/buildings/main.png"; break; case 7: imageToAdd = "graphic/buildings/smith.png"; break; case 8: imageToAdd = "graphic/group_right.png"; overviewLink.prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text()+"' /> "); imageToAdd = "graphic/group_left.png"; break; case 9: imageToAdd = "graphic/premium/coinbag_14x14.png"; overviewLink.parent().width(150); break; } if (imageToAdd !== "") { overviewLink.prepend("<img src='https://www.tribalwars.vodka/"+imageToAdd+"' title='"+overviewLink.text()+"' /> "); } }); } } var logoffLink = $("#linkContainer a:last"); if (user_data.global.duplicateLogoffLink) { $("#linkContainer a:first").after(" - ").after(logoffLink.clone()); } logoffLink.before("<a target='_blank' title='"+trans.sp.sp.moreScriptsTooltip+"' href='"+server_settings.scriptsDatabaseUrl+"'>"+trans.sp.sp.moreScripts+"</a>") .before(" - <a target='_top' id='sanguPackageEditSettingsLink' href='"+getUrlString("screen=settings&mode=sangu")+"' title='" + trans.sp.sp.sanguLinkTitle + "'>Sangu Package</a> - "); (function() { var position = $("#sanguPackageEditSettingsLink").position(), options = { left: position.left, top: ($(window).height() - 100) }, content = { body: trans.sp.sp.firstTimeRunEditSettings }; createFixedTooltip("sanguActivatorSettingsTooltip", content, options); }()); (function() { //console.time("resourceColoring"); try { var storage = parseInt($("#storage").text(), 10); // Color resources based on how full the storage place is if (user_data.global.resources.active) { $("#wood,#iron,#stone").each(function () { var x = parseInt(this.innerHTML / storage * 10 - 1, 10); $(this).css("background-color", user_data.global.resources.backgroundColors[x]); }); } // Blink full resources if (user_data.global.resources.blinkWhenStorageFull) { $("#wood,#iron,#stone").filter(function () { return parseInt(this.innerHTML, 10) == storage; }).css({ "font-weight": "bolder", "color": "black" }).fadeOut().fadeIn(); } } catch (e) { handleException(e, "resourcecoloring"); } //console.timeEnd("resourceColoring"); }()); // adjust links to incoming attacks/support // keep track of current amount of incomings if (user_data.global.incomings.editLinks || user_data.global.incomings.track) { (function() { //console.time("incomingsindicator"); try { var incoming = $("table.box:last"), incomingAttacksLinks = $("a[href*='subtype=attacks']", incoming), variableReplacer = function (text) { var difference = ""; if (sinceLastCheckTimeNew > 0) { difference += "+" + sinceLastCheckTimeNew; if (sinceLastCheckTimeArrived > 0) { difference += " "; } } if (sinceLastCheckTimeArrived > 0) { difference += "-" + sinceLastCheckTimeArrived; } return text.replace("{difference}", difference) .replace("{elapsed}", lastCheckTimeElapsed) .replace("{time}", lastCheckTime) .replace("{current}", currentAmountOfIncomings .replace("{saved}", lastKnownAmountOfIncomings)); }; if (incomingAttacksLinks.size() > 0) { if (user_data.global.incomings.editLinks) { incomingAttacksLinks.attr("href", incomingAttacksLinks.attr("href") + "&page=-1&group=0"); } if (user_data.global.incomings.track) { incomingAttacksLinks.parent().css("white-space", "nowrap"); // Split current and new attacks in incomings link var incomingAttacksAmountLink = incomingAttacksLinks.last(); var currentAmountOfIncomings = incomingAttacksAmountLink.text().match(/\d+/)[0]; var lastKnownAmountOfIncomings = parseInt(pers.get("lastKnownAmountOfIncomings" + game_data.player.sitter), 10) || 0, sinceLastCheckTimeNew = parseInt(pers.get("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter), 10) || 0, sinceLastCheckTimeArrived = parseInt(pers.get("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter), 10) || 0; var lastCheckTime = pers.get("lastKnownAmountOfIncomingsTime" + game_data.player.sitter); var lastCheckTimeElapsed; if (!lastCheckTime) { lastCheckTime = trans.sp.incomings.indicator.lastTimeCheckNotYetSet; lastCheckTimeElapsed = lastCheckTime; } else { lastCheckTime = new Date().getTime() - parseInt(lastCheckTime, 10); lastCheckTimeElapsed = prettyDate(lastCheckTime); lastCheckTime = twDateFormat(new Date(lastCheckTime)); } if (currentAmountOfIncomings != lastKnownAmountOfIncomings || sinceLastCheckTimeNew > 0 || sinceLastCheckTimeArrived > 0) { var newAttacks = currentAmountOfIncomings - lastKnownAmountOfIncomings; if (newAttacks > 0) { sinceLastCheckTimeNew += newAttacks; pers.set("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter, sinceLastCheckTimeNew); } else if (newAttacks < 0) { sinceLastCheckTimeArrived -= newAttacks; pers.set("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter, sinceLastCheckTimeArrived); } pers.set("lastKnownAmountOfIncomings" + game_data.player.sitter, currentAmountOfIncomings); $("#incomings_amount").html(variableReplacer(user_data.global.incomings.indicator)); incomingAttacksLinks.attr("title", variableReplacer(user_data.global.incomings.lastTimeCheckWarning)); incomingAttacksLinks.fadeOut("slow").fadeIn("slow"); } // extra image to set the lastCheckTime on incomings overview page if (current_page.screen === "overview_villages" && current_page.mode === "incomings") { // Tooltip for first time users if (lastCheckTime == trans.sp.incomings.indicator.lastTimeCheckNotYetSet) { // show info tooltip var position = incomingAttacksAmountLink.position(); var options = { left: position.left - 200, top: position.top + 35, width: 250 }; var content = {body: trans.sp.incomings.indicator.lastTimeCheckHintBoxTooltip.replace("{img}", "<img src='graphic/ally_forum.png'>")}; createFixedTooltip("incomingsIndicatorHelp", content, options); } // change last incomings-check time incomingAttacksLinks.last().parent().after( "<td class='box-item' id='changeLastCheckTimeBox' style='white-space: nowrap'><a href='#' id='changeLastCheckTime'> " + "<img src='graphic/ally_forum.png' style='padding-top: 5px' " + "title='"+variableReplacer(user_data.global.incomings.indicatorTooltip)+"'/> </a></td>"); // Set last incomings-check time $("#changeLastCheckTime").click(function() { var newCheckTime = new Date(); pers.set("lastKnownAmountOfIncomingsTime" + game_data.player.sitter, newCheckTime.getTime()); pers.set("lastKnownAmountOfIncomings" + game_data.player.sitter, currentAmountOfIncomings); pers.set("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter, 0); pers.set("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter, 0); pers.setGlobal("fixedToolTip_incomingsIndicatorHelp", 1); $("#changeLastCheckTimeBox").fadeOut(); window.location.href = window.location.href; }); } } } else { // When there are no more incomings, stop tracking if (user_data.global.incomings.track) { pers.set("lastKnownAmountOfIncomings" + game_data.player.sitter, 0); pers.set("lastKnownAmountOfIncomingsAdded" + game_data.player.sitter, 0); pers.set("lastKnownAmountOfIncomingsRemoved" + game_data.player.sitter, 0); } } // change incoming support link if (user_data.global.incomings.editLinks) { var incomingSupport = $("a[href*='subtype=supports']", incoming); if (incomingSupport.size() > 0) { if (user_data.global.incomings.editLinks) { incomingSupport.attr("href", incomingSupport.attr("href") + "&page=-1&group=0"); } } } } catch (e) { handleException(e, "incomingsindicator"); } //console.time("incomingsindicator"); }()); } if (server_settings.ajaxAllowed && user_data.global.visualizeFriends) { (function() { //console.time("friends"); try { function Friends() { this.lastCheck = new Date().getTime(); this.online = { names: "", amount: 0 }; this.offlineAmount = 0; } /** * Insert a 'friends' link with visual online/offline indication */ function updateTWFriendsLink() { var friendsLink = $("<a href='" + getUrlString("&screen=buddies") + "'></a>"); friendsLink.html( trans.sp.rest.friendsOnline .replace("{friends}", friendsLink.text()) .replace("{onlineimg}", "<img src='graphic/dots/green.png' />") .replace("{online#}", friends.online.amount) .replace("{offlineimg}", "<img src='graphic/dots/red.png' />") .replace("{offline#}", friends.offlineAmount) ); if (friends.online.amount > 0) { friendsLink.attr("title", trans.sp.rest.friendsOnlineTitle.replace("{playerNames}", friends.online.names.substr(1))); } $("#sanguPackageEditSettingsLink").before(friendsLink).before(" - "); } /** * Parse the #content_value and update the friends link. * Is called from ajax call. * @param {string} overview the #content_value of the friends page */ function parseFriendsTable(overview) { var friendsTable = $("h3+table.vis:first", overview); if (friendsTable.size() == 1) { var friendRows = friendsTable.find("tr:gt(0)"); friendRows.each(function() { var friendName = $.trim($("a:first", this).text()); var statusIndicatorImage = $("img:first", this); if( statusIndicatorImage.length > 0 ) { if (/red\.png/.test(statusIndicatorImage.attr("src"))) { friends.offlineAmount++; } else { if (friendName != game_data.player.name) { friends.online.names += ", " + friendName; friends.online.amount++; } } } }); // localStorage save of online friends pers.set("friendsOnline", JSON.stringify(friends)); updateTWFriendsLink(); } } var friends = pers.get("friendsOnline"); // check friends page only every 5 minutes (or when on friends page itself) if ($("#village_link").val() == "/game.php?screen=buddies") { friends = new Friends(); parseFriendsTable(content_value); } else { if (friends) { friends = JSON.parse(friends); } if (!friends || friends.lastCheck < new Date().getTime() - 1000 * 60 * 3) { friends = new Friends(); ajax("buddies", parseFriendsTable); } else { updateTWFriendsLink(); } } } catch (e) { handleException(e, "friends"); } //console.timeEnd("friends"); }()); } //var end_time = new Date(); //console.timeEnd("SanguPackage"); //q("" + pad(Math.abs(start_time.getTime() - end_time.getTime()), 3) + " -> " + location.search); } } if (location.href.indexOf('sangu.be') !== -1) { // sangu.be (function() { // Check current version with version on the sangu.be site var lastVersion = $("#sanguPackageVersion"), resultBox = $("#versionCheckResult"); if (lastVersion.length === 1) { resultBox.show(); resultBox.css("padding", "20px"); resultBox.css("margin", "10px"); resultBox.css("font-size", 18); resultBox.css("height", 30); resultBox.css("text-align", "center"); if ('8.90.0'.indexOf(lastVersion.text()) === 0) { resultBox.css("background-color", "green"); resultBox.text("Je hebt de laatste versie!"); } else { resultBox.css("background-color", "red"); resultBox.text("Er is een nieuwe versie beschikbaar!"); } } }()); } else if (location.href.indexOf('tribalwars.nl') !== -1) { // TribalWars page (function (func, GM_xmlhttpRequest) { var lastCheck = sessionStorage.lastUpdateCheck, currentVersion = '8.90.0'; function displayNewVersion() { var a = document.createElement('a'); var linkText = document.createTextNode(" - Sangu Package Update!"); a.appendChild(linkText); a.title = "Er is een update voor het Sangu Package beschikbaar!"; a.href = "http://sangu.be"; a.style.color = "black"; a.style.fontWeight = "bolder"; a.style.backgroundColor = "yellow"; document.getElementById("linkContainer").appendChild(a); } if (typeof GM_xmlhttpRequest !== "undefined") { if (!lastCheck) { sessionStorage.lastUpdateCheck = "done"; try { // GM_xmlhttpRequest didn't work when put in sangu_ready GM_xmlhttpRequest({ method: "GET", url: "http://www.sangu.be/api/sangupackageversion.php", synchronous: false, onload: function(response) { if (response.responseText !== currentVersion) { sessionStorage.lastUpdateCheck = "hasNew"; displayNewVersion(); } } }); } catch (e) { console.log("error fetching latest version number:"); console.log(e); } } else if (lastCheck === "hasNew") { displayNewVersion(); } } var script = document.createElement('script'); script.setAttribute("type", "application/javascript"); if (window.mozInnerScreenX !== undefined) { // Firefox has troubles with renaming commands, villages, ... (it works some of the time) // But waiting for document.ready slows down the script so only wait for this on FF // An optimization could be to put document.readys only around those blocks that are // problematic. script.textContent = '$(document).ready(' + func + ');'; } else { script.textContent = '(' + func + ')();'; } document.body.appendChild(script); // run the script document.body.removeChild(script); // clean up }(sangu_ready, (typeof GM_xmlhttpRequest === "undefined" ? undefined : GM_xmlhttpRequest))); }