// ==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 // @downloadURL https://update.greasyfork.icu/scripts/32615/Sangu%20Package.user.js // @updateURL https://update.greasyfork.icu/scripts/32615/Sangu%20Package.meta.js // ==/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: "package@sangu.be", /** * 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." + "

" + "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: "Controleer eerst of er een update is!
" + "Foutmelding: {error}
" + "Details:
" + "" + "

Je kan de bug hier melden." + "
Of je kan de bug mailen." + "

Een bug waarvan we niet weten dat ie bestaat zal ook niet gefixed worden!
" + "
Geef zoveel mogelijk informatie mee bij het sturen van een bugrapport!!!
", activatePackageWithCompatibility: "Sangu Package (v{version}) mogelijk incompatibel met huidige TW versie", firstTimeRun: "Welkom! 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: "Laat je looptijden uitrekenen door Sangu!
" + "Gebruik de nieuwe kolom uiterst rechts om de looptijden tot een ingegeven doeldorp te berekenen.
" + "
Je kan de eenheden icons ({unitIcon}) aanklikken om de snelheid van de traagste eenheid te wijzigen." + "" + "
Klikken wijzigt de snelheid op de huidige pagina. " + "
Dubbelklikken wijzigt de snelheid op alle pagina's." + "
" + "
De cellen met de groene en rode rand geven de huidige traagst eenheid-snelheid aan." + "

De iconen in de 'Opdracht' kolom:" + "
Gebruik om een rij te verwijderen." + "
Gebruik 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: "Alle dorpen met minstens {requiredDiff}k bevolking minder dan {to}k
" + "(configuratie wijzigbaar bij Sangu instellingen)", 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: "
(configuratie wijzigbaar bij Sangu instellingen)" }, 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 = "" + twDurationFormat(dist.travelTime) + ""; dist.isNightBonus = true; } else { var displayTime = twDateFormat(dist.arrivalTime); if (speed != 'merchant' && dist.isNightBonus) { displayTime = "" + displayTime + ""; } 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 = '' + formatNumber(totalFarm); if (stackOptions.showFarmLimit && world_config.farmLimit > 0) { stackDesc += ' / ' + formatNumber(farmSize); } if (stackOptions.percentage) { stackDesc += ' (' + stackOptions.percentage + ')'; } 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 $('
').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('
' + '

' + '' + content.title + '

' + '
' + content.body + '
' + '
'); $("."+id+"closeTooltip", "#" + id).click(function() { $("#" + id).hide(); if (options.showOnce) { pers.setGlobal(persKey, "1"); } }); } } function createSpoiler(button, content, opened) { return "
" + content + "
"; } function createMoveableWidget(id, title, content) { return '

' + title + '

' + content + '
'; } function printCoord(village, desc) { if (server_settings.coordinateLinkAllowed) { return "" + desc + ""; } else { return "" + desc + " "; } } // 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("  "+trans.sp.sp.removeScriptWarning+""); $("#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( " "); // 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}", "")}; createFixedTooltip("sanguActivatorTooltip", content, options); }()); } else { (function() { var position = $("#storage").position(), options = { left: position.left - 150, top: position.top + 35 }, content = {body: 'Sangu stelt zijn nieuwste tool voor: TW Tactics!

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} {difference})", 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 = ""; cell += " "; $("#menu_row2").append("" + cell + ""); $("#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 = ""; 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 += ""; } 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("").attr("slowestUnit", slowest_unit); } if (ownFarmTotal > 0 && user_data.overview.ajaxSeperateSupportStacks) { // stack in the village unitTable.find("table:first").append(""); } if (totalFarm - ownFarmTotal > 0) { // stack from other villages supportingTroopsTable += ""; if (user_data.overview.ajaxSeperateSupportStacks) { (function() { var supportDisplay = stackDisplay(totalFarm - ownFarmTotal, { showFarmLimit: true }); supportingTroopsTable += ''; }()); } unitTable.after(createMoveableWidget("os_units", trans.sp.main.unitsOther, supportingTroopsTable + "
" + unitLabel.prev().outerHTML() + " " + formatNumber(supportingTroopsAmount) + " " + unitDesc + "
" + stackDisplay(ownFarmTotal).desc + "
» " + trans.sp.main.rallyPointTroops + "
' + '' + '' + supportDisplay.desc + '' + '
")); } // 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 = '' + '' + trans.tw.all.farm + ': ' + stackDetails.desc + '' + ''; cellContent = ' | ' + trans.tw.all.farm + ': ' + stackDetails.desc + ''; $("#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(""); $("#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 = ""; dodgeMenu += ''; dodgeMenu += " "; dodgeMenu += ''; dodgeMenu += ""; dodgeMenu += trans.sp.tagger.renameTo + ""; dodgeMenu += "" + trans.sp.tagger.slowest + ""; dodgeMenu += ""; dodgeMenu += ""; if (slowest_unit != null) { dodgeMenu += ""; } dodgeMenu += ""; 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 = $(""); 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 = $("").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 = ""; header += " "; header += ""; row.replaceWith("" + header + "" + trans.sp.tagger.incomingTroops + "" + trans.sp.tagger.arrival + "" + trans.sp.tagger.arrival + "" + trans.sp.tagger.dodgeTime + " " + ""); $("#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:first", row).text() + ""); $("#selectAllIgnore").click(function () { var ingoreBoxes = $("input[name^='id_']", incomingTable); var isChecked = $("#selectAllIgnore").is(":checked"); ingoreBoxes.each(function() { $(this).attr("checked", isChecked); }); }); row.prepend("# " + amountOfAttacks + "").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("# " + amountOfAttacks + ""); } else { row.prepend(" "); } row.before(" " + trans.sp.tagger.switchModus + ""); $("#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(" "); } row.find("td:last").attr("colspan", 5); } else { // normal incoming rows var checkboxCell = "" + twDurationFormat(dodgeTime.totalSecs / 2 / 60) + ""); amountOfAttacks++; } else { row.append(" "); } // 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(" "); } row.prepend(checkboxCell + ">"); 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 = "
"; newLayout += "
"; 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( ''); } } }); // 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( "
" + trans.sp.main.showHiddenDivs.replace("{amount}", currentlyHidden.length) + "" ); $("#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( "
" + header.html() + "
" + isDodge[1] + "
"); 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('
'); input = input.substr(input.lastIndexOf('/') + 1); $(this).append('
'); $(this).append('
'); }); } } 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 = $("") .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("" + trans.tw.main.loyaltyHeader + " " + loyalty.html() + ""); } }); } 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("" + trans.sp.snob.canProduce + "" + canProduce + " " + "+ " + stored + ""); } 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("" + trans.sp.tagger.sentOn + "" + trans.sp.tagger.ago + ""); 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("" + twDateFormat(newDate, true) + "" + sendAt + ""); // 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( ""); $("#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("  " + 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("" + trans.sp.command.returnOn + "" + twDateFormat(returnTime, true, true).substr(3) + ""); 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("  " + returnTimeCell.text() + ""); } } else { var imgType = type.indexOf(trans.tw.command.abortedOperation) == 0 ? imgType = "cancel" : "return"; arrivalCell.prepend("  " + 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('
'+ trans.sp.command.precedingAttack + '
'); } else { content_value.find("h2").after('
XX
'); } if (counter != arraylengthminusone){ $("#lastattack").after(''+ trans.sp.command.nextAttack+ ''); } else { $("#lastattack").after('XX'); } //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(''); unitTable.find("tr:last").append('' + formatNumber(totalPop) + ''); } } 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 += "  " + dist.html + ""; } // 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 += "
"; } htmlStr += printCoord(target, "» " + trans.sp.all.target + ": " + target.x + "|" + target.y) + "  " + dist.html + ""; } if (htmlStr.length > 0) { targetLocation.append("" + htmlStr + ""); } // 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("" + trans.sp.all.total + ": " + formatNumber(sent.wood) + "  " + formatNumber(sent.stone) + "  " + formatNumber(sent.iron) + ""); } } } } catch (e) { handleException(e, "market"); } }()); break; case "settings": // Add sangu to the menu (function() { var settingsMenu = $("table.vis:first", content_value); settingsMenu.append( " Sangu Package"); settingsMenu.append( "" + "" + trans.sp.sp.settings.importSettings + "" + "" + "" + "" + trans.sp.sp.settings.exportSettings + "" + ""); settingsMenu.after( "
" + "" + "
" + "Sangu Website" + "
" + "
"); /** * 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 + "

" + ""); } 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("
"); $("#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("" + trans.sp.rest.sittingAttackTill + "" + (tillTime.getDate() + "." + pad(tillTime.getMonth() + 1, 2) + "." + tillTime.getFullYear()) + ""); } 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 = $('"); $("#textsArea").append("
"); $("#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 = ""; menu += "
"; menu += " " + trans.sp.buildOverview.optimistic + " "; menu += ""; menu += ""; menu += "
"; 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 = ""; menu += "
"; menu += ""; menu += " " + trans.sp.smithOverview.optimistic + " "; menu += ""; menu += ""; menu += "
"; $("#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 += "
"; menu += trans.sp.defOverview.village + " "; menu += ""; menu += " F "; menu += ""; menu += "  |  "; menu += ""; menu += "
"; menu += " " + trans.sp.commands.filtersReverseInfo + ": "; menu += "  "; menu += ""; menu += "  "; menu += "  "; menu += "  "; menu += "  "; menu += "  "; menu += ""; menu += "
"; var selectAllRow = $("#group_assign_table tr:last"); $("#group_assign_table").before(menu).after("
" + selectAllRow.text() + "
"); 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}", "") + targetVillage.coord + ""); if (isAlreadyVisible) { $("#filterContext").html(distanceHeader); } else { $("#group_assign_table").find("th:first").after("" + distanceHeader + " "); $(".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("" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + ""); } else { mainRow.find("td:eq(1)").html("" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + ""); } }, { 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 = ""; menu += "
"; menu += ""; menu += " "; menu += ""; menu += ""; if (!isSupport) { menu += "  "; } else { menu += ""; menu += ""; menu += ""; menu += ""; menu += ""; menu += trans.sp.defOverview.village + " "; menu += ""; // TODO: untranslated F(ields) menu += " F "; menu += ""; menu += ""; menu += " "; //menu += "
"; } menu += ""; menu += "
"; menu += isSupport ? trans.sp.defOverview.extraFiltersSupport : trans.sp.defOverview.extraFiltersDefense; menu += ""; menu += " " + trans.sp.defOverview.extraFiltersInfo; menu += ""; menu += " "; menu += ""; menu += "  "; menu += "    "; menu += "     "; menu += "  "; menu += ""; menu += ""; menu += ""; menu += "
"; 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}", "") + targetVillage.coord + "")); 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("" + trans.sp.defOverview.fieldsPrefix.replace("{0}", parseInt(tag.distance, 10)) + ""); }, { 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( "" + "" + "" + "
" + trans.sp.defOverview.freeText + "
"); $("#textsArea").parent().after(""); } 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 + "
"); $("#closeTextsArea").click(function() { $("#textsArea").parent().parent().remove(); }); }); // Check all villages checkbox replacement $("input.selectAll").replaceWith(""); $("#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() + ' ' + trans.sp.all.fieldsSuffix.replace("{0}", distance) + ''); supportedCell.append(' ' + trans.sp.all.fieldsSuffix.replace("{0}", distance) + ''); 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 += "" + formatNumber(totals[i]) + ""; } else { troopCells += ""; } } self.attr("population", grandTotal); var color = getStackColor(grandTotal); color = "" + formatNumber(grandTotal) + ""; nextRow.before(" " + (isSupport ? trans.sp.defOverview.totalFromOtherVillages : trans.sp.defOverview.totalInOtherVillages) + "" + troopCells + color + ""); } }); 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 += ""; menu += ""; if (location.href.indexOf('type=all') > -1 || location.href.indexOf('&type=') == -1) { menu += ""; } menu += "
"; menu += ""; menu += ""; menu += " " + trans.sp.commands.totalRows + " "; var isSupport = location.href.indexOf('type=support') > -1; menu += ""; menu += ""; menu += ""; if (commandListType !== "attack" && commandListType !== "return") { menu += "   "; menu += " "; menu += ""; } menu += "
"; // second row menu += ""; menu += "
"; menu += " " + trans.sp.commands.filtersReverseInfo + ": "; menu += ""; menu += ""; menu += "       "; menu += "  "; menu += ""; menu += ""; menu += ""; menu += ""; menu += ""; menu += "
"; $("#commands_table").before(menu); $("#select_all").replaceWith(""); 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(""); } } 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(""); } else { alert(trans.sp.commands.exportNone); } } if (exportWidgets.length > 0) { if ($("#textsArea").size() == 0) { $(this).parent().parent().parent().append(""); } else { $("#textsArea").html(""); } for (var i = 0; i < exportWidgets.length; i++) { $("#textsArea").append(exportWidgets[i]); } $("#textsArea").append("
"); $("#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 += "" + value.html() + ""; 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 += "" + trans.sp.commands.totalRowsText.replace("{0}", amount).replace("{1}", formatNumber(totalDef['pop'])) + " "; $.each(world_data.units, function (iUnit, vUnit) { newTable += "" + (totalDef[vUnit] == 0 ? " " : formatNumber(totalDef[vUnit])) + ""; }); newTable += ""; } }); } 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 += ""; $(this).find("td").each(function (i) { if (i == 2) { newTable += " "; } else if ($(this).text() == 0) { newTable += "0"; } else { newTable += "" + $(this).html() + ""; } }); newTable += ""; } else { newTable += "" + value.html() + ""; } lastArrival = currentArrival; amount++; }); if (sum) { newTable += "" + amount + " "; } }); } var menu = $("#commands_table tr").first().html(), totalRow = $("#commands_table tr:last"); $("#commands_table").html("" + menu + newTable + totalRow.outerHTML() + "
"); $("#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("
" + totalVillagesDesc + "
" + totalDesc + ":" + amountOfCommandos + "
"); } else { pageSize[0].id = "amountOfTargets"; pageSize.parent().prev().text(totalVillagesDesc); pageSize = pageSize.val(targets.length).parent().parent().parent(); pageSize.append('' + totalDesc + ':' + amountOfCommandos + ''); } } 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('' + trans.sp.incomings.amount + '' + rowCount + ''); } else { $("#amountOfRows").text(villagesTargeted); $("#villagesTargeted").val(villagesTargeted); } } } }; var columnsToFilterCount = 5; // build sangu menu var menu = ""; menu += ""; menu += ""; menu += "
"; menu += ""; menu += ""; menu += " " + trans.sp.incomings.summation + " "; menu += ""; menu += ""; menu += ""; menu += ""; menu += ""; menu += ""; menu += ""; menu += "
"; // second row menu += ""; menu += ""; // 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 = ""; return menu; } menu += buildColumnFilter(); //menu += ""; menu += "
"; menu += " " + trans.sp.commands.filtersReverseInfo + ": "; menu += ""; menu += ""; menu += ""; menu += ""; menu += ""; //menu += ""; //menu += "
"; 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(""); $("#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(""); $("#textsArea").append( "" + "
" + "" + ""); $("#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(""+trans.sp.incomings.attackId+""+trans.sp.incomings.attackIdDifference+""); 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(""+attackId+""+diffDescription+""); }); }); // 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 += "" + row.html() + ""; amount++; }); if (addTotalRow) { if (amount === 1) { newTable += " "; } else { newTable += "" + trans.sp.incomings.amount + "  " + amount + "   "; } } }); var menu = $("tr:first", overviewTable).html(); var totalRow = $("tr:last", overviewTable).html(); overviewTable.html("" + menu + newTable + totalRow + "
"); 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("  "); } }); } 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("  "); } }); } 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("  "); } }); } 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("  "); imageToAdd = "graphic/group_left.png"; break; case 9: imageToAdd = "graphic/premium/coinbag_14x14.png"; overviewLink.parent().width(150); break; } if (imageToAdd !== "") { overviewLink.prepend("  "); } }); } } var logoffLink = $("#linkContainer a:last"); if (user_data.global.duplicateLogoffLink) { $("#linkContainer a:first").after(" - ").after(logoffLink.clone()); } logoffLink.before(""+trans.sp.sp.moreScripts+"") .before(" - Sangu Package - "); (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}", "")}; createFixedTooltip("incomingsIndicatorHelp", content, options); } // change last incomings-check time incomingAttacksLinks.last().parent().after( " " + " "); // 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 = $(""); friendsLink.html( trans.sp.rest.friendsOnline .replace("{friends}", friendsLink.text()) .replace("{onlineimg}", "") .replace("{online#}", friends.online.amount) .replace("{offlineimg}", "") .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))); }