Greasy Fork is available in English.

hwmHuntHelper

Помощник ГО

// ==UserScript==
// @name           hwmHuntHelper
// @namespace      Tamozhnya1
// @description    Помощник ГО
// @author         Mantens, ElMarado, CheckT, Pagan of Dark, Tamozhnya1
// @version        13.5
// @include        https://www.heroeswm.ru/group_wars.php*
// @include        https://www.heroeswm.ru/plstats_hunters.php*
// @include        https://www.heroeswm.ru/home.php*
// @include        https://www.heroeswm.ru/map.php*
// @include        https://www.heroeswm.ru/mercenary_guild.php*
// @include        https://www.lordswm.com/group_wars.php*
// @include        https://www.lordswm.com/plstats_hunters.php*
// @include        https://www.lordswm.com/home.php*
// @include        https://www.lordswm.com/map.php*
// @include        https://www.lordswm.com/mercenary_guild.php*
// @include        https://www.heroeswm.ru/leader_guild.php*
// @include        https://www.lordswm.com/leader_guild.php*
// @include        https://www.heroeswm.ru/lg_event.php*
// @include        https://www.lordswm.com/lg_event.php*
// @include        https://www.heroeswm.ru/reaping_event.php*
// @include        https://www.lordswm.com/reaping_event.php*
// @include        https://www.heroeswm.ru/tj_single.php*
// @include        https://www.lordswm.com/tj_single.php*
// @include        https://www.heroeswm.ru/pirate_self_event.php*
// @include        https://www.lordswm.com/pirate_self_event.php*
// @include        https://daily.heroeswm.ru/help/gn/monsters.php*
// @grant          GM_getValue
// @grant          GM_setValue
// @grant          GM_deleteValue
// @grant          GM_listValues
// @grant 		   GM.xmlHttpRequest
// @license        MIT
// ==/UserScript==

// Update by CheckT
// небольшая доработка скрипта hwm_GO_exp от ElMarado (Based on script Mantens)
//    - хранение настроек независимо по игрокам
//    - кнопка "пометить всех птиц"
// Оригинал https://greasyfork.org/ru/scripts/11692-hwm-go-exp


const playerIdMatch = document.cookie.match(/pl_id=(\d+)/);
const PlayerId = playerIdMatch ? playerIdMatch[1] : "";
const lang = document.documentElement.lang || (location.hostname == "www.lordswm.com" ? "en" : "ru");
const isEn = lang == "en";
const win = window.wrappedJSObject || unsafeWindow;
const isHeartOnPage = (document.querySelector("canvas#heart") || document.querySelector("div#heart_js_mobile")) ? true : false;
const isMooving = location.pathname == '/map.php' && !document.getElementById("map_right_block");
const isNewInterface = document.querySelector("div#hwm_header") ? true : false;
const isMobileInterface = document.querySelector("div#btnMenuGlobal") ? true : false;
const isMobileDevice = mobileCheck(); // Там нет мышки
const isNewPersonPage = document.querySelector("div#hwm_no_zoom") ? true : false;

fetch.get = (url) => fetch({ url });
fetch.post = (url, data) => fetch({ url, method: 'POST', body: data });

if(!PlayerId) {
    return;
}


_NABEG=2;_GN_OTRYAD=5;_GN_MONSTER=7;_GN_NABEGI=8;_GN_ZASHITA=10;_GN_ARMY=12;_MAL_TOUR=14;_THIEF_WAR=16;_SURVIVAL=20;_NEWGROUP=21;
_ELEMENTALS=22;_GNOMES=23;_NEWKZS=24;NEWKZS=24;_NEWKZS_T=25;NEWKZS_T=25;_NEWTHIEF=26;_NEWCARAVAN=27;_NEWGNCARAVAN=29;_SURVIVALGN=28;
_TUNNEL=30;_SEA=32;_HELL=33;_CASTLEWALLS=35;_UNIWAR=36;_DIFFTUR=37;_UNIWARCARAVAN=38;_PVPGUILDTEST=39;_PVPGUILD=40;_BALANCED_EVENT=41;
_NECR_EVENT=42;_NECR_EVENT2=43;_HELLOWEEN=44;_SURVIVAL_GNOM=45;_DEMON_EVENT=46;_DEMON_EVENT2=47;_DEMON_EVENT3=48;_DEMON_EVENT4=49;_PVEDUEL=50;_DEMONVALENTIN=51;
_QUICKTOUR=52;_BARBTE_ATTACK=53;_BARBTE_DEEP=54;_BARBTE_BOSS=55;_TRANSEVENT=56;_STEPEVENT=57;_STEPEVENT2=58;_KZS_PVE=59;_2TUR=60;_RANGER=61;
_PRAET=62;_RANGER_TEST=63;_SUN_EVENT1=64;_SUN_EVENT2=65;_NEWCARAVAN2=66;_23ATTACK=67;_2TU_FAST=68;_SV_ATTACK=69;_KILLER_BOT=70;_SV_DUEL=71;
_SV_WAR=72;_FAST_TEST=73;_TRUE_EVENT=74;_TIKVA_BOT=75;_TIKVA_ATTACK=76;_ELKA_DEFENSE=77;_PPE_EVENT=78;_ALTNECR_EVENT=79;_CLAN_SUR_DEF=80;_CLAN_SUR_ATT=81;
_QUESTWAR=82;_BARBNEW_DEEP=83;_BARBNEW_BOSS=84;_ELKA_RESCUE=85;_REGWAR1=86;_REGWAR2=87;_CLAN_SUR_CAPT=88;_CLAN_SUR_DEF_PVP=89;_TRUE_TOUR=90;_NOOB_DUEL=91;
_ALTMAG_EVENT=92;_ALTELF_EVENT=93;_NEWPORTAL_EVENT=94;_UNIGUILD=95;_PIRATE_EVENT=96;_TOUR_EVENT=97;_PAST_EVENT=98;_GOLD_EVENT=99;_FAST_TEST2=100;_OHOTA_EVENT=101;
_BUNT_EVENT=102;_ZASADA_EVENT=103;_CLAN_NEW_PVP=104;_SURV_DEEP=105;_SURV_DEEP_BOSS=106;_2AND3_EVENT=107;_CASTLE_EVENT=108;_CARAVAN_EVENT=109;_CAMPAIGN_WAR=110;_NY2016=111;
_ALTTE_EVENT=112;_PVP_EVENT=113;_ALTTE2_EVENT=114;_PIRATE_NEW_EVENT=115;_PVP_KR_EVENT=116;_CATCH_EVENT=117;_PVP_DIAGONAL_EVENT=118;_VILLAGE_EVENT=119;_TRAVEL_EVENT=120;_CASTLE_BATTLE2X2=121;
_PVP_BOT=122;_PIRATE_SELF_EVENT=123;_2ZASADA_EVENT=124;_NEWCARAVAN3=125;_ONEDAY_EVENT=126;_CRE_EVENT=127;_GL_EVENT=128;_1ZASADA_EVENT=129;_NYGL2018_EVENT=130;_EGYPT_EVENT=131;
_GL_DWARF_EVENT=132;_NAIM_MAP_EVENT=133;_2BOT_TUR=134;_CRE_SPEC=135;_CRE_INSERT=136;_CRE_TOUR=137;_GNOM_EVENT=138;_MAPHERO_EVENT=138;_NEWCRE_EVENT=139;_NEWOHOTA_EVENT=140;
_2SURVIVAL=141;_ADVENTURE_EVENT=142;_AMBUSHHERO_EVENT=143;_FRACTION_EVENT=144;_PVP_KZS=145;_REAPING_MAP_EVENT=147;


if(location.pathname == "/home.php" || location.pathname == "/pl_info.php" && getUrlParamValue(location.href, "id") == PlayerId) {
    if(isNewPersonPage) {
        const levelInfoCell = Array.from(document.querySelectorAll("div.home_pers_info")).find(x => x.innerHTML.includes(isEn ? "Combat level" : "Боевой уровень"));
        if(levelInfoCell) {
            console.log(levelInfoCell.querySelector("div[id=bartext] > span").innerText)
            setPlayerValue("PlayerLevel", parseInt(levelInfoCell.querySelector("div[id=bartext] > span").innerText));
        }
    } else {
        const levelExec = new RegExp(`<b>${isEn ? "Combat level" : "Боевой уровень"}: (\\d+?)<\\/b>`).exec(document.documentElement.innerHTML);
        if(levelExec) {
            setPlayerValue("PlayerLevel", parseInt(levelExec[1]) || 1);
        }
    }
}
const PlayerLevel = parseInt(getPlayerValue("PlayerLevel", 1));
const sectors = {
    "cx=50&cy=50": 1, //Empire Capital
    "cx=51&cy=50": 2, //East River
    "cx=50&cy=49": 3, //Tiger Lake
    "cx=51&cy=49": 4, //Rogues' Wood
    "cx=50&cy=51": 5, //Wolf Dale
    "cx=50&cy=48": 6, //Peaceful Camp
    "cx=49&cy=51": 7, //Lizard Lowland
    "cx=49&cy=50": 8, //Green Wood
    "cx=49&cy=48": 9, //Eagle Nest
    "cx=50&cy=52": 10, //Portal Ruins
    "cx=51&cy=51": 11, //Dragon Caves
    "cx=49&cy=49": 12, //Shining Spring
    "cx=48&cy=49": 13, //Sunny Sity
    "cx=52&cy=50": 14, //Magma Mines
    "cx=52&cy=49": 15, //Bear Mountain
    "cx=52&cy=48": 16, //Fairy Trees
    "cx=53&cy=50": 17, //Harbour City (Port City)
    "cx=53&cy=49": 18, //Mithril Coast
    "cx=51&cy=52": 19, //GreatWall
    "cx=51&cy=53": 20, //Titans' Valley
    "cx=52&cy=53": 21, //Fishing Village
    "cx=52&cy=54": 22, //Kingdom Capital
    "cx=48&cy=48": 23, //Ungovernable Steppe
    "cx=51&cy=48": 24, //Crystal Garden
    "cx=53&cy=52": 25, //East Island
    "cx=49&cy=52": 26, //The Wilderness
    "cx=48&cy=50": 27 //Sublime Arbor
}
const monsters = [{"name":"bpirate","title":"Абордажники","experience":30,"health":16,"enTitle":"Pirate Fighters"},{"name":"zealot","title":"Адепты","experience":121,"health":80,"enTitle":"Exorcists"},{"name":"hellcharger","title":"Адские жеребцы","experience":136,"health":50,"imageName":"nightmare","enTitle":"Hell horses"},{"name":"zhryak","title":"Адские жнецы","experience":250,"health":99,"enTitle":"Hell reapers"},{"name":"hellhound","title":"Адские псы","experience":33,"health":15,"imageName":"demondog","enTitle":"Wolfhounds"},{"name":"reanimatorup","title":"Адские реаниматоры","experience":43,"health":27,"enTitle":"Infernal reanimators"},{"name":"troglodyteup","title":"Адские троглодиты","experience":7,"health":6,"enTitle":"Infernal Troglodytes"},{"name":"iceelb","title":"Айсберговые элементали","experience":50,"health":90,"canFly":true,"enTitle":"Iceberg elementals"},{"name":"diamondgolem","title":"Алмазные големы","experience":110,"health":60,"enTitle":"Diamond golems"},{"name":"yetiup","title":"Алмасты","experience":400,"health":290,"enTitle":"Almases"},{"name":"angel","title":"Ангелы","experience":330,"health":180,"canFly":true,"enTitle":"Angels"},{"name":"marksman","title":"Арбалетчики","experience":19,"health":10,"enTitle":"Crossbowmen"},{"name":"archangel","title":"Архангелы","experience":390,"health":220,"canFly":true,"enTitle":"Archangels"},{"name":"archdemon","title":"Архидемоны","experience":312,"health":211,"enTitle":"Antichrists"},{"name":"archdevil","title":"Архидьяволы","experience":311,"health":199,"enTitle":"Archdevils"},{"name":"archlich","title":"Архиличи","experience":110,"health":55,"enTitle":"Archliches"},{"name":"archmage","title":"Архимаги","experience":70,"health":30,"enTitle":"Lorekeepers"},{"name":"assassin","title":"Ассасины","experience":33,"health":14,"imageName":"assasin","enTitle":"Poisoners"},{"name":"assida","title":"Ассиды","experience":53,"health":30,"canFly":true,"enTitle":"Ayssids"},{"name":"ghostdragon","title":"Астральные драконы","experience":310,"health":150,"canFly":true,"enTitle":"Mirage dragons"},{"name":"banshee","title":"Баньши","experience":205,"health":110,"enTitle":"Death proclaimers"},{"name":"behemoth","title":"Бегемоты","experience":350,"health":210,"enTitle":"Behemoths"},{"name":"berserker","title":"Берсерки","experience":42,"health":25,"enTitle":"Berserkers"},{"name":"maiden","title":"Бестии","experience":30,"health":16,"enTitle":"Rogues"},{"name":"imp","title":"Бесы","experience":6,"health":4,"enTitle":"Imps"},{"name":"beholder","title":"Бехолдеры","experience":33,"health":22,"enTitle":"Beholders"},{"name":"wisp","title":"Блуждающие огни","experience":7,"health":10,"canFly":true,"enTitle":"Will-O-Wisps"},{"name":"battlegriffin","title":"Боевые грифоны","experience":45,"health":35,"canFly":true,"enTitle":"Frenzied griffins"},{"name":"silverunicorn","title":"Боевые единороги","experience":135,"health":77,"enTitle":"Brilliant unicorns"},{"name":"mcentaur","title":"Боевые кентавры","experience":21,"health":10,"enTitle":"Tempered centaurs"},{"name":"battlemage","title":"Боевые маги","experience":72,"health":29,"enTitle":"Battlemagi"},{"name":"slon","title":"Боевые слоны","experience":120,"health":100,"enTitle":"Fighting elephants"},{"name":"vampire","title":"Вампиры","experience":68,"health":30,"enTitle":"Vampires"},{"name":"warmong","title":"Вармонгеры","experience":36,"health":20,"enTitle":"Protectors"},{"name":"cursed","title":"Ведьмы-призраки","experience":30,"health":20,"canFly":true,"imageName":"cursed_","enTitle":"Cursed witches"},{"name":"priestessup","title":"Ведьмы моря","experience":70,"health":35,"enTitle":"Sea witches"},{"name":"giant","title":"Великаны","experience":160,"health":100,"enTitle":"Trashers"},{"name":"giantarch","title":"Великаны-лучники","experience":130,"health":100,"enTitle":"Giant archers"},{"name":"upleviathan","title":"Великие левиафаны","experience":300,"health":250,"enTitle":"Great leviathans"},{"name":"wendigo","title":"Вендиго","experience":20,"health":25,"enTitle":"Wendigos"},{"name":"druideld","title":"Верховные друиды","experience":101,"health":38,"imageName":"ddeld","enTitle":"Anchorites"},{"name":"wraith","title":"Вестники смерти","experience":205,"health":100,"enTitle":"Death heralds"},{"name":"wyvern","title":"Виверны","experience":170,"health":90,"canFly":true,"enTitle":"Tamed wyverns"},{"name":"djinn_vizier","title":"Визири джиннов","experience":110,"health":50,"canFly":true,"enTitle":"Fortune genies"},{"name":"matriarch","title":"Владычицы тени","experience":185,"health":90,"enTitle":"Dark sibyls"},{"name":"water","title":"Водные элементали","experience":57,"health":43,"enTitle":"Water elementals"},{"name":"chieftain","title":"Вожаки","experience":100,"health":48,"enTitle":"Chieftains"},{"name":"air","title":"Воздушные элементали","experience":59,"health":30,"canFly":true,"enTitle":"Air elementals"},{"name":"anubisup","title":"Воины Анубиса","experience":420,"health":200,"enTitle":"Anubis warriors"},{"name":"battlerager","title":"Воины ярости","experience":42,"health":30,"enTitle":"Beastslayers"},{"name":"mercfootman","title":"Воины-наёмники","experience":25,"health":24,"enTitle":"Mercenary warriors"},{"name":"shieldguard","title":"Воители","experience":12,"health":12,"enTitle":"Veterans"},{"name":"faeriedragon","title":"Волшебные драконы","experience":800,"health":500,"canFly":true,"enTitle":"Faerie dragons"},{"name":"thiefmage","title":"Воры-колдуны","experience":35,"health":30,"enTitle":"Renegade magicians"},{"name":"thiefwarrior","title":"Воры-разведчики","experience":35,"health":45,"enTitle":"Renegade scouts"},{"name":"thiefarcher","title":"Воры-убийцы","experience":35,"health":40,"enTitle":"Renegade thugs"},{"name":"seraph2","title":"Высшие ангелы","experience":390,"health":220,"canFly":true,"enTitle":"Thrones"},{"name":"vampirelord","title":"Высшие вампиры","experience":70,"health":35,"enTitle":"Vampire counts"},{"name":"masterlich","title":"Высшие личи","experience":100,"health":55,"enTitle":"Demiliches"},{"name":"highwayman","title":"Вышибалы","experience":30,"health":24,"enTitle":"Bruisers"},{"name":"harpy","title":"Гарпии","experience":29,"health":15,"canFly":true,"enTitle":"Harpies"},{"name":"harpyhag","title":"Гарпии-ведьмы","experience":45,"health":15,"canFly":true,"enTitle":"Raiding harpies"},{"name":"harpooner","title":"Гарпунеры","experience":18,"health":10,"enTitle":"Harpooners"}
,{"name":"hydra","title":"Гидры","experience":108,"health":80,"enTitle":"Hydras"},{"name":"darkeye","title":"Глаза тьмы","experience":33,"health":26,"enTitle":"Shadow eyes"},{"name":"upseamonster","title":"Глубоководные черти","experience":140,"health":105,"enTitle":"Voracious anglerfish"},{"name":"rotzombie","title":"Гниющие зомби","experience":17,"health":23,"enTitle":"Ghouls"},{"name":"goblin","title":"Гоблины","experience":5,"health":3,"enTitle":"Goblins"},{"name":"goblinarcher","title":"Гоблины-лучники","experience":9,"health":3,"enTitle":"Goblin archers"},{"name":"goblinmag","title":"Гоблины-маги","experience":9,"health":3,"enTitle":"Goblin warlocks"},{"name":"trapper","title":"Гоблины-трапперы","experience":15,"health":7,"enTitle":"Goblin trappers"},{"name":"gogachi","title":"Гоги","experience":13,"health":13,"imageName":"gog","enTitle":"Gogs"},{"name":"dgolem","title":"Големы смерти","experience":329,"health":350,"enTitle":"Death golems"},{"name":"brute","title":"Головорезы","experience":6,"health":8,"enTitle":"Brutes"},{"name":"mountaingr","title":"Горные стражи","experience":24,"health":12,"enTitle":"Mountain sentries"},{"name":"gremlin","title":"Гремлины","experience":5,"health":5,"enTitle":"Gremlins"},{"name":"saboteurgremlin","title":"Гремлины-вредители","experience":9,"health":6,"enTitle":"Gremlin wreckers"},{"name":"griffon","title":"Грифоны","experience":59,"health":30,"canFly":true,"enTitle":"Griffins"},{"name":"thunderlord","title":"Громовержцы","experience":162,"health":120,"enTitle":"Invokers"},{"name":"axegnom","title":"Громоглавы","experience":14,"health":10,"enTitle":"Thunderheads"},{"name":"nomadup","title":"Гунны","experience":60,"health":33,"enTitle":"Huns"},{"name":"deserter","title":"Дезертиры","experience":40,"health":25,"enTitle":"Deserters"},{"name":"succubusmis","title":"Демонессы","experience":67,"health":30,"imageName":"succubusm","enTitle":"Mistresses"},{"name":"smalllizard","title":"Детёныши ящера","experience":13,"health":13,"imageName":"smalllizard_","enTitle":"Lizard cubs"},{"name":"djinn","title":"Джинны","experience":103,"health":40,"canFly":true,"enTitle":"Genies"},{"name":"djinn_sultan","title":"Джинны-султаны","experience":110,"health":45,"canFly":true,"enTitle":"Senior genies"},{"name":"savageent","title":"Дикие энты","experience":210,"health":175,"enTitle":"Savage Treant"},{"name":"robber","title":"Дозорные","experience":7,"health":5,"enTitle":"Outriders"},{"name":"eadaughter","title":"Дочери земли","experience":72,"health":35,"enTitle":"Earth shamans"},{"name":"sdaughter","title":"Дочери неба","experience":75,"health":35,"enTitle":"Sky shamans"},{"name":"ancientbehemoth","title":"Древние бегемоты","experience":390,"health":250,"imageName":"abehemoth","enTitle":"Ancient Behemoths"},{"name":"ancientpig","title":"Древние кабаны","experience":12,"health":15,"enTitle":"Ancient boars"},{"name":"amummy","title":"Древние мумии","experience":135,"health":80,"enTitle":"Ancient mummies"},{"name":"ancienent","title":"Древние энты","experience":210,"health":181,"enTitle":"Ironroot treefolk"},{"name":"sprite","title":"Дриады","experience":20,"health":6,"canFly":true,"enTitle":"Sprites"},{"name":"druid","title":"Друиды","experience":74,"health":34,"imageName":"dd_","enTitle":"Druids"},{"name":"poltergeist","title":"Духи","experience":27,"health":20,"canFly":true,"enTitle":"Poltergeists"}
,{"name":"ocean","title":"Духи океана","experience":53,"health":30,"canFly":true,"enTitle":"Ocean spirits"},{"name":"devil","title":"Дьяволы","experience":245,"health":166,"enTitle":"Devils"},{"name":"vermin","title":"Дьяволята","experience":10,"health":6,"enTitle":"Vermins"},{"name":"unicorn","title":"Единороги","experience":124,"health":57,"enTitle":"Unicorns"},{"name":"iron_golem","title":"Железные големы","experience":33,"health":18,"imageName":"golem","enTitle":"Golems"}
,{"name":"runepriest","title":"Жрецы рун","experience":59,"health":60,"enTitle":"Priests"}
,{"name":"runekeeper","title":"Жрецы пламени","experience":100,"health":65,"enTitle":"Ascetics"}
,{"name":"priestmoon","title":"Жрицы луны","experience":60,"health":50,"enTitle":"Moon Priestesses","imageName":"zhrica"},{"name":"priestess","title":"Жрицы моря","experience":70,"health":35,"enTitle":"Sea priestesses"},{"name":"priestsun","title":"Жрицы солнца","experience":70,"health":55,"enTitle":"Sun Priestesses","imageName":"zhricaup"},{"name":"vindicator","title":"Защитники веры","experience":20,"health":23,"enTitle":"Crusaders"},{"name":"defender","title":"Защитники гор","experience":7,"health":7,"enTitle":"Sentries"},{"name":"greendragon","title":"Зелёные драконы","experience":350,"health":200,"canFly":true,"enTitle":"Green dragons"},{"name":"earth","title":"Земные элементали","experience":63,"health":75,"enTitle":"Earth elementals"},{"name":"evileye","title":"Злобные глаза","experience":33,"health":22,"enTitle":"Evil eyes"},{"name":"zombie","title":"Зомби","experience":11,"health":17,"enTitle":"Zombies"},{"name":"emeralddragon","title":"Изумрудные драконы","experience":400,"health":200,"canFly":true,"enTitle":"Jade dragons"},{"name":"impergriffin","title":"Имперские грифоны","experience":62,"health":35,"canFly":true,"enTitle":"Royal griffins"},{"name":"inquisitor","title":"Инквизиторы","experience":121,"health":80,"enTitle":"Clerics"},{"name":"seducer","title":"Искусительницы","experience":65,"health":26,"enTitle":"Temptresses"},{"name":"efreeti","title":"Ифриты","experience":200,"health":90,"canFly":true,"enTitle":"Efreeti"},{"name":"efreetisultan","title":"Ифриты султаны","experience":250,"health":100,"canFly":true,"enTitle":"Efreeti sultans"},{"name":"yeti","title":"Йети","experience":400,"health":280,"enTitle":"Yeties"},{"name":"boar","title":"Кабаны","experience":12,"health":17,"enTitle":"Boars"},{"name":"stone_gargoyle","title":"Каменные горгульи","experience":16,"health":15,"canFly":true,"imageName":"gargoly","enTitle":"Gargoyles"},{"name":"kammon","title":"Каменные монстры","experience":20,"health":28,"enTitle":"Stone monsters"},{"name":"kamnegryz","title":"Камнегрызы","experience":67,"health":55,"enTitle":"Stonegnawers"},{"name":"kamneed","title":"Камнееды","experience":56,"health":45,"enTitle":"Stoneeaters"},{"name":"fcentaur","title":"Кентавры","experience":13,"health":6,"enTitle":"Centaurs"},{"name":"vampireprince","title":"Князья вампиров","experience":70,"health":40,"enTitle":"Dreadlords"},{"name":"outlaw","title":"Колдуны-ренегаты","experience":6,"health":6,"enTitle":"Turncoat Mages"},{"name":"colossus","title":"Колоссы","experience":350,"health":175,"enTitle":"Giants"},{"name":"hellkon","title":"Кони преисподней","experience":138,"health":66,"imageName":"hellstallion","enTitle":"Searing horses"},{"name":"piratkaup","title":"Корсарки","experience":32,"health":12,"enTitle":"Women corsairs"},{"name":"apirate","title":"Корсары","experience":16,"health":13,"enTitle":"Corsairs"},{"name":"brawler","title":"Костоломы","experience":27,"health":20,"enTitle":"Brawlers"},{"name":"bonedragon","title":"Костяные драконы","experience":280,"health":150,"canFly":true,"enTitle":"Skeletal dragons"},{"name":"nomad","title":"Кочевники","experience":50,"health":30,"enTitle":"Nomads"},{"name":"ncentaur","title":"Кочевые кентавры","experience":20,"health":9,"enTitle":"Centaur outriders"},{"name":"nightmare","title":"Кошмары","experience":140,"health":66,"imageName":"stallion","enTitle":"Nightmares"},{"name":"reddragon","title":"Красные драконы","experience":400,"health":235,"canFly":true,"enTitle":"Red dragons"},{"name":"peasant","title":"Крестьяне","experience":5,"health":4,"imageName":"paesant","enTitle":"Farmers"},{"name":"crusader","title":"Крестоносцы","experience":27,"health":30,"enTitle":"Templars"},{"name":"crystaldragon","title":"Кристальные драконы","experience":400,"health":200,"canFly":true,"enTitle":"Crystal Dragons"},{"name":"redlizard","title":"Кровавые ящеры","experience":30,"health":35,"imageName":"redlizard_","enTitle":"Vampiric lizards"},{"name":"bloodeyecyc","title":"Кровоглазые циклопы","experience":500,"health":235,"enTitle":"Tribal beholders"},{"name":"rakshasa_kshatra","title":"Кшатрии ракшасы","experience":162,"health":135,"enTitle":"Sphynx immortals"},{"name":"lavadragon","title":"Лавовые драконы","experience":329,"health":275,"enTitle":"Core dragons"},{"name":"scout","title":"Лазутчики","experience":20,"health":10,"enTitle":"Bandits"},{"name":"banditka","title":"Лазутчицы","experience":12,"health":8,"enTitle":"Infiltrators"},{"name":"squire","title":"Латники","experience":21,"health":26,"imageName":"swordman","enTitle":"Guardians"},{"name":"leviathan","title":"Левиафаны","experience":250,"health":200,"enTitle":"Leviathans"}
,{"name":"leprekon","title":"Лепреконы","experience":11,"health":7,"imageName":"lepr","enTitle":"Leprechauns"},{"name":"arcaneelf","title":"Лесные снайперы","experience":42,"health":12,"enTitle":"Sharpshooters"},{"name":"bobbit","title":"Лесные хоббиты","experience":9,"health":6,"enTitle":"Forest hobbits"},{"name":"shaman","title":"Лесные шаманы","experience":200,"health":110,"enTitle":"Forest shamans"},{"name":"lich","title":"Личи","experience":87,"health":50,"enTitle":"Liches"},{"name":"stalker","title":"Ловчие","experience":34,"health":15,"enTitle":"Stalkers"},{"name":"archer","title":"Лучники","experience":15,"health":7,"enTitle":"Bowmen"},{"name":"mage","title":"Маги","experience":63,"health":18,"enTitle":"Magi"},{"name":"magicel","title":"Магические элементали","experience":200,"health":80,"enTitle":"Magic elementals"},{"name":"magmadragon","title":"Магма драконы","experience":329,"health":280,"enTitle":"Magma dragons"},{"name":"magneticgolem","title":"Магнитные големы","experience":57,"health":28,"enTitle":"Lodestone golems"},{"name":"megogachi","title":"Магоги","experience":16,"health":13,"imageName":"magog","enTitle":"Magogs"},{"name":"raremamont","title":"Мамонты","experience":160,"health":110,"enTitle":"Mammoths","imageName":"mamont"},{"name":"manticore","title":"Мантикоры","experience":130,"health":80,"canFly":true,"enTitle":"Manticores"},{"name":"skirmesher","title":"Мастера копья","experience":17,"health":12,"enTitle":"Master spearmen"},{"name":"masterhunter","title":"Мастера лука","experience":42,"health":14,"imageName":"hunterelf","enTitle":"Grandmaster bowmen"},{"name":"negro","title":"Матросы-чужеземцы","experience":24,"health":17,"enTitle":"Sailors-strangers"},{"name":"bloodsister","title":"Мегеры","experience":49,"health":24,"enTitle":"Termagants"},{"name":"bear","title":"Медведи","experience":22,"health":22,"enTitle":"Bears"},{"name":"medusa","title":"Медузы","experience":45,"health":25,"enTitle":"Medusas"},{"name":"medusaup","title":"Медузы королевы","experience":55,"health":30,"enTitle":"Medusas Queens"},{"name":"spearwielder","title":"Метатели копья","experience":11,"health":10,"enTitle":"Spearmen"},{"name":"minotaur","title":"Минотавры","experience":39,"health":31,"enTitle":"Tamed minotaurs"},{"name":"minotaurguard","title":"Минотавры-стражи","experience":56,"health":35,"imageName":"minotaurguard_","enTitle":"Minotaur soldiers"},{"name":"taskmaster","title":"Минотавры-надсмотрщики","experience":56,"health":40,"enTitle":"Minotaur gladiators"},{"name":"dgolemup","title":"Могильные големы","experience":400,"health":400,"enTitle":"Sepulcher golems"},{"name":"cbal","title":"Мобильные баллисты","experience":100,"health":65,"enTitle":"Mobile ballista"},{"name":"gnomon","title":"Молотобойцы","experience":12,"health":9,"enTitle":"Warhammerers"},{"name":"priest","title":"Монахи","experience":101,"health":54,"enTitle":"Monks"},{"name":"piratemonster","title":"Морские дьяволы","experience":300,"health":190,"enTitle":"Sailors` devil"},{"name":"seamonster","title":"Морские черти","experience":120,"health":90,"enTitle":"Anglerfish"},{"name":"mummy","title":"Мумии","experience":115,"health":50,"enTitle":"Mummies"},{"name":"pharaoh","title":"Мумии фараонов","experience":135,"health":70,"enTitle":"Sphynx mummies"},{"name":"enforcer","title":"Мятежники","experience":10,"health":7,"enTitle":"Rebels"},{"name":"naga","title":"Наги","experience":160,"health":110,"enTitle":"Nagas"},{"name":"dromad","title":"Наездники на верблюдах","experience":60,"health":40,"enTitle":"Camel riders"},{"name":"wolfrider","title":"Наездники на волках","experience":20,"health":10,"enTitle":"Wolf Riders"},{"name":"hyenarider","title":"Наездники на гиенах","experience":31,"health":13,"enTitle":"Hyena riders"},{"name":"boarrider","title":"Наездники на кабанах","experience":31,"health":14,"enTitle":"Boar riders"},{"name":"bearrider","title":"Наездники на медведях","experience":24,"health":25,"enTitle":"Dwarven ursary"},{"name":"darkrider","title":"Наездники на ящерах","experience":65,"health":40,"imageName":"lizardrider","enTitle":"Lizard cavalry"},{"name":"dromadup","title":"Налетчики на верблюдах","experience":70,"health":45,"enTitle":"Camel raiders"},{"name":"wolfraider","title":"Налётчики на волках","experience":31,"health":12,"imageName":"hobwolfrider","enTitle":"Wolf Raiders"},{"name":"reptiloid","title":"Никсы","experience":110,"health":80,"enTitle":"Nixes"},{"name":"reptiloidup","title":"Никсы-воины","experience":180,"health":90,"enTitle":"Nix warriors"},{"name":"dryad","title":"Нимфы","experience":20,"health":6,"canFly":true,"imageName":"dryad_","enTitle":"Dryads"},{"name":"obsgargoyle","title":"Обсидиановые горгульи","experience":26,"health":20,"canFly":true,"imageName":"obsgargoly","enTitle":"Enchanted gargoyles"},{"name":"hotdog","title":"Огненные гончие","experience":36,"health":15,"imageName":"firehound","enTitle":"Blazing hounds"},{"name":"hornedoverseer","title":"Огненные демоны","experience":23,"health":13,"imageName":"fdemon","enTitle":"Incendiaries"},{"name":"firedragon","title":"Огненные драконы","experience":255,"health":230,"enTitle":"Lava dragons"},{"name":"firebird","title":"Огненные птицы","experience":117,"health":65,"canFly":true,"imageName":"firebird_","enTitle":"Firebirds"},{"name":"fire","title":"Огненные элементали","experience":60,"health":43,"enTitle":"Fire elementals"},{"name":"ogre","title":"Огры","experience":60,"health":50,"enTitle":"Ogres"},{"name":"ogrebrutal","title":"Огры-ветераны","experience":75,"health":70,"enTitle":"Ogre trophy-hunters"},{"name":"ogremagi","title":"Огры-маги","experience":74,"health":65,"enTitle":"Ogre magi"},{"name":"ogreshaman","title":"Огры-шаманы","experience":74,"health":55,"enTitle":"Ogre shamans"},{"name":"fatpirateup","title":"Одноглазые пираты","experience":190,"health":120,"enTitle":"One-eyed pirates"},{"name":"conscript","title":"Ополченцы","experience":7,"health":6,"enTitle":"Recruits"},{"name":"orc","title":"Орки","experience":29,"health":12,"enTitle":"Orcs"},{"name":"orcchief","title":"Орки-вожди","experience":38,"health":18,"enTitle":"Orc chiefs"},{"name":"orcrubak","title":"Орки-тираны","experience":38,"health":20,"enTitle":"Orc tyrants"},{"name":"orcshaman","title":"Орки-шаманы","experience":33,"health":13,"enTitle":"Orc shamans"},{"name":"paladin","title":"Паладины","experience":262,"health":100,"enTitle":"Paladins"},{"name":"executioner","title":"Палачи","experience":83,"health":40,"enTitle":"Warlords"},{"name":"spider","title":"Пауки","experience":15,"health":9,"enTitle":"Spiders"},{"name":"footman","title":"Пехотинцы","experience":17,"health":16,"enTitle":"Swordsmen"},{"name":"pitlord","title":"Пещерные владыки","experience":195,"health":120,"imageName":"pitlord_","enTitle":"Pit demons"},{"name":"deephydra","title":"Пещерные гидры","experience":115,"health":125,"enTitle":"Ladons"},{"name":"pitfiend","title":"Пещерные демоны","experience":157,"health":110,"imageName":"pitfiend_","enTitle":"Cave demons"},{"name":"pity","title":"Пещерные отродья","experience":165,"health":140,"imageName":"pitspawn","enTitle":"Abyss demons"},{"name":"piratka","title":"Пиратки","experience":20,"health":10,"enTitle":"Women pirates"},{"name":"zpirate","title":"Пираты зомби","experience":200,"health":150,"enTitle":"Zombie pirates"},{"name":"piratemonsterup","title":"Пираты Ктулху","experience":350,"health":200,"enTitle":"Pirates of Cthulhu"},{"name":"piroman","title":"Пироманьяки","experience":10,"health":20,"enTitle":"Pyromaniacs"},{"name":"hungerplant","title":"Пожиратели плоти","experience":130,"health":70,"enTitle":"Flesh-eating trees"},{"name":"ghost","title":"Привидения","experience":26,"health":8,"canFly":true,"enTitle":"Ghosts"},{"name":"spearthrower","title":"Прибрежные налётчики","experience":10,"health":19,"enTitle":"Coastal raiders","imageName":"jpirate"},{"name":"spectre","title":"Призраки","experience":27,"health":19,"canFly":true,"enTitle":"Apparitions"},{"name":"gpiratka","title":"Призраки пираток","experience":17,"health":8,"canFly":true,"enTitle":"Ghosts of pirates"},{"name":"spectraldragon","title":"Призрачные драконы","experience":310,"health":160,"canFly":true,"enTitle":"Shadow dragons"},{"name":"rakshasa_rani","title":"Принцессы ракшас","experience":155,"health":120,"imageName":"rakshas","enTitle":"Sphynx guardians"},{"name":"briskrider","title":"Проворные наездники","experience":94,"health":50,"enTitle":"Lizard chargers"},{"name":"cursedbehemoth","title":"Проклятые бегемоты","experience":400,"health":250,"imageName":"dbehemoth","enTitle":"Cursed behemoths"},{"name":"predator","title":"Проклятые горгульи","experience":25,"health":35,"canFly":true,"imageName":"hgarg","enTitle":"Cursed Gargoyles"},{"name":"cursedent","title":"Проклятые энты","experience":250,"health":215,"enTitle":"Cursed treefolk"},{"name":"thunderbird","title":"Птицы грома","experience":115,"health":65,"canFly":true,"enTitle":"Thunderbirds"},{"name":"darkbird","title":"Птицы тьмы","experience":120,"health":60,"canFly":true,"enTitle":"Dark rocs"},{"name":"vulture","title":"Пустынные налетчики","experience":50,"health":40,"canFly":true,"enTitle":"Desert Raiders"},{"name":"duneraider","title":"Пустынные рейдеры","experience":22,"health":12,"enTitle":"Dune raiders"},{"name":"duneraiderup","title":"Пустынные убийцы","experience":24,"health":12,"enTitle":"Dune assassins"},{"name":"rakshasa_raja","title":"Раджи ракшас","experience":160,"health":140,"enTitle":"Sphynx warriors"},{"name":"tombraider","title":"Расхитители могил","experience":14,"health":10,"enTitle":"Grave raiders"},{"name":"gladiator","title":"Ретиарии","experience":12,"health":25,"enTitle":"Retiarius"},{"name":"horneddemon","title":"Рогатые демоны","experience":14,"health":13,"imageName":"hdemon","enTitle":"Demons"},{"name":"rapukk","title":"Рогатые жнецы","experience":200,"health":99,"enTitle":"Horned reapers"},{"name":"rocbird","title":"Роки","experience":104,"health":55,"canFly":true,"imageName":"roc","enTitle":"Rocs"},{"name":"brigand","title":"Рубаки","experience":6,"health":5,"enTitle":"Vagabonds"},{"name":"cavalier","title":"Рыцари","experience":232,"health":90,"imageName":"knight","enTitle":"Cavalry"},{"name":"deadknight","title":"Рыцари смерти","experience":190,"health":100,"enTitle":"Unholy knights"},{"name":"blackknight","title":"Рыцари тьмы","experience":160,"health":90,"enTitle":"Black knights"},{"name":"pristineunicorn","title":"Светлые единороги","experience":135,"health":80,"enTitle":"Pristine Unicorns"},{"name":"dbehemoth","title":"Свирепые бегемоты","experience":410,"health":280,"enTitle":"Infuriated behemoths"},{"name":"untamedcyc","title":"Свободные циклопы","experience":700,"health":225,"enTitle":"Unfettered cyclops"},{"name":"scarabup","title":"Священные скарабеи","experience":11,"health":6,"canFly":true,"enTitle":"Sacred scarabs"},{"name":"whitebearrider","title":"Северные наездники","experience":36,"health":30,"enTitle":"Rearguard ursary"},{"name":"spegasus","title":"Серебряные пегасы","experience":50,"health":30,"canFly":true,"enTitle":"Silver pegasus"},{"name":"kachok","title":"Силачи","enTitle":"Strongmen","experience":20,"health":50},{"name":"siren","title":"Сирены","experience":60,"health":20,"enTitle":"Sirens"},{"name":"upsiren","title":"Сирены-искусительницы","experience":70,"health":24,"enTitle":"Seducing sirens"},{"name":"scarab","title":"Скарабеи","experience":10,"health":6,"canFly":true,"enTitle":"Scarabs"},{"name":"skeleton","title":"Скелеты","experience":6,"health":4,"imageName":"sceleton","enTitle":"Skeletons"},{"name":"skmarksman","title":"Скелеты-арбалетчики","experience":12,"health":6,"enTitle":"Skeletal crossbowmen"},{"name":"sceletonwar","title":"Скелеты-воины","experience":10,"health":5,"enTitle":"Skeletal legionnaires"},{"name":"skeletonpirateup","title":"Скелеты-корсары","experience":10,"health":4,"enTitle":"Skeletal corsairs","imageName":"dpirateup"},{"name":"cpirate","title":"Скелеты-моряки","experience":6,"health":4,"enTitle":"Skeleton sailor"},{"name":"skeletonarcher","title":"Скелеты-лучники","experience":10,"health":4,"imageName":"sceletonarcher","enTitle":"Skeletal bowmen"},{"name":"skeletonpirate","title":"Скелеты-пираты","experience":7,"health":4,"enTitle":"Skeletal pirates","imageName":"dpirate"},{"name":"manticoreup","title":"Скорпикоры","experience":140,"health":80,"canFly":true,"enTitle":"Scorpicores"},{"name":"scorp","title":"Скорпионы","experience":6,"health":4,"enTitle":"Scorpions"},{"name":"anubis","title":"Слуги Анубиса","experience":350,"health":160,"enTitle":"Anubis avatars"},{"name":"krokodil","title":"Служители оазисов","experience":110,"health":70,"enTitle":"Oasis acolytes"},{"name":"chuvak","title":"Снежные воины","experience":35,"health":27,"enTitle":"Snow warriors"},{"name":"snowwolf","title":"Снежные волки","experience":70,"health":50,"enTitle":"Snow wolves"},{"name":"steelgolem","title":"Стальные големы","experience":54,"health":24,"enTitle":"Modern golems"},{"name":"runepatriarch","title":"Старейшины рун","experience":100,"health":70,"enTitle":"Patriarchs"},{"name":"mastergremlin","title":"Старшие гремлины","experience":9,"health":6,"enTitle":"Gremlin engineers"},{"name":"jdemon","title":"Старшие демоны","experience":20,"health":13,"enTitle":"Fiends"},{"name":"ddhigh","title":"Старшие друиды","experience":101,"health":34,"enTitle":"High Druids"},{"name":"mauler","title":"Степные бойцы","experience":23,"health":12,"enTitle":"Enforcers"},{"name":"warrior","title":"Степные воины","experience":21,"health":12,"enTitle":"Invaders"}
,{"name":"goblinus","title":"Степные гоблины","experience":5,"health":3,"enTitle":"Tribal goblins"},{"name":"cyclopus","title":"Степные циклопы","experience":390,"health":220,"enTitle":"Tribal cyclops"},{"name":"elgargoly","title":"Стихийные горгульи","experience":25,"health":16,"canFly":true,"enTitle":"Grotesques"},{"name":"crossman","title":"Стрелки","experience":16,"health":8,"imageName":"crossbowman","enTitle":"Wardens"},{"name":"mercarcher","title":"Стрелки-наёмники","experience":15,"health":8,"enTitle":"Mercenary archers"},{"name":"succubus","title":"Суккубы","experience":61,"health":20,"imageName":"succub","enTitle":"Succubi"},{"name":"shadow_witch","title":"Сумеречные ведьмы","experience":157,"health":80,"imageName":"witch","enTitle":"Dark witches"},{"name":"shadowdragon","title":"Сумеречные драконы","experience":350,"health":200,"canFly":true,"enTitle":"Twilight dragons"},{"name":"wdancer","title":"Танцующие с ветром","experience":33,"health":14,"imageName":"winddancer","enTitle":"Forest brethren"},{"name":"dancer","title":"Танцующие с клинками","experience":20,"health":12,"enTitle":"Forest keepers"},{"name":"wardancer","title":"Танцующие со смертью","experience":33,"health":12,"imageName":"bladedancer","enTitle":"Elite forest keepers"},{"name":"thane","title":"Таны","experience":131,"health":100,"enTitle":"Dreadbanes"},{"name":"foulwyvern","title":"Тёмные виверны","experience":195,"health":105,"canFly":true,"enTitle":"Venomous wyverns"},{"name":"grimrider","title":"Тёмные всадники","experience":94,"health":50,"enTitle":"Lizard assailants"},{"name":"foulhydra","title":"Тёмные гидры","experience":115,"health":125,"enTitle":"Foul hydras"},{"name":"burbuly","title":"Тёмные горгульи","experience":21,"health":30,"canFly":true,"enTitle":"Dark Gargoyles"},{"name":"titan","title":"Титаны","experience":400,"health":190,"enTitle":"Titans"},{"name":"stormtitan","title":"Титаны шторма","experience":400,"health":190,"enTitle":"Stormcallers"},{"name":"fatpirate","title":"Толстяки","experience":180,"health":100,"enTitle":"Fatso"},{"name":"troglodyte","title":"Троглодиты","experience":5,"health":5,"enTitle":"Troglodytes"},{"name":"troll","title":"Тролли","experience":150,"health":150,"enTitle":"Trolls"},{"name":"tengu","title":"Тэнгу","experience":100,"health":45,"canFly":true,"enTitle":"Tengu"},{"name":"slayer","title":"Убийцы","experience":70,"health":34,"enTitle":"Commanders"},{"name":"verblud","title":"Угонщики верблюдов","experience":55,"health":35,"enTitle":"Camel thieves"},{"name":"wight","title":"Умертвия","experience":165,"health":95,"enTitle":"Death envoys"},{"name":"pixel","title":"Феи","experience":12,"health":5,"canFly":true,"imageName":"pp","enTitle":"Faeries"},{"name":"phoenix","title":"Фениксы","experience":600,"health":777,"canFly":true,"enTitle":"Phoenixes"},{"name":"shootpirateup","title":"Флибустьеры","experience":75,"health":18,"enTitle":"Flibustiers"},{"name":"fury","title":"Фурии","experience":49,"health":16,"enTitle":"Shrews"},{"name":"plant","title":"Хищные растения","experience":92,"health":60,"enTitle":"Waspworts"},{"name":"hobbit","title":"Хоббиты","experience":8,"health":4,"enTitle":"Hobbits"},{"name":"hobgoblin","title":"Хобгоблины","experience":9,"health":4,"enTitle":"Hobgoblins"},{"name":"blackbearrider","title":"Хозяева медведей","experience":36,"health":30,"enTitle":"Frontier ursary"},{"name":"mistress","title":"Хозяйки ночи","experience":185,"health":100,"enTitle":"Shadow mistresses"},{"name":"cerberus","title":"Церберы","experience":41,"health":15,"enTitle":"Cerberi"},{"name":"cyclop","title":"Циклопы","experience":172,"health":85,"enTitle":"Cyclops"},{"name":"cyclopod","title":"Циклопы-генералы","experience":187,"health":100,"imageName":"cyclopod_","enTitle":"Cyclop generals"},{"name":"cyclopking","title":"Циклопы-короли","experience":182,"health":95,"enTitle":"Cyclop kings"},{"name":"shamancyclop","title":"Циклопы-шаманы","experience":190,"health":105,"imageName":"cyclopshaman","enTitle":"Cyclops shamans"},{"name":"mercwizard","title":"Чародеи-наёмники","experience":35,"health":36,"enTitle":"Mercenary sorcerers"},{"name":"champion","title":"Чемпионы","experience":252,"health":100,"enTitle":"Chargers"},{"name":"blackwidow","title":"Черные вдовы","experience":40,"health":14,"enTitle":"Black widows"},{"name":"scorpup","title":"Черные скорпионы","experience":9,"health":5,"enTitle":"Black scorpions"},{"name":"blacktroll","title":"Черные тролли","experience":180,"health":180,"enTitle":"Crazed trolls"},{"name":"familiar","title":"Черти","experience":10,"health":6,"enTitle":"Spawns"},{"name":"blackdragon","title":"Чёрные драконы","experience":400,"health":240,"canFly":true,"enTitle":"Black dragons"},{"name":"plaguezombie","title":"Чумные зомби","experience":15,"health":17,"enTitle":"Infected zombies"},{"name":"shakal","title":"Шакалы","experience":30,"health":24,"enTitle":"Jackals"},{"name":"shakalup","title":"Шакалы-воины","experience":45,"health":30,"enTitle":"Jackals-warriors"},{"name":"shamaness","title":"Шаманки","experience":66,"health":30,"enTitle":"Shamans"},{"name":"banditkaup","title":"Шпионки","experience":14,"health":9,"enTitle":"Spies"},{"name":"battlegriffon","title":"Штурмовые грифоны","experience":62,"health":52,"canFly":true,"enTitle":"Wild griffins"},{"name":"slonup","title":"Штурмовые слоны","experience":150,"health":110,"enTitle":"Assault elephants"},{"name":"elf","title":"Эльфийские лучники","experience":38,"health":10,"enTitle":"Elven bowmen"},{"name":"treant","title":"Энты","experience":187,"health":175,"enTitle":"Treefolk","imageName":"ent"},{"name":"spiderpois","title":"Ядовитые пауки","experience":30,"health":14,"enTitle":"Venomous spiders"},{"name":"tenguup","title":"Ямабуси Тэнгу","experience":100,"health":60,"canFly":true,"enTitle":"Yamabushi Tengu"},{"name":"flamelord","title":"Ярлы","experience":162,"health":120,"enTitle":"Punishers"},{"name":"evilbunny2023","title":"Злой кроля 2023","experience":130,"health":123,"newYear":true,"enTitle":"Evil rabbit 2023"},{"name":"evilcat2023","title":"Злой котик 2023","experience":45,"health":23,"newYear":true,"enTitle":"Evil cat 2023"},{"name":"eviltiger2022","title":"Злой тигр 2022","experience":100,"health":122,"newYear":true,"enTitle":"Furious Tiger 2022"},{"name":"bull2021","title":"Злой бык 2021","experience":69,"health":71,"newYear":true,"enTitle":"Ox 2021","imageName":"byk2"},{"name":"rat2020","title":"Злая крыса 2020","experience":20,"health":20,"newYear":true,"enTitle":"Rat 2020"},{"name":"pig2019","title":"Свин 2019","experience":16,"health":19,"newYear":true,"enTitle":"Pig 2019","imageName":"evilpig"},{"name":"evildog","title":"Злой пёс 2018","experience":100,"health":88,"newYear":true,"enTitle":"Evil Dog 2018"},{"name":"rooster","title":"Злой Петушок 2017","experience":60,"health":77,"canFly":true,"newYear":true,"enTitle":"Evil Rooster 2017"},{"name":"gorilla","title":"Злая Обезьяна 2016","experience":40,"health":66,"newYear":true,"enTitle":"Evil Monkey 2016"},{"name":"kozel","title":"Злой Козел 2015","experience":35,"health":55,"newYear":true,"enTitle":"Evil Goat 2015"},{"name":"evilhorse","title":"Злая Лошадь 2014","experience":45,"health":84,"newYear":true,"enTitle":"Mad horse 2014"},{"name":"evilsnake","title":"Злая Змея 2013","experience":45,"health":73,"newYear":true,"enTitle":"Mad snake 2013"},{"name":"ppirateup","title":"Одноногие пираты","experience":55,"health":30,"enTitle":"One-legged pirates"}
,{"name":"pikeman","title":"Копейщики","experience":15,"health":15,"enTitle":"Pikemen"}
,{"name":"snowmonster","title":"Снежные монстры","experience":400,"health":350,"enTitle":"Snow monsters"}
,{"name":"drowned","title":"Утопленники","experience":20,"health":16,"enTitle":"Drowned men"}
,{"name":"reanimator","title":"Реаниматоры","experience":40,"health":27,"enTitle":"Reanimators"}
,{"name":"pushkarup","title":"Обречённые бомбардиры","experience":208,"health":76,"enTitle":"Doomed bombers",imageFullName:"pushkarupanip40"}
,{"name":"poacher","title":"Браконьеры","experience":33,"health":16,"enTitle":"Poachers"}
,{"name":"gnomka","title":"Жрицы огня","experience":70,"health":40,"enTitle":"Priestesses of fire"}
,{"name":"maroder","title":"Мародёры","experience":10,"health":7,"enTitle":"Marauders"}
,{"name":"ppirate","title":"Морские волки","experience":45,"health":25,"enTitle":"Sea wolves"}
,{"name":"varg","title":"Наездники на варгах","experience":60,"health":44,"enTitle":"Varg riders"}
,{"name":"ork","title":"Орочьи воины","experience":44,"health":24,"enTitle":"Orc warriors"}
,{"name":"satyr","title":"Сатиры","experience":49,"health":36,"enTitle":"Satyrs"}
,{"name":"gnollsh","title":"Гноллы-шаманы","experience":11,"health":6,"enTitle":"Gnolls-shamans"}
,{"name":"warden","title":"Надзиратели","experience":70,"health":39,"enTitle":"Prison guards"}
,{"name":"outlawup","title":"Чародеи-ренегаты","experience":6,"health":8,"enTitle":"Turncoat Warmages"}
,{"name":"shootpirate","title":"Буканиры","experience":45,"health":15,"enTitle":"Buccaneers"}
,{"name":"brigandup","title":"Душегубы","experience":10,"health":6,"enTitle":"Murderers"}
,{"name":"vorovka","title":"Воровки","experience":44,"health":30,"enTitle":"Shadow thieves"}

,{"name":"acrossbowman","title":"Элитные арбалетчики","experience":45,"health":24,"enTitle":"Elite crossbowmen"}

,{"name":"ant","title":"Муратавры","experience":33,"health":27,"enTitle":"Antauruses"}
,{"name":"buffalo","title":"Буйволы","experience":120,"health":120,"enTitle":"Buffaloes"}
,{"name":"dragonfly","title":"Стрекозы","experience":40,"health":20,"canFly":true,"enTitle":"Dragon flyers"}
,{"name":"serpentfly","title":"Крылатые змии","experience":35,"health":20,"canFly":true,"enTitle":"Serpent flyers"}
,{"name":"basiliskup","title":"Древние василиски","experience":44,"health":40,"enTitle":"Ancient basilisks"}
,{"name":"klop","title":"Кислотники","experience":22,"health":12,"enTitle":"Acidspitters"}
,{"name":"vedma","title":"Карги с болот","experience":80,"health":40,"enTitle":"Bog hags"}
,{"name":"vedmaup","title":"Хозяйки топей","experience":95,"health":46,"enTitle":"Mire Mistress"}

,{"name":"exile","title":"Маги-изгнанники","experience":60,"health":28,"enTitle":"Exiled mages"}
,{"name":"monk","title":"Еретики","experience":40,"health":20,"enTitle":"Heretics"}
,{"name":"stoneman","title":"Каменные гиганты","experience":200,"health":100,"enTitle":"Stone giants"}

,{"name":"gnollboss","title":"Гноллы-вожаки","experience":50,"health":36,"enTitle":"Gnoll Leaders"}
,{"name":"gnoll","title":"Гноллы","experience":9,"health":6,"enTitle":"Gnolls"}
,{"name":"gnollup","title":"Яростные гноллы","experience":13,"health":9,"enTitle":"Furious gnolls"}
,{"name":"gnollka","title":"Дочери стаи","experience":9,"health":6,"enTitle":"Daughters of gnolls"}
,{"name":"adeptus","title":"Сектанты","experience":40,"health":46,"enTitle":"Cultists"}
,{"name":"robberup","title":"Соглядатаи","experience":13,"health":6,"enTitle":"Snoopers"}
,{"name":"blud","title":"Блудницы","experience":10,"health":7,"enTitle":"Mystic courtesans"}
,{"name":"gnollum","title":"Метатели боласов","experience":12,"health":6,"enTitle":"Bolas throwers"}
,{"name":"charmerup","title":"Повелители змей","experience":15,"health":10,"enTitle":"Snake masters"}
,{"name":"gorynych2024","title":"Злой Горыныч 2024","experience":200,"health":124,"canFly":true,"newYear":true,"enTitle":"Evil Dragon 2024"}
,{"name":"smaster","title":"Мастера клинка","experience":150,"health":84,"enTitle":"Blade masters"}
,{"name":"throwgnom","title":"Метатели молота","experience":40,"health":24,"enTitle":"Warhammermen"}
,{"name":"witchhunter","title":"Охотники на ведьм","experience":78,"health":38,"enTitle":"Witch hunters"}

,{"name":"grinchshad","title":"Тень Гринча","experience":100,"health":1000,"enTitle":"Grinch`s Shadow"}

//Фауна и жители леса
,{"name":"bigspider","title":"Гигантские пауки","experience":50,"health":55,"enTitle":"Giant Spiders"}
,{"name":"lizard","title":"Гигантские ящеры","experience":25,"health":25,"imageName":"lizard_","enTitle":"Giant lizards"}
,{"name":"swolf","title":"Степные волки","experience":20,"health":25,"enTitle":"Plains wolves"}
,{"name":"zerg","title":"Клыколиски","experience":50,"health":40,"enTitle":"Fangolisks"}
,{"name":"forestspirit","title":"Духи леса","experience":90,"health":50,"canFly":true,"enTitle":"Spirits of forest","imageName":"spirit"}
,{"name":"whitetiger","title":"Белые тигры","experience":60,"health":35,"enTitle":"White tigers"}
,{"name":"ptero","title":"Птероящеры","experience":33,"health":20,"enTitle":"Pterolizards"}
,{"name":"pteroup","title":"Матриархи птероящеров","experience":43,"health":27,"enTitle":"Pterolizards matriarchs"}
,{"name":"basilisk","title":"Василиски","experience":44,"health":35,"enTitle":"Basilisks"}

,{"name":"gekkon","title":"Ядоплюи","experience":20,"health":11,"enTitle":"Venomspitters"}
,{"name":"gekkonup","title":"Гремучие ядоплюи","experience":20,"health":21,"enTitle":"Rattlesnake venomspitters"}
,{"name":"yascher","title":"Вараны","experience":75,"health":44,"enTitle":"Varans"}
,{"name":"yascherup","title":"Огнедышащие вараны","experience":90,"health":49,"enTitle":"Fire-breathing varans"}

//Сектанты
,{"name":"demoniac","title":"Одержимые","experience":6,"health":5,"enTitle":"Demoniacs"}
,{"name":"drakonid","title":"Туманник","experience":300,"health":160,"canFly":true,"enTitle":"Foggy"}

//Разбойники
,{"name":"charmer","title":"Заклинатели змей","experience":15,"health":9,"enTitle":"Snake charmers"}
,{"name":"krokodilup","title":"Стражи оазисов","experience":100,"health":80,"enTitle":"Oasis guards"}
,{"name":"krokodilmag","title":"Жрецы оазисов","experience":110,"health":60,"enTitle":"Oasis priests"}
,{"name":"varan","title":"Загонщики на варанах","experience":80,"health":60,"enTitle":"Varan beaters"}
,{"name":"nomadbow","title":"Скитальцы","experience":63,"health":31,"enTitle":"Wanderers"}
,{"name":"vsad_unit","title":"Завоеватели","experience":300,"health":200,"enTitle":"Conquerors"}
,{"name":"deserterup","title":"Искариоты","experience":60,"health":30,"enTitle":"Iscariots"}
,{"name":"zasad","title":"Засадники","experience":110,"health":70,"enTitle":"Ambushers"}
,{"name":"traitor","title":"Изменники","experience":20,"health":9,"enTitle":"Traitors"}
,{"name":"gnollumup","title":"Дикие звероловы","experience":16,"health":8,"enTitle":"Wild beasthunters"}
,{"name":"stonemanup","title":"Лавовые гиганты","experience":240,"health":110,"enTitle":"Lava giants"}
,{"name":"tombraiderup","title":"Расхитители гробниц","experience":17,"health":12,"enTitle":"Tomb raiders"}
,{"name":"sekhmet","title":"Сехметиты","experience":100,"health":50,"enTitle":"Sekhmetites"}

// Обитатели пляжа
, { name: "shellmonster", title: "Моллюски", enTitle: "Clam-monster", health: 90, experience: 80 }
, { name: "shell", title: "Ракушки", enTitle: "Shells", health: 6, experience: 7 }
, { name: "krevetko", title: "Эбиры", enTitle: "Ebirahs", health: 66, experience: 90 }
, { name: "krab", title: "Гигантские крабы", enTitle: "Giant crabs", health: 50, experience: 80 }
, { name: "krabup", title: "Плотоядные крабы", enTitle: "Carnivorous crabs", health: 60, experience: 100 }

, { name: "shad", title: "Тени", enTitle: "Shadows", health: 9, experience: 14,"canFly": true }

//Грибы
,{"name":"mushroom","title":"Мухоморища","experience":150,"health":90,"enTitle":"Amanitas"}
,{"name":"boletus","title":"Споровики","experience":22,"health":17,"enTitle":"Sporeballs"}
,{"name":"grib","title":"Боровики","experience":30,"health":20,"enTitle":"Boletuses"}
,{"name":"fungus","title":"Грибоманты","experience":50,"health":29,"enTitle":"Mushroommancers"}

//Армия Тьмы
,{"name":"blackarcher","title":"Сумрачные следопыты","experience":26,"health":13,"enTitle":"Twilight hunters"}
,{"name":"deadarcher","title":"Чёрные сагиттарии","experience":33,"health":16,"enTitle":"Black sagittarii"}
,{"name":"blackmage","title":"Тёмные проклинатели","experience":39,"health":20,"enTitle":"Dark hexers"}
,{"name":"deadmage","title":"Ваятели проклятий","experience":60,"health":27,"enTitle":"Сursing thaumaturges"}
,{"name":"necrodogup","title":"Сумрачные гончие","experience":15,"health":9,"enTitle":"Twilight hounds"}
,{"name":"necromancer","title":"Ткачи смерти","experience":66,"health":33,"enTitle":"Deathweavers"}
,{"name":"deadptic","title":"Предвестники тьмы","experience":100,"health":82,"canFly":true,"enTitle":"Harbingers of darkness"}
,{"name":"blackfootman","title":"Чёрные стражи","experience":26,"health":25,"enTitle":"Black guards"}

//Армия холода
,{"name":"snowarcher","title":"Полярные охотники","experience":36,"health":18,"enTitle":"Polar hunters"}
,{"name":"snegovik","title":"Гигантские снеговики","experience":160,"health":100,"enTitle":"Giant snowmen"}
,{"name":"wbear","title":"Белые медведи","experience":77,"health":55,"enTitle":"White bears"}
,{"name":"chuvakup","title":"Ледяные воины","experience":35,"health":33,"enTitle":"Ice warriors"}
,{"name":"snowowl","title":"Снежные совы","experience":100,"health":76,"canFly":true,"enTitle":"Snow owls"}
,{"name":"snowowlup","title":"Полярные совы","experience":120,"health":81,"canFly":true,"enTitle":"Polar owls"}
,{"name":"snowwolfup","title":"Полярные волки","experience":75,"health":53,"enTitle":"Polar wolves"}
,{"name":"icequeen","title":"Снежные королевы","experience":120,"health":29,"enTitle":"Ice queens"}
,{"name":"icequeenup","title":"Ледяные королевы","experience":120,"health":39,"enTitle":"Ice-Maidens"}
,{"name":"iceddragonup","title":"Морозные драконы","experience":350,"health":250,"canFly":true,"enTitle":"Frost dragons"}
,{"name":"iceddragon","title":"Ледяные драконы","experience":250,"health":220,"canFly":true,"enTitle":"Iced dragons","imageName":"icedragon"}
,{"name":"iceel","title":"Ледяные элементали","experience":50,"health":45,"canFly":true,"enTitle":"Ice elementals"}
,{"name":"iceelup","title":"Ледниковые элементали","experience":50,"health":45,"canFly":true,"enTitle":"Glacial elementals"}
,{"name":"flake","title":"Снежинки","experience":7,"health":10,"canFly":true,"enTitle":"Snowflakes"}
,{"name":"minidragon","title":"Дрэйки","experience":60,"health":60,"canFly":true,"enTitle":"Drakes"}
,{"name":"wendigoup","title":"Древние вендиго","experience":30,"health":35,"enTitle":"Ancient wendigos"}

//Механики
,{"name":"mechdron","title":"Дроны","experience":10,"health":7,"canFly":true,"enTitle":"Drones"}
,{"name":"mechspider","title":"Боты-пауки","experience":17,"health":12,"enTitle":"Spider-bots"}
,{"name":"mechspiderup","title":"Боты-арахниды","experience":21,"health":14,"enTitle":"Arachnid-bots"}
,{"name":"mechanic","title":"Механики","experience":50,"health":30,"enTitle":"Mechanics"}
,{"name":"mechtank","title":"Паровые танки","experience":200,"health":120,"enTitle":"Steam tanks"}
,{"name":"mechtankup","title":"Паровые аннигиляторы","experience":250,"health":140,"enTitle":"Steam annihilators"}
,{"name":"alchemist","title":"Алхимики","experience":95,"health":60,"enTitle":"Alchemists"}
,{"name":"alchemistup","title":"Изобретатели","experience":110,"health":68,"enTitle":"Inventors"}

// Амфибии
,{"name":"sharkguard","title":"Акульи стражи","experience":87,"health":25,"enTitle":"Ichthys guard"}
,{"name":"wanizame","title":"Акульи бойцы","experience":123,"health":31,"enTitle":"Ichthys fighters"}
,{"name":"kappa","title":"Каппы","experience":78,"health":21,"enTitle":"Kappas"}
,{"name":"kappashoya","title":"Могучие каппы","experience":114,"health":25,"enTitle":"Mighty kappas"}
,{"name":"coralp","title":"Коралловые жрицы","experience":111,"health":18,"enTitle":"Coral priestesses"}
,{"name":"pearlp","title":"Жемчужные жрицы","experience":159,"health":22,"enTitle":"Pearl priestesses"}
,{"name":"springspirit","title":"Духи ручьёв","experience":315,"health":70,"enTitle":"Spring spirits"}
,{"name":"mizukami","title":"Духи морей","experience":402,"health":76,"enTitle":"Spring custodians"}
,{"name":"kenshi","title":"Кэнши","experience":438,"health":80,"enTitle":"Tritons"}
,{"name":"kensei","title":"Кэнсэи","experience":564,"health":90,"enTitle":"Myrmidons"}
,{"name":"snowmaiden","title":"Снежные девы","experience":450,"health":65,"enTitle":"Snow maidens"}
,{"name":"yukionna","title":"Ледяные девы","experience":582,"health":72,"enTitle":"Frost maidens"}
,{"name":"kirin","title":"Кирины","experience":1467,"health":255,"enTitle":"Aquatic serpents"}
,{"name":"sacredkirin","title":"Священные кирины","experience":1794,"health":265,"enTitle":"Aquatic drakes"}

// Инферно
,{"name":"maniac","title":"Помешанные","experience":87,"health":23,"enTitle":"Maniacs"}
,{"name":"demented","title":"Безумцы","experience":129,"health":28,"enTitle":"Demented"}
,{"name":"hellhound6","title":"Адские гончие","experience":123,"health":22,"enTitle":"Hellhounds"}
,{"name":"cerber","title":"Адские церберы","experience":180,"health":28,"enTitle":"Hell cerberi"}
,{"name":"succubus6","title":"Адские суккубы","experience":108,"health":20,"enTitle":"Demonesses","canFly":true}
,{"name":"lilim","title":"Лилимы","experience":159,"health":24,"enTitle":"Infernal succubi","canFly":true}
,{"name":"tormentor","title":"Садисты","experience":441,"health":80,"enTitle":"Tormentors"}
,{"name":"lacerator","title":"Изверги","experience":522,"health":85,"enTitle":"Torturers"}
,{"name":"breeder","title":"Породительницы","experience":366,"health":70,"enTitle":"Breeders"}
,{"name":"mbreeder","title":"Матки-породительницы","experience":441,"health":75,"enTitle":"Heinous breeders"}
,{"name":"juggernaut","title":"Разрушители","experience":120,"health":90,"enTitle":"Juggernauts"}
,{"name":"ravager","title":"Опустошители","experience":136,"health":100,"enTitle":"Ravagers"}
,{"name":"pitfiend6","title":"Демоны бездны","experience":1728,"health":270,"enTitle":"Wrath demons"}
,{"name":"pitlord6","title":"Владыки бездны","experience":2250,"health":280,"enTitle":"Hatred demons"}

// Некрополис
,{"name":"skeleton6","title":"Костяные воины","experience":72,"health":18,"enTitle":"Skeletal warriors"}
,{"name":"skeletons6","title":"Костяные копейщики","experience":111,"health":23,"enTitle":"Skeletal Spearmen"}
,{"name":"ghoul","title":"Упыри","experience":105,"health":25,"enTitle":"Nachzehrers"}
,{"name":"ravenousghoul","title":"Ненасытные упыри","experience":147,"health":32,"enTitle":"Ravenous ghouls"}
,{"name":"ghost6","title":"Привидения прошлого","experience":99,"health":21,"enTitle":"Ghosts of past"}
,{"name":"spectre6","title":"Призраки прошлого","experience":138,"health":27,"enTitle":"Specters of past"}
,{"name":"lich6","title":"Личи прошлого","experience":375,"health":65,"enTitle":"Liches of past"}
,{"name":"vampire6","title":"Кровопийцы","experience":327,"health":80,"enTitle":"Bloodsuckers"}
,{"name":"vampirelord6","title":"Вампиры прошлого","experience":408,"health":95,"enTitle":"Vampires of past"}
,{"name":"fatespinner","title":"Прядильщицы судеб","experience":1746,"health":280,"enTitle":"Fate spinners"}

// Непокорные племена
,{"name":"goblin6","title":"Непокорные гоблины","experience":66,"health":23,"enTitle":"Wild goblins"}
,{"name":"goblinhunter6","title":"Гоблины-охотники","experience":99,"health":26,"enTitle":"Goblin hunters"}
,{"name":"mauler6","title":"Громилы","experience":117,"health":30,"enTitle":"Maulers"}
,{"name":"crusher6","title":"Крушилы","experience":162,"health":36,"enTitle":"Crushers"}
,{"name":"harpy6","title":"Непокорные гарпии","experience":99,"health":29,"enTitle":"Unruly harpies"}
,{"name":"fury6","title":"Сирины","experience":144,"health":33,"enTitle":"Frenzied harpies"}
,{"name":"dreamwalker6","title":"Сноходцы","experience":315,"health":85,"enTitle":"Dreamwalkers"}
,{"name":"dreamreaver6","title":"Ловцы снов","experience":399,"health":100,"enTitle":"Dreamreavers"}
,{"name":"jaguar6","title":"Воины-ягуары","experience":369,"health":85,"enTitle":"Worshippers"}
,{"name":"panther6","title":"Воины-пантеры","experience":480,"health":90,"enTitle":"Fetishists"}
,{"name":"centaur6","title":"Непокорные кентавры","experience":645,"health":70,"enTitle":"Nomad centaurs"}
,{"name":"mcentaur6","title":"Кентавры-мародёры","experience":849,"health":80,"enTitle":"Marauding centaurs"}
,{"name":"cyclop6","title":"Непокорные циклопы","experience":1662,"health":330,"enTitle":"Wild cyclops"}
,{"name":"ecyclop6","title":"Разъяренные циклопы","experience":2283,"health":360,"enTitle":"Raging cyclops"}

// Рыцари солнца
,{"name":"sentinel","title":"Стражи","experience":66,"health":23,"enTitle":"Sentinels"}
,{"name":"praetorian","title":"Гвардейцы","experience":99,"health":32,"enTitle":"Praetorians"}
,{"name":"cman","title":"Арбалетчики света","experience":111,"health":22,"enTitle":"Marksmen"}
,{"name":"marks","title":"Арбалетчики солнца","experience":50,"health":28,"enTitle":"Templar marksmen"}
,{"name":"sister","title":"Послушницы","experience":72,"health":19,"enTitle":"Novices"}
,{"name":"vestal","title":"Весталки","experience":108,"health":25,"enTitle":"Vestals"}
,{"name":"griffin","title":"Грифоны света","experience":456,"health":75,"enTitle":"Tamed griffins"}
,{"name":"igriffin","title":"Грифоны солнца","experience":588,"health":85,"enTitle":"Templar griffins"}
,{"name":"radiantglory","title":"Сияние","experience":489,"health":65,"enTitle":"Blessed spirits"}
,{"name":"blazingglory","title":"Лучезарное сияние","experience":170,"health":70,"enTitle":"Beaming spirits"}
,{"name":"sunrider","title":"Всадники солнца","experience":489,"health":90,"enTitle":"Sun chargers"}
,{"name":"suncrusader","title":"Крестоносцы солнца","experience":240,"health":95,"enTitle":"Champions"}
,{"name":"celestial","title":"Небесные воители","experience":1956,"health":300,"enTitle":"Celestials"}
,{"name":"seraph","title":"Серафимы","experience":800,"health":325,"enTitle":"Seraphs"}

// Строения
,{"name":"archtower","title":"Башня лучников","experience":0,"health":0,"enTitle":"Archer tower", isBuilding: true}
,{"name":"towerwall","title":"Башня лучников","experience":0,"health":0,"enTitle":"Archer tower", isBuilding: true}
,{"name":"bigtower","title":"Основная башня","experience":0,"health":0,"enTitle":"Main tower", isBuilding: true}//?
,{"name":"witchhouse","title":"Дом","experience":0,"health":0,"enTitle":"House", isBuilding: true}
,{"name":"sklep","title":"Склеп","experience":0,"health":0,"enTitle":"Crypt", isBuilding: true}
,{"name":"grob1","title":"Могила","experience":0,"health":0,"enTitle":"Grave", isBuilding: true}
,{"name":"logovo2","title":"Логово бандитов","experience":0,"health":0,"enTitle":"Bandits lair", isBuilding: true}
,{"name":"logovo3","title":"Логово бандитов","experience":0,"health":0,"enTitle":"Bandits lair", isBuilding: true}
,{"name":"logovo4","title":"Повозка бандитов","experience":0,"health":0,"enTitle":"Bandits wagon", isBuilding: true}
,{"name":"sbor1","title":"Завод механиков","experience":0,"health":0,"enTitle":"Mechanics factory", isBuilding: true}
,{"name":"hellgate","title":"Врата ада","experience":0,"health":0,"enTitle":"Hell gate", isBuilding: true}
,{"name":"brevno","title":"Бревно","experience":0,"health":0,"enTitle":"Log", isBuilding: true}
];
// let monsterData = Object.keys(mob_rus_exp).reduce((t, x, i) => [...t, `{ id: ${i + 1}, name: '${mob_rus_exp[x][2]}', title: isEn ? '${x}' : '${x}', experience: ${mob_rus_exp[x][0]}, health: ${mob_rus_exp[x][1]}, canFly: ${mob_rus_exp[x][3] == 1 ? 'true' : 'false'} }`], []);
// let monsterData = monsters.reduce((t, x, i) => [...t, `{ name: '${x.name}', title: "${x.title}", experience: ${x.experience}, health: ${x.health}, canFly: ${x.canFly}, newYear: false }`], []);
// console.log(`[${monsterData.join(", ")}]`);
//deleteValue("monsters");
const newMonsters = JSON.parse(getValue("monsters", "[]"));
newMonsters.forEach(x => {
    let baseMonster = monsters.find(y => y.name == x.name);
    if(baseMonster) {
        baseMonster.wanted = x.wanted ? true : false;
        if(x.experience > 0 && x.health > 0) {
            baseMonster.title = x.title;
            baseMonster.enTitle = x.enTitle;
            baseMonster.experience = x.experience;
            baseMonster.health = x.health;
            baseMonster.canFly = x.canFly ? true : false;
            baseMonster.newYear = x.newYear ? true : false;
        }
    } else {
        monsters.push(x);
    }
});
monsters.sort(sortBy(isEn ? "enTitle" : "title"));
const addedMonsters = monsters.filter(x => x.isNew);
if(addedMonsters.length > 0) {
    console.log(addedMonsters.map(x => `{ name: "${x.name}", title: "${x.title}", enTitle: "${x.enTitle}", health: ${x.health}, experience: 0 }`).join(", "));
}

var warlogProcessing = false;
var terminateProcess = false;

main();
async function main() {
    showArmiesHealth();
    //console.log(Array.isArray("asfasdf"))
    if(location.pathname == "/mercenary_guild.php") {
        const tasksPanel = document.querySelector("body > center > table table td[rowspan='2']");

        const warStatistics = JSON.parse(getValue(`WarStatistics${PlayerId}`, "{}"));
        const warlogScanned = warStatistics.minWarId > 0 && warStatistics.firstWarId == warStatistics.minWarId;

        //const refreshRef = Array.from(document.querySelectorAll("a[href='/mercenary_guild.php']")).find(x => x.innerText == (isEn ? "Refresh" : "Обновить"));
        const getWarsStatisticsName = warlogScanned ? (isEn ? "Append war statistics" : "Пополнить боевую статистику") : (isEn ? "Get war statistics" : "Получить боевую статистику");
        const getWarsStatistics = addElement("input", { id: "getWarsStatistics", style: "border: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #592c08; font-family: verdana,geneva,arial cyr; position: relative; text-align: center; font-weight: 700; background: url(../i/homeico/art_btn_bg_gold.png) #dab761; background-size: auto; background-size: 100% 100%; border-radius: 5px; box-shadow: inset 0 0 0 1px #fce6b0,inset 0 0 0 2px #a78750,0 0 0 1px rgba(0,0,0,.13); line-height: 25px; cursor: pointer; transition: -webkit-filter .15s; transition: filter .15s;", type: "button", value: getWarsStatisticsName }, tasksPanel);
        getWarsStatistics.addEventListener("click", function(e) { readWarlog(e); });
        const clearWarsStatisticsButton = addElement("input", { id: "clearWarsStatisticsButton", style: "border: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #592c08; font-family: verdana,geneva,arial cyr; position: relative; text-align: center; font-weight: 700; background: url(../i/homeico/art_btn_bg_gold.png) #dab761; background-size: auto; background-size: 100% 100%; border-radius: 5px; box-shadow: inset 0 0 0 1px #fce6b0,inset 0 0 0 2px #a78750,0 0 0 1px rgba(0,0,0,.13); line-height: 25px; cursor: pointer; transition: -webkit-filter .15s; transition: filter .15s;", type: "button", value: isEn ? "Clear statistics" : "Очистить статистику" }, tasksPanel);
        clearWarsStatisticsButton.addEventListener("click", clearWarsStatistics);

        // const correctWarsStatisticsButton = addElement("input", { style: "border: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #592c08; font-family: verdana,geneva,arial cyr; position: relative; text-align: center; font-weight: 700; background: url(../i/homeico/art_btn_bg_gold.png) #dab761; background-size: auto; background-size: 100% 100%; border-radius: 5px; box-shadow: inset 0 0 0 1px #fce6b0,inset 0 0 0 2px #a78750,0 0 0 1px rgba(0,0,0,.13); line-height: 25px; cursor: pointer; transition: -webkit-filter .15s; transition: filter .15s;", type: "button", value: isEn ? "Correct statistics" : "Скорректировать статистику" }, tasksPanel);
        // correctWarsStatisticsButton.addEventListener("click", function(e) { correctWarsStatistics(e); });

        if(tasksPanel) {
            tasksPanel.insertAdjacentHTML("beforeend", getMercAgenciesTable());
            const enemies = tasksPanel.querySelectorAll("b");
            for(const enemy of enemies) {
                const enemyExec = /(.+) {(\d+)}/.exec(enemy.innerText);
                if(enemyExec) {
                    const enemyName = enemyExec[1];
                    const enemyLevel = enemyExec[2];
                    // История
                    const historyContainer = addElement("div", { id: `historyContainer${enemyName}`, style: "display: none;" }, enemy, "afterend");
                    const wars = restoreWars(enemyName, PlayerId); // JSON.parse(getPlayerValue(enemyName, "[]")).map(x => JSON.parse(x));
                    //console.log(wars);
                    if(wars.length > 0) {
                        //console.log(getPlayerValue(enemyName, "[]"));
                        for(const war of wars) {
                            historyContainer.insertAdjacentHTML("beforeend", `<div><a href="/warlog.php?warid=${war.id}" target="_blank">${war.isWin ? "<b>" : ""}${war.date.substr(0, 16).replace("T", " ")} <span title="${isEn ? "Player level" : "Уровень игрока"}">(${war.playerLevel})</span> {${war.enemyLevel}}${war.isWin ? "</b>" : ""}</a></div>`);
                        }
                        const historyToggler = addElement("div", { title: isEn ? "History" : "История", style: "display: inline-block; cursor: pointer;", innerHTML: `<img spoiled="true" src="https://dcdn.heroeswm.ru/i/inv_im/btn_expand.svg" style="vertical-align: middle;">` }, enemy, "afterend");
                        historyToggler.addEventListener("click", function(e) {
                            const historyContainer = document.getElementById(`historyContainer${enemyName}`);
                            historyContainer.style.display = (historyContainer.style.display == "none" ? "block" : "none");
                            e.target.setAttribute("spoiled", !(e.target.getAttribute("spoiled") == "true"));
                            e.target.style.transform = e.target.getAttribute("spoiled") == "true" ? 'rotate(0deg)' : 'rotate(90deg)';
                        });
                    }
                    let creatueName;
                    let isMonster = false;
                    if(enemyName.includes(isEn ? "-raids" : "-набеги")) {
                        creatueName =  enemyName.replace(isEn ? "-raids" : "-набеги", "");
                    }
                    if(enemyName.includes(isEn ? "-monster" : "-монстр")) {
                        creatueName =  enemyName.replace(isEn ? "-monster" : "-монстр", "");
                        isMonster = true;
                    }
                    if(creatueName) {
                        const monster = monsters.find(x => (isEn ? x.enTitle : x.title) == creatueName);
                        if(monster) {
                            enemy.innerHTML = enemy.innerHTML.replace(creatueName, `<a href="army_info.php\?name=${monster.name}">${creatueName}</a>`);
                            if(isMonster) {
                                let monstersDataIds = JSON.parse(getValue("MonstersDataIds", "{}"));//                                console.log(monstersDataIds);
                                let monstersDataId = monstersDataIds[monster.title];
                                if(!monstersDataId) {
                                    const doc = await getRequest("https://daily.heroeswm.ru/help/gn/monsters.php");
                                    monstersDataIds = Array.from(doc.querySelectorAll("select#id > option")).filter(x => parseInt(x.value) > 0).reduce((t, x) => { t[x.innerText] = parseInt(x.value); return t; }, {});
                                    console.log(monstersDataIds);
                                    setValue("MonstersDataIds", JSON.stringify(monstersDataIds));
                                    monstersDataId = monstersDataIds[monster.title];
                                }
                                if(monstersDataId) {
                                    enemy.addEventListener("mouseenter", async function(e) {
                                        let tooltipDiv = document.getElementById(`monster${monster.name}TooltipDiv`);
                                        if(!tooltipDiv) {
                                            e.target.style.position = "relative";
                                            tooltipDiv = addElement("div", { id: `monster${monster.name}TooltipDiv`, innerHTML: isEn ? "Loading..." : "Загрузка...", style: "position: absolute; left: 0px; z-index: 150;" }, e.target);

                                            const monsterDataDoc = await getRequest(`https://daily.heroeswm.ru/help/gn/monsters.php?id=${monstersDataId}`);
                                            // const images = [...monsterDataDoc.querySelectorAll("img[src^='../']")];
                                            // //images.forEach(x => x.src.replace("https://www.heroeswm.ru/", "https://daily.heroeswm.ru/"))
                                            // images.forEach(x => x.src = `https://daily.heroeswm.ru/img/creatures/icons/crossman.png`)
                                            // console.log(images.map(x => x.src));
                                            // console.log(images.filter(x => x.src.includes("https://www.heroeswm.ru/")));
                                            const monsterLevelsDataTable = monsterDataDoc.querySelector("table.Table");
                                            const currentLevelRow = Array.from(monsterLevelsDataTable.rows).find(x => x.cells[0].innerHTML.includes(`{${enemyLevel}}`));
                                            currentLevelRow.style.backgroundColor = "yellow";
                                            tooltipDiv.innerHTML = monsterLevelsDataTable.outerHTML;
                                            const table = tooltipDiv.querySelector("table");
                                            table.style.whiteSpace = "nowrap";
                                        }
                                        const anchorRect = e.target.getBoundingClientRect();
                                        tooltipDiv.style.top = `${anchorRect.height}px`;
                                        tooltipDiv.style.display = "";
                                        //console.log(`tooltipDiv.style.display: ${tooltipDiv.style.display}`);
                                    });
                                    enemy.addEventListener("mouseleave", function(e) { const tooltipDiv = document.getElementById(`monster${monster.name}TooltipDiv`); if(tooltipDiv) { tooltipDiv.style.display = "none"; } });
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    createSettingsCaller();
    const settingsButtonContainer = document.querySelector("div#hwm_map_objects_and_buttons");
    observe(settingsButtonContainer, createSettingsCaller);
    applyGreenPeace();
    if(!getPlayerBool("hideHunts")) {
        Array.from(document.querySelectorAll("tr > td[colspan*='2']")).filter(x => x.innerHTML == (isEn ? "You are already in a challenge!" : "Вы уже в заявке!")).forEach(x => { x.align = 'right'; x.innerHTML = `<a href="map.php?action=skip">${isEn ? "Skip" : "Пройти мимо"}</a>`; }); //добавить ссылку на пропуск охот, если стоишь в заявке на бой или карточную игру
        if(getPlayerBool("show_archive")) {
            for(const ref of document.querySelectorAll("div > a[href*='mid=']")) {
                const s = ref.href.split('&mid');
                ref.insertAdjacentHTML("afterEnd", `<br><a href="${s[0]}&show_archive=1&mid${s[1]}" target=_blanc><img border="0" title="${isEn ? "Archive record before 2015-03-01" : "Рекорд из архива (до 01.03.2015"}" src="http://dcdn.heroeswm.ru/i/s_knowledge.gif"></a>`); //добавить ссылку на рекорд из архива
            }
        }
        transformMapHunts();
    }
    huntHelpers();
    Array.from(document.querySelectorAll("a[href*='group_wars.php']")).forEach(x => x.href = x.href.replace("group_wars.php", "group_wars.php?filter=hunt")); //заменяет ссылку в групповые бои на такую же с выделением свободных охот
    if(location.pathname == "/plstats_hunters.php") {
        // const monstersInfo = Array.from(document.querySelectorAll("a[href^='army_info.php?name=']")).map(x => ({ name: getUrlParamValue(x.href, "name"), title: x.innerText }));
        // console.log(monstersInfo.filter(x => !monsters.map(y => y.name).includes(x.name)));

        // monsters.forEach(x => {
            // const monsterInfo = monstersInfo.find(y => y.name == x.name);
            // if(isEn && monsterInfo) {
                // x.enTitle = monsterInfo.title;
            // }
        // })
        // monsters.forEach(x => {
            // const monsterInfo = monstersInfo.find(y => y.title == x.title);
            // if(x.name != monsterInfo.name) {
                // x.imageName = x.name;
                // x.name = monsterInfo.name;
            // }
        // })
        //console.log(JSON.stringify(monsters));
        //console.log(monstersInfo.filter(x => !monsters.map(y => y.title).includes(x.title)));
        add_archive();
    }
}
async function showArmiesHealth() {
    let armyContainers = [];
    if(location.pathname == "/leader_guild.php" || location.pathname == "/lg_event.php" || location.pathname == "/reaping_event.php" || location.pathname == "/tj_single.php" || location.pathname == "/pirate_self_event.php") {
        let unitSources = [...document.querySelectorAll("div.cre_creature > a[href^='army_info.php?name=']")];
        unitSources = [...unitSources, ...document.querySelectorAll("div.hwm_dynamic_portrait > div > a[href^='army_info.php?name=']")];
        const global_container_blockArray = unitSources.map(x => x.closest("div.global_container_block.event_old_chrome_column")).filter(onlyUnique);
        const armyUnits = unitSources.map((x, i) => {
            if(location.pathname == "/pirate_self_event.php") {
                return { armyContainer: getParent(x, "td") };
            }
            let deep = 3;
            if(location.pathname == "/tj_single.php" && x.closest("div.global_container_block.event_old_chrome_column") == global_container_blockArray[0]) {
                deep = 5;
            }
            return { armyContainer: getParent(x, "div", deep) };
        });
        armyContainers = [...armyContainers, ...groupToArray(armyUnits, x => x.armyContainer).map(x => x.key)];
    }
    //console.log(armyContainers);
    for(const x of armyContainers) {
        await showArmyHealth(x);
        observe(x, async function() { await showArmyHealth(x); });
    }
}
async function showArmyHealth(armyContainer) {
    console.log(armyContainer);
    let unitSources = [...armyContainer.querySelectorAll("a[href^='army_info.php?name=']")];
    const units = [];
    for(const x of unitSources) {
        //console.log(`x.href: ${x.href}`);
        const name = getUrlParamValue(x.href, "name");
        const monster = await getMonster(x.href);
        units.push({
            name: name,
            amount: parseInt((x.parentNode.querySelector("div.cre_amount") || x.parentNode.parentNode.querySelector("div.cre_amount"))?.innerText
            || x.parentNode.querySelector("div.cre_amount48")?.innerText
            || 0),
            health: monster?.health || 0,
            experience: monster?.experience || 0,
            title: monster ? (isEn ? monster.enTitle : monster.title) : "",
            isAbsent: monster ? false : true,
            isBuilding: monster?.isBuilding || false
        });
    }
    //console.log(units);
    const totalHealth = units.reduce((t, x) => t + x.amount * x.health, 0);
    const totalExperience = units.reduce((t, x) => t + x.amount * x.experience, 0);

    const absentUnits = units.filter(x => x.isAbsent && x.amount > 0).map(x => x.name).filter(onlyUnique);
    const absentHint = absentUnits.join(", ");

    const bigMonster = units.filter(x => x.title && x.amount == 0 && !x.isBuilding).map(x => x.title).filter(onlyUnique);
    const bigMonsterHint = bigMonster.join(", ");
    //console.log(`armyContainer.style.display: ${armyContainer.style.display}`);

    const buildings = units.filter(x => x.isBuilding).map(x => x.title).filter(onlyUnique);
    const buildingsHint = buildings.join(", ");

    const isFlex = armyContainer.style.display == "flex";
    if(!isFlex) {
        //armyContainer.insertAdjacentHTML("beforeend", `<br>`);
    } else {
        armyContainer.style.flexWrap = "wrap";
        addElement("div", { style: "flex-basis: 100%; height: 0;"}, armyContainer);
    }
    armyContainer.insertAdjacentHTML("beforeend", `<div name=armyHealthAndExperience style="display: inline-block; font-size: 12px; text-align: center; width: 100%;">
<span>${isEn ? "Health" : "Здоровье"} ${totalHealth}</span>
<span>${isEn ? "Experience" : "Опыт"} ${totalExperience}</span>${absentHint ? `<span style="color: red; font-weight: bold;" title="${isEn ? "Mosters absent in db" : "Монстры отсутствующие в базе"} ${absentHint}">?</span>` : ""}${bigMonsterHint ? `<span title="${isEn ? "Mosters" : "Монстры"}: ${bigMonsterHint}">👹</span>` : ""}${buildingsHint ? `<span title="${isEn ? "Buildings" : "Постройки"}: ${buildingsHint}">🏠</span>` : ""}
</div>`);

    const fixedDivSelectors = ["div#tableDiv"];
    for(const fixedDivSelector of fixedDivSelectors) {
        const fixedDiv = armyContainer.closest(fixedDivSelector);
        if(fixedDiv) {
            const armyHealthAndExperience = armyContainer.querySelector("div[name=armyHealthAndExperience]");
            const armyHealthAndExperienceRect = armyHealthAndExperience.getBoundingClientRect();
            const tableDivRect = fixedDiv.getBoundingClientRect();
            fixedDiv.style.height = `${tableDivRect.height + armyHealthAndExperienceRect.height}px`;
        }
    }
}
async function getMonster(url) {
    const name = getUrlParamValue(url, "name");
    const monster = monsters.find(y => y.name == name);
    if(monster) {
        return monster;
    }

    const urlSearch = url.split("?")[1];
    let doc = await getRequest(`https://www.heroeswm.ru/army_info.php?${urlSearch}`);
    const title = doc.querySelector("div.info_header_content > div > h1").innerText;
    const health = parseInt(doc.querySelector("div.scroll_content_half > img[src*='attr_hit_points.png']").closest("div").querySelector("div").innerText);

    doc = await getRequest(`https://www.lordswm.com/army_info.php?${urlSearch}`);
    const enTitle = doc.querySelector("div.info_header_content > div > h1").innerText;
    const unit = { name: name, title: title, enTitle: enTitle, health: health, isNew: true};

    const newMonsters = JSON.parse(getValue("monsters", "[]"));
    newMonsters.push(unit);
    monsters.push(unit);
    setValue("monsters", JSON.stringify(newMonsters));
    
    return unit;
}
function onlyUnique(value, index, array) { return array.indexOf(value) === index; }
async function transformMapHunts() {
    if(location.pathname != '/map.php') {
        return;
    }
    const map_hunt_block_div = document.querySelector("div#map_hunt_block_div");
    if(map_hunt_block_div) {
        const lastChild = map_hunt_block_div.lastChild;
        if(lastChild.tagName?.toLowerCase() == "br") {
            lastChild.remove();
        }
    }
    const koef = parseFloat(getPlayerValue("koef_dop_exp", 1));
    const hunts = [];
    for(const x of Array.from(document.querySelectorAll("div[id^=neut_right_block] > div:first-child > div:first-child"))) {
        const armyRef = x.querySelector("a[href^='army_info.php?name=']");
        const name = getUrlParamValue(armyRef.href, "name");
        const amount = parseInt(x.querySelector("b").innerText.match(/(\d+)/)[1]);
        const title = armyRef.innerText;
        let gold = 0;
        const goldMatch = x.innerHTML.match(new RegExp(`(\\d+) ${isEn ? "gold" : "золота"}`));
        if(goldMatch) {
            gold = parseInt(goldMatch[1]);
        }
        const monster = await getMonster(armyRef.href);
        const fullExperience = Math.round(amount * monster.experience / 5);
        let experience = Math.min(fullExperience, PlayerLevel * 500);
        if(PlayerLevel > 2) { //Если опыт меньше нижней отсечки по уровню (3+ уровни)
            experience = Math.max(experience, PlayerLevel * 100);
        }
        experience = Math.round(experience * koef); // total_exp - опыт с учетом коэф. перекача

        const isHalfAmount = x.innerHTML.includes("[1/2]");
        let diamonds = x.innerHTML.includes("diamonds.png") ? 0.1 : 0;
        const diamondsMatch = new RegExp(isEn ? "([\\d\\.]+) diamond" : "([\\d\\.]+) бриллиант").exec(x.innerHTML);
        if(diamondsMatch) {
            diamonds = parseFloat(diamondsMatch[1]);
        }
        let guildPoints = 1;
        const guildPointsMacth = x.innerText.match(/\+([2,3,5])/);
        if(guildPointsMacth) {
            guildPoints = parseInt(guildPointsMacth[1]);
        }
        hunts.push({ name: name, title: title, amount: amount, title: title, gold: gold, monster: monster, huntDescriptionPanel: x, fullExperience: fullExperience, experience: experience, isHalfAmount: isHalfAmount, diamonds: diamonds, guildPoints: guildPoints });
    }
    if(hunts.length == 0) {
        return;
    }
    console.log(hunts);
    document.title = isEn ? "Hunt found" : "Охота найдена";
    // Если находимся в режиме поиска, то пропускаем охоты, не отвечающие критериям поиска. В режиме поиска мы находимся, если включен хоть один критериев поиска.
    const isLookingFor = getPlayerBool("lookingForMarkedInList") && monsters.find(x => x.wanted) || Number(getPlayerValue("experienceLimit")) > 0 || getPlayerBool("lookingForHalfAmount") || getPlayerBool("lookingForDiamond") || getPlayerBool("lookingForFlying") || getPlayerBool("lookingForAdvancedGuildPoints");
    if(isLookingFor) {
        const found = hunts.find(isHuntMatch) ? true : false;
        if(!found) {
            const skipButton = document.querySelector(`div#map_hunt_block_div div[hint^='${isEn ? "Pass" : "Пройти"}']`);
            if(skipButton) {
                document.title = isEn ? "Hunt skipped" : "Охота пропущена";
                if(getPlayerBool("skipUnmatchedHunts")) {
                    skipButton.dispatchEvent(new MouseEvent('click')); //setTimeout(function() { window.location.href = location.protocol+'//'+location.hostname+'/'+'map.php?action=skip'; }, 2000);
                }
            }
        }
    }
    for(const hunt of hunts) {
        if(getPlayerBool("isShortHuntDescription")) {
            hunt.huntDescriptionPanel.innerHTML = `<a href="army_info.php?name=${hunt.name}">${hunt.title}</a> (${hunt.amount}${hunt.isHalfAmount ? "[1/2]" : ""}) ${isEn ? "guard" : "стерегут"}${hunt.gold > 0 ? ` ${hunt.gold} ${isEn ? "g." : "з."}`: ""}${hunt.diamonds > 0 ? ` ${hunt.diamonds} <img style="width: 16px; height: 16px; border: 0; vertical-align: middle;" title="${isEn ? "Diamonds" : "Бриллианты"}" src="https://dcdn.heroeswm.ru/i/r/48/diamonds.png">`: ""}`;
            hunt.huntDescriptionPanel.style.fontSize = "11px";
            if(hunt.guildPoints > 1) {
                hunt.huntDescriptionPanel.insertAdjacentHTML("beforeend", `<b>(+${hunt.guildPoints})</b>`);
            }
        }
        // История
        //correctWars(hunt.title); // Нужна только мне из-за первоначальных кривых данных
        const wars = restoreWars(hunt.title, PlayerId);//        const wars = JSON.parse(getPlayerValue(hunt.title, "[]")).map(x => JSON.parse(x));
        if(wars.length > 0) {
            const historyContainer = addElement("div", { id: `historyContainer${hunt.name}`, style: "display: none;" }, hunt.huntDescriptionPanel);
            //console.log(wars);
            for(const war of wars) {
                historyContainer.insertAdjacentHTML("beforeend", `<div><a href="/warlog.php?warid=${war.id}" target="_blank">${war.isWin ? "<b>" : ""}${war.date.substr(0, 16).replace("T", " ")} <span title="${isEn ? "Player level" : "Уровень игрока"}">(${war.playerLevel})</span> (${war.enemyLevel})${war.isWin ? "</b>" : ""}</a></div>`);
            }

            addElement("br", {}, hunt.huntDescriptionPanel.nextSibling);
            const historyToggler = addElement("div", { title: isEn ? "History" : "История", style: "display: inline-block; cursor: pointer;", innerHTML: `<img spoiled="true" src="https://dcdn.heroeswm.ru/i/inv_im/btn_expand.svg" style="vertical-align: middle;">` }, hunt.huntDescriptionPanel.nextSibling);
            historyToggler.addEventListener("click", function(e) {
                const historyContainer = document.getElementById(`historyContainer${hunt.name}`);
                historyContainer.style.display = (historyContainer.style.display == "none" ? "block" : "none");
                e.target.setAttribute("spoiled", !(e.target.getAttribute("spoiled") == "true"));
                e.target.style.transform = e.target.getAttribute("spoiled") == "true" ? 'rotate(0deg)' : 'rotate(90deg)';
            });
        }
        //

        const hp = getPlayerBool("showTotalMonstersHealth", true) ? ` <font style="font-size: 9px;color:#CD00CD">HP:<b>${hunt.monster.health * hunt.amount}</b></font>` : "";
        if(getPlayerBool("showTotalMonstersHealth", true)) {
            const amountEndIndex = hunt.huntDescriptionPanel.innerHTML.indexOf(")");
            hunt.huntDescriptionPanel.innerHTML = hunt.huntDescriptionPanel.innerHTML.substring(0, amountEndIndex) + hp + hunt.huntDescriptionPanel.innerHTML.substring(amountEndIndex);
        }
        const min_count = Math.round(hunt.amount / 5 - 0.5); //Для минимального 5% прироста, чтобы получить минимальную умелку 0.2 (20% от 1) убиваем 20% существ
        let exp_min_count = Math.min(Math.floor(hunt.monster.experience * min_count / 5), PlayerLevel * 500); //Опыт при минимальном приросте
        let exp_with_helper = Math.min(Math.round(hunt.fullExperience / 2), PlayerLevel * 500); //Опыт с помощником (50/50)
        if(PlayerLevel > 2) { //Если опыт меньше нижней отсечки по уровню (3+ уровни)
            exp_with_helper = Math.max(exp_with_helper, PlayerLevel * 35);
            exp_min_count = Math.max(exp_min_count, PlayerLevel * 14);
        }
        exp_with_helper = (exp_with_helper * koef).toFixed(0);
        exp_min_count = (exp_min_count * koef).toFixed(0);

        if(isLookingFor && isHuntMatch(hunt)) {
            hunt.huntDescriptionPanel.closest("div[id^=neut_show]").style.background = "#D1FFD1";
        }
        const fullExperienceText = hunt.experience != hunt.fullExperience ? ` (${isEn ? "from" : "из"} ${hunt.fullExperience})` : "";
        hunt.huntDescriptionPanel.insertAdjacentHTML("beforeend", `
<style>
.huntVariants {
    border-collapse: collapse;
}
.huntVariants td,
.huntVariants th {
    font-size: 7pt;
    border: 1px solid #b94a48 !important;
}
</style>
<table class="huntVariants">
    <tr><th>${isEn ? "Hunt" : "Варианты охоты"}</th><th>${isEn ? "Exp" : "Опыт"}</th><th>${isEn ? "Next amount" : "След. кол-во"}</th></tr>
    <tr><td>${isEn ? "by oneself" : "в одиночку"} 100%</td><td>${hunt.experience}${fullExperienceText}</td><td>${(hunt.amount * 1.3).toFixed(0)}</td></tr>
    <tr${getPlayerBool("enable_Exp_Half") ? "" : " style='display: none;'"}><td>${isEn ? "with a partner" : "с напарником"} 50%</td><td>${exp_with_helper}</td><td>${(hunt.amount * Math.pow(1.3, 0.5)).toFixed(0)}</td></tr>
    <tr${getPlayerBool("enable_5_procent") ? "" : " style='display: none;'"}><td title="${isEn ? "with a partner for min growth 5.6%" : "с напарником для минимального прироста в 5.6%"}">${isEn ? "with a partner" : "с напарником"} 20% (${min_count})</td><td>${exp_min_count}</td><td>${(hunt.amount * Math.pow(1.3, 0.2)).toFixed(0)}</td></tr>
</table>
`);
        if(hunt.experience < (PlayerLevel + 1) * 100 && PlayerLevel > 1) {
            hunt.huntDescriptionPanel.insertAdjacentHTML("beforeend", `<br><font style="color:#0000CD">${isEn ? "Kill it now! On level" : "Убей сейчас! На"} ${PlayerLevel + 1} ${isEn ? " you gain" : "уровне за них дадут"} <b>${(PlayerLevel + 1) * 100}</b> ${isEn ? "exp" : "опыта"}.</font>`);
        }
    }
}
function correctWars(name, playerId = PlayerId) {
    const wars = JSON.parse(getValue(`${name}${playerId}`, "[]")).map(x => JSON.parse(x));
    for(const war of wars) {
        if(war.warDate) {
            war.date = war.warDate;
            delete war.warDate;
        }
        if(war.warId) {
            war.id = war.warId;
            delete war.warId;
        }
        if(!war.enemyName) {
            war.enemyName = name;
        }
        if(!war.type) {
            war.type = 0;
        }
    }
    setValue(`${name}${playerId}`, JSON.stringify(wars.map(x => JSON.stringify(x))));
}
function createTraceMonstersPanelCaller(monstersListContainer) {
    const monstersListActivator = addElement('div', { id: "get_list_go", class: "job_fl_btn show_hint", style: "width: 20px; height: 20px; vertical-align: middle; display: inline-block;", innerHTML: `<img src="//dcdn.heroeswm.ru/i/mobile_view/icons_add/pismo.png" style="width: 16px; height: 16px;">` }, monstersListContainer);
    monstersListActivator.addEventListener("click", showMonstersPanel);
}
function showMonstersPanel() {
    const panelName = "Monsters";
    let bg = document.getElementById(`bg${panelName}Overlay`);
    let bgc = document.getElementById(`bg${panelName}Center`);
    if(bg) {
        bg.style.display = "block";
        bgc.style.display = "block";
        return;
    }
    bg = addElement('div', { id: `bg${panelName}Overlay`, style: "position: fixed; left: 0px; width: 100%; top: 0px; height: 100%; background: #000000; opacity: 0.5; z-index: 1120;" }, document.body);
    const topStyle = isMobileDevice ? "top: 0;" : "top: 50%; transform: translateY(-50%);";
    bgc = addElement('div', { id: `bg${panelName}Center`, style: `position: fixed; left: ${(document.body.offsetWidth - 650) / 2}px; width: 650px; ${topStyle} height: 100%; overflow: auto; background: #F6F3EA; z-index: 1121;` }, document.body);
    bg.addEventListener("click", function() { hidePanel(panelName); }); //клик вне окна
    let monstersTableHtml = "";
    for(const monster of monsters) {
        const imageName = monster.imageFullName || `${monster.imageName || monster.name}anip33`;
        const imageSource = `https://dcdn.heroeswm.ru/i/portraits/${imageName}.png`;
        monstersTableHtml += `
<tr name="${monster.name}">
    <td style="text-align: center;"><img name=monsterPicture style="height: 25px; width: 30px; border: 0; display: ${getPlayerBool("viewMonsterPictures") ? "" : "none"};" src="${imageSource}"></td>
    <td style="text-align: center;"><input name=title type=text value="${isEn && monster.enTitle ? monster.enTitle : monster.title}"></td>
    <td style="text-align: center;"><input name=experience type=number value="${monster.experience}" style="width: 70px;"></td>
    <td style="text-align: center;"><input name=health type=number value="${monster.health}" style="width: 70px;"></td>
    <td style="text-align: center;"><input name=canFly type=checkbox ${monster.canFly ? "checked" : ""}></td>
    <td style="text-align: center;"><input name=wanted type=checkbox ${monster.wanted ? "checked" : ""}></td>
    <td style="text-align: center;"><input name=newYear type=checkbox ${monster.newYear ? "checked" : ""}></td>
</tr>`;
    }
    bgc.innerHTML = `
<style>
    .grid {
        border-collapse: collapse;
    }
    .grid th, .grid td {
        border: 1px solid black;
    }
    .grid-header td {
        text-align: center;
        font-weight: bold;
    }
</style>
<div style="border: 1px solid #abc; padding: 5px; margin: 2px;">
    <div>
        <b>${isEn ? "Select creatures for hunt. Total" : "Выберите существ для охоты. Всего"} <font style="color: #FF0000;">${monsters.length}</font></b>
        <input type="button" id="lookForAllButton" value="${isEn ? "Look for all" : "Искать всех"}">
        <input type="button" id="dontLookForAnyoneButton" value="${isEn ? "Don't look for anyone" : "Не искать никого"}">
        <input type="button" id="deleteGreatCreaturesButton" value="${isEn ? "Delete great creatures from portal" : "Удалить великих существ из портала"}">
        <button id="closeMonstersListButton" type="button" style="float: right; cursor: pointer; font-size: 20px;" title="${isEn ? "Close" : "Закрыть"}">&times;</button>
        <hr/>
    </div>
    <table class=grid cellspacing="0">
        <tr class="grid-header">
            <td><input type=checkbox id=viewMonsterPicturesCheckbox title="${isEn ? "Show pictures" : "Показать картинки"}"></td>
            <td>${isEn ? "Title" : "Заголовок"}</td>
            <td>${isEn ? "Experience" : "Опыт"}</td>
            <td>${isEn ? "Health" : "Здоровье"}</td>
            <td>${isEn ? "Can fly" : "Летает"}</td>
            <td>${isEn ? "Wanted" : "Разыски<br>вается"}</td>
            <td>${isEn ? "New year" : "Ново<br>годний"}</td>
        </tr>
        ${monstersTableHtml}
    </table>
</div>`;
    document.getElementById("viewMonsterPicturesCheckbox").addEventListener("click", function() { setPlayerValue("viewMonsterPictures", this.checked); toggleMonsterPictures(); });
    document.getElementById("viewMonsterPicturesCheckbox").checked = getPlayerBool("viewMonsterPictures");

    document.getElementById('lookForAllButton').addEventListener("click", wantedAll);
    document.getElementById('dontLookForAnyoneButton').addEventListener("click", unwantAll);
    
    const deleteGreatCreaturesButton = document.getElementById('deleteGreatCreaturesButton');
    const megaMonsters = JSON.parse(getValue("monsters", "[]")).filter(x => x.name.startsWith("mega_"));
    deleteGreatCreaturesButton.style.display = megaMonsters.length > 0 ? "" : "none";
    deleteGreatCreaturesButton.addEventListener("click", function() {
        const newMonsters = JSON.parse(getValue("monsters", "[]")).filter(x => !x.name.startsWith("mega_"));
        setValue("monsters", JSON.stringify(newMonsters));
        location.reload();
    });
    document.getElementById("closeMonstersListButton").addEventListener("click", function() { hidePanel(panelName); }); //крестик в углу
    Array.from(bgc.querySelectorAll("input[name=title]")).forEach(x => x.addEventListener("change", function() { setMonsterProperty(this.closest("tr").getAttribute("name"), isEn ? "enTitle" : "title", this.value); }));
    Array.from(bgc.querySelectorAll("input[name=experience]")).forEach(x => x.addEventListener("change", function() { setMonsterProperty(this.closest("tr").getAttribute("name"), this.name, this.value); }));
    Array.from(bgc.querySelectorAll("input[name=health]")).forEach(x => x.addEventListener("change", function() { setMonsterProperty(this.closest("tr").getAttribute("name"), this.name, this.value); }));
    Array.from(bgc.querySelectorAll("input[name=canFly]")).forEach(x => x.addEventListener("change", function() { setMonsterProperty(this.closest("tr").getAttribute("name"), this.name, this.checked); }));
    Array.from(bgc.querySelectorAll("input[name=wanted]")).forEach(x => x.addEventListener("change", function() { setMonsterProperty(this.closest("tr").getAttribute("name"), this.name, this.checked); }));
    Array.from(bgc.querySelectorAll("input[name=newYear]")).forEach(x => x.addEventListener("change", function() { setMonsterProperty(this.closest("tr").getAttribute("name"), this.name, this.checked); }));
}
function toggleMonsterPictures() {
    Array.from(document.querySelectorAll("img[name=monsterPicture]")).forEach(x => x.style.display = getPlayerBool("viewMonsterPictures") ? "" : "none");
}
function setMonsterProperty(monsterName, propertyName, propertyValue) {
    //console.log(`monsterName: ${monsterName}, propertyName: ${propertyName}, propertyValue: ${propertyValue}`);
    const newMonsters = JSON.parse(getValue("monsters", "[]"));
    let monster = newMonsters.find(x => x.name == monsterName);
    if(!monster) {
        monster = monsters.find(x => x.name == monsterName);
        newMonsters.push(monster);
    }
    monster[propertyName] = propertyValue;
    setValue("monsters", JSON.stringify(newMonsters));
}
function wantedAll() {
    monsters.forEach(x => { x.wanted = true; });
    setValue("monsters", JSON.stringify(monsters));
    bindWanted();
}
function unwantAll() {
    monsters.forEach(x => { x.wanted = false; });
    setValue("monsters", JSON.stringify(monsters));
    bindWanted();
}
function bindWanted() {
    const monstersPanel = document.querySelector(`#bgMonstersCenter`);
    Array.from(monstersPanel.querySelectorAll("input[name=wanted]")).forEach(x => {
        const monster = monsters.find(y => y.name == x.closest("tr").getAttribute("name"));
        x.checked = monster?.wanted || false;
    });
}
function createSettingsCaller() {
    const settingsButtonContainer = document.querySelector("div#hwm_map_objects_and_buttons > div.job_fl_btns_block");
    if(settingsButtonContainer) {
        let huntHelperSettingsButton = document.querySelector("#huntHelperSettingsButton"); // console.log(huntHelperSettingsButton); - всегда нул
        if(!huntHelperSettingsButton) {
            settingsButtonContainer.insertAdjacentHTML("beforeend", `
    <a id=huntHelperSettingsButton href="javascript:void(0);" class="map_sel_obj_t" style="width: 200px;">
        <div class="job_fl_btn show_hint" hint="${isEn ? "HuntHelper script settings" : "Настройки скрипта HuntHelper"}">
            <img src="https://dcdn.heroeswm.ru/i/btns/job_fl_btn_hunters.png">
        </div>
    </a>`);
            huntHelperSettingsButton = document.querySelector("#huntHelperSettingsButton");
            huntHelperSettingsButton.addEventListener("click", showSettingsPanel);
            if(typeof win.hwm_hints_init === 'function') win.hwm_hints_init();
        }
    }
}
function showSettingsPanel() {
    const panelName = "hwmHuntHelperSettings";
    if(showPupupPanel(panelName)) {
        return;
    }
    const innerHtml = `
    <label><input type=checkbox id=isShortHuntDescriptionCheckbox> ${isEn ? "Brief hunt description" : "Краткое сообщение об охоте"}</label>
    <br>
    <label><input type=checkbox id=showTotalMonstersHealthCheckBox> ${isEn ? "Show total monsters health" : "Показать суммарное здоровье монстров"}</label>
    <br>
    <label><input type=checkbox id=set_enable_Exp_Half> ${isEn ? "Show <b>exp with helper</b>, if kill 50% each" : "Отображать <b>опыт с помощником</b>, если убьёте по 50%"}</label>
    <br>
    <label><input type=checkbox id=set_enable_5_procent> ${isEn ? "Display how many creatures to kill <b>for the minimum increase</b> of creatures" : "Отображать сколько убить существ <b>для минимального прироста</b> существ"}</label>
    <hr/>
    <label><input type=checkbox id=set_show_archive> ${isEn ? "Show <b>archive records links</b>" : "Отображать <b>ссылки на рекорды</b> из архива"}</label> <img src="https://dcdn.heroeswm.ru/i/icons/attr_knowledge.png" width="18">
    <br>
    <label><input type=checkbox id=hideHuntsCheckbox> ${isEn ? "Hide hunts" : "Скрыть охоты"} (<b><font color=green size=3>GreenPeace</font></b>)</label>
    <br>
    ${isEn ? "Overexp rate" : "Коэффициент перекача"} <input id="set_koef" value="${getPlayerValue("koef_dop_exp", 1)}" style="width: 100px;" maxlength="6" type="number">
    <hr/>
    <label><input type=checkbox id=skipUnmatchedHuntsCheckbox> ${isEn ? "Skip unmatched hunts" : "Пропускать неподходящие охоты"}</label>
    <br>
    <b>${isEn ? "Looking for" : "Искать"}</b>
    <br>
    <label>1) <input type=checkbox id=lookingForMarkedInListCheckbox> ${isEn ? "creatures marked in the list" : "существ отмеченных в списке"}</label><span id=monstersListContainer></span>
    <br>
    2) ${isEn ? "experience less then" : "опыт меньше, чем"}: <input id="experienceLimitInput" type="number" value="${getPlayerValue("experienceLimit", "0")}" style="width: 70px;">
    <br>
    <label>3) <input type=checkbox id=lookingForHalfAmountCheckbox> ${isEn ? "half amount ([1/2])" : "половинки ([1/2])"}</label>
    <br>
    <label>4) <input type=checkbox id=lookingForDiamondCheckbox> <img width="16" height="16" border="0" title="${isEn ? "Diamonds" : "Бриллианты"}" src="https://dcdn.heroeswm.ru/i/r/48/diamonds.png"></label>
    <br>
    <label>5) <input type=checkbox id=lookingForFlyingCheckbox> ${isEn ? "flying" : "летающих"}</label>
    <br>
    <span><label>6) <input type=checkbox id=lookingForAdvancedGuildPointsCheckbox> ${isEn ? "advanced guild points" : "увеличенные очки гильдии"}</label> <form style="display: inline-block;" oninput="minAdvancedPointsOutput.value = minAdvancedPointsInput.value"><input id=minAdvancedPointsInput type=range list=advancedGuildPointsDatalist min=2 max=5 style="width: 60px; vertical-align: middle;" onfocus="this.select();"/><output name=minAdvancedPointsOutput for="minAdvancedPointsInput"></output></form> ${isEn ? "and more" : "и более"}</span>
    <datalist id="advancedGuildPointsDatalist">
      <option value="2"></option>
      <option value="3"></option>
      <option value="5"></option>
    </datalist>`;
    const settingsDiv = addElement("div", { innerHTML: innerHtml });
    bindSettings(settingsDiv);
    bindSettingsHandlers(settingsDiv);

    createTraceMonstersPanelCaller(settingsDiv.querySelector("#monstersListContainer"));

    const fieldsMap = [];
    fieldsMap.push([settingsDiv]);
    const title = `${getScriptReferenceHtml()} ${getSendErrorMailReferenceHtml()} ${isEn ? "Creatures total" : "Всего существ"}: <font style="color:#FF0000;">${monsters.length}</font>`;
    createPupupPanel(panelName, title, fieldsMap);
}
function bindSettings(settingsDiv) {
    settingsDiv.querySelector("#isShortHuntDescriptionCheckbox").checked = getPlayerBool("isShortHuntDescription");
    settingsDiv.querySelector("#set_enable_Exp_Half").checked = getPlayerBool("enable_Exp_Half");
    settingsDiv.querySelector("#set_enable_5_procent").checked = getPlayerBool("enable_5_procent");
    settingsDiv.querySelector("#set_show_archive").checked = getPlayerBool("show_archive");
    settingsDiv.querySelector("#hideHuntsCheckbox").checked = getPlayerBool("hideHunts");

    settingsDiv.querySelector("#skipUnmatchedHuntsCheckbox").checked = getPlayerBool("skipUnmatchedHunts");
    settingsDiv.querySelector("#lookingForMarkedInListCheckbox").checked = getPlayerBool("lookingForMarkedInList");
    settingsDiv.querySelector("#experienceLimitInput").value = getPlayerValue("experienceLimit", "");
    settingsDiv.querySelector("#lookingForHalfAmountCheckbox").checked = getPlayerBool("lookingForHalfAmount");
    settingsDiv.querySelector("#lookingForDiamondCheckbox").checked = getPlayerBool("lookingForDiamond");
    settingsDiv.querySelector("#lookingForFlyingCheckbox").checked = getPlayerBool("lookingForFlying");
    settingsDiv.querySelector("#lookingForAdvancedGuildPointsCheckbox").checked = getPlayerBool("lookingForAdvancedGuildPoints");
    settingsDiv.querySelector("#minAdvancedPointsInput").value = getPlayerValue("minAdvancedPoints", "2");
    settingsDiv.querySelector("output[name=minAdvancedPointsOutput]").value = getPlayerValue("minAdvancedPoints", "2");

    settingsDiv.querySelector("#showTotalMonstersHealthCheckBox").checked = getPlayerBool("showTotalMonstersHealth", true);
}
function bindSettingsHandlers(settingsDiv) {
    settingsDiv.querySelector("#isShortHuntDescriptionCheckbox").addEventListener("click", function() { setPlayerValue("isShortHuntDescription", this.checked); });
    settingsDiv.querySelector("#set_enable_Exp_Half").addEventListener("click", function() { setPlayerValue("enable_Exp_Half", this.checked); });
    settingsDiv.querySelector("#set_enable_5_procent").addEventListener("click", function() { setPlayerValue("enable_5_procent", this.checked); });
    settingsDiv.querySelector("#set_show_archive").addEventListener("click", function() { setPlayerValue("show_archive", this.checked); });
    settingsDiv.querySelector("#hideHuntsCheckbox").addEventListener("click", function() { setPlayerValue("hideHunts", this.checked); applyGreenPeace(); });
    settingsDiv.querySelector("#set_koef").addEventListener("change", function() { setPlayerValue("koef_dop_exp", Number(this.value)); });

    settingsDiv.querySelector("#skipUnmatchedHuntsCheckbox").addEventListener("click", function() { setPlayerValue("skipUnmatchedHunts", this.checked); });
    settingsDiv.querySelector("#lookingForMarkedInListCheckbox").addEventListener("click", function() { setPlayerValue("lookingForMarkedInList", this.checked); });
    settingsDiv.querySelector("#experienceLimitInput").addEventListener("change", function() { setPlayerValue("experienceLimit", this.value); });
    settingsDiv.querySelector("#lookingForHalfAmountCheckbox").addEventListener("click", function() { setPlayerValue("lookingForHalfAmount", this.checked); });
    settingsDiv.querySelector("#lookingForDiamondCheckbox").addEventListener("click", function() { setPlayerValue("lookingForDiamond", this.checked); });
    settingsDiv.querySelector("#lookingForFlyingCheckbox").addEventListener("click", function() { setPlayerValue("lookingForFlying", this.checked); });
    settingsDiv.querySelector("#lookingForAdvancedGuildPointsCheckbox").addEventListener("click", function() { setPlayerValue("lookingForAdvancedGuildPoints", this.checked); });
    settingsDiv.querySelector("#minAdvancedPointsInput").addEventListener("change", function() { setPlayerValue("minAdvancedPoints", this.value); });

    settingsDiv.querySelector("#showTotalMonstersHealthCheckBox").addEventListener("click", function() { setPlayerValue("showTotalMonstersHealth", this.checked); });
}
function hidePanel(panelName) {
    document.getElementById(`bg${panelName}Overlay`).style.display = "none";
    document.getElementById(`bg${panelName}Center`).style.display = "none";
}
function isHuntMatch(hunt) {
    if(getPlayerBool("lookingForMarkedInList") && hunt.monster.wanted) {
        return true;
    }
    if(hunt.experience <= Number(getPlayerValue("experienceLimit"))) {
        return true;
    }
    if(getPlayerBool("lookingForHalfAmount") && hunt.isHalfAmount) {
        return true;
    }
    if(getPlayerBool("lookingForDiamond") && hunt.diamonds > 0) {
        return true;
    }
    if(getPlayerBool("lookingForFlying") && hunt.monster.canFly) {
        return true;
    }
    if(getPlayerBool("lookingForAdvancedGuildPoints") && hunt.guildPoints >= parseInt(getPlayerValue("minAdvancedPoints", "2"))) {
        return true;
    }
    return false;
}
function huntHelpers() {
    if(location.pathname != '/group_wars.php') {
        return;
    }
    const battleRows = Array.from(document.querySelectorAll("center table.wb > tbody > tr"));
    for(const titleRow of battleRows.slice(0, 1)) {
        titleRow.cells[3].innerHTML += `
<label style="font-size: 7pt;">${isEn ? "Hunter" : "Охотник"}<input type=checkbox id=set_find_Hunt title=""></label>`;
        titleRow.cells[6].innerHTML += `
<label style="font-size: 7pt;">${isEn ? "Show HP" : "Показать HP"}<input type=checkbox id=showTotalMonstersHealthCheckBox title=""></label>
<label style="font-size: 7pt;">${isEn ? "Signal" : "Сигнал"}<input type=checkbox id=set_beep_if_free title=""></label>`;
        document.querySelector("#set_find_Hunt").addEventListener("click", function() { setPlayerValue("find_Hunt", this.checked); location.reload(); });
        document.querySelector("#set_beep_if_free").addEventListener("click", function() { setPlayerValue("beep_if_free", this.checked); });
        document.querySelector("#showTotalMonstersHealthCheckBox").addEventListener("click", function() { setPlayerValue("showTotalMonstersHealth", this.checked); location.reload(); });
        document.querySelector("#set_find_Hunt").checked = getPlayerBool("find_Hunt");
        document.querySelector("#set_beep_if_free").checked = getPlayerBool("beep_if_free");
        document.querySelector("#showTotalMonstersHealthCheckBox").checked = getPlayerBool("showTotalMonstersHealth", true);
    }
    for(const row of battleRows.slice(1)) {
        const mapRef = row.querySelector("td > a[href*='map.php?cx']");
        if(!mapRef) {
            if(getPlayerBool("find_Hunt")) {
                row.style.display = "none";
            }
            continue;
        }
        const battleDescriptionCell = row.childNodes[6];
        const monstrRef = battleDescriptionCell.querySelector("a[href^='army_info.php?name=']");
        const monsterTitle = monstrRef.querySelector("i").innerText;
        const monstersAmount = parseInt(monstrRef.parentNode.innerHTML.match(/\((\d+)\)/)[1]);
        const monster = monsters.find(x => x.title == monsterTitle);
        if(!monster) {
            console.log(`Не найден monsterTitle: ${monsterTitle}, monstersAmount: ${monstersAmount}`)
            continue;
        }
        //console.log(mapRef.href.replace("/map.php", "/move_sector.php").replace(mapRef.search, `?id=${sectors[mapRef.search.slice(1)]}`));

        mapRef.href = mapRef.href.replace("/map.php", "/move_sector.php").replace(mapRef.search, `?id=${sectors[mapRef.search.slice(1)]}`);
        mapRef.title = isEn ? "Go" : "Перейти";

        const total_exp = Math.floor(monster.experience * monstersAmount / 5);
        const backgroundColor = total_exp < PlayerLevel * 133 ? "#cfd" : (total_exp < PlayerLevel * 100 ? "#0f0" : 'inherit');
        battleDescriptionCell.insertAdjacentHTML("beforeend", `<br><font style="font-size: 7pt; color: #013220; background-color: ${backgroundColor};"><b>${total_exp}</b></font>${isEn ? "&nbspexp." : "&nbspопыта."}`);
        if(getPlayerBool("showTotalMonstersHealth", true)) {
            battleDescriptionCell.insertAdjacentHTML("beforeend", ` <font style="font-size: 7pt; color: #CD00CD">HP:&nbsp;<b>${monster.health * monstersAmount}</b></font>`);
        }
        if(getPlayerBool("beep_if_free") && battleDescriptionCell.innerHTML.includes(isEn ? "Join" : "Вступить")) {
            new Audio("https://zvukogram.com/mp3/cats/1002/vyistrel-iz-vintovki-po-misheni.mp3").play();
        }
    }
}
function add_archive() {
    //добавить ссылку на архив рекордов на странице рекордов
    if(location.pathname != "/plstats_hunters.php") {
        return;
    }
    //const container = document.querySelector("body > center > table table")?.closest("div");
    const container = document.body;
    //console.log(container)
    if(!container) {
        return;
    }
    const show_archive = getUrlParamValue(location.href, "show_archive");
    let alterRecordsUrl;
    if(show_archive != "1") {
        const mid = getUrlParamValue(location.href, "mid");
        if(!mid) {
            alterRecordsUrl = location.href + '&show_archive=1';
        } else {
            alterRecordsUrl = location.href.replace("&mid", "&show_archive=1&mid");
        }
    } else {
        alterRecordsUrl = location.href.replace(/&?show_archive=1/, "");
    }
    const alterRecordsText = show_archive == "1" ? (isEn ? "Current records" : "Текущие рекорды") : (isEn ? "Records archive before 01.03.2015" : "Архив рекордов до 01.03.2015");
    container.insertAdjacentHTML("beforeend", `<br><center><a href="${alterRecordsUrl}"><b><font color="blue">${alterRecordsText}</font></b></a></center>`);
}
function applyGreenPeace() {
    const map_hunt_block_div = document.querySelector("#map_hunt_block_div");
    if(map_hunt_block_div) {
        map_hunt_block_div.style.display = getPlayerBool("hideHunts") ? "none" : "block";
    }
}
async function readWarlog(e = null, playerId = PlayerId, pages = 0) {
    if(warlogProcessing) {
        const terminateProcessConfirm = confirm(isEn ? "Stop?" : "Прервать?");
        if(terminateProcessConfirm) {
            terminateProcess = true;
        }
        return;
    }
    const warStatistics = JSON.parse(getValue(`WarStatistics${playerId}`, "{}"));
    let warlogScanned = warStatistics.minWarId > 0 && warStatistics.firstWarId == warStatistics.minWarId;
    if(!warlogScanned && !confirm(isEn ? "It takes about 20 minutes. Continue?" : "Это займет около 20-ти минут. Продолжить?")) {
        return;
    }
    warlogProcessing = true;
    terminateProcess = false;
    let { lastWarlogPageIndex, firstWarId } = await getLastWarlogPageIndex(playerId);   //console.log(`playerId: ${playerId}, pages: ${pages}, lastWarlogPageIndex: ${lastWarlogPageIndex}`);

    warStatistics.firstWarId = firstWarId;    console.log(warStatistics);
    warlogScanned = warStatistics.minWarId > 0 && warStatistics.firstWarId == warStatistics.minWarId;
    if(pages) {
        lastWarlogPageIndex = Math.min(lastWarlogPageIndex, pages - 1);
    }
    let totalWars = 0;
    let totalPages = 0;
    let minDate;
    let maxDate;
    let minWarId;
    let maxWarId;
    let currentPageIndex = 0;
    while(currentPageIndex <= lastWarlogPageIndex) {
        if(e) {
            e.target.value = `${isEn ? "Process page" : "Обработка страницы"} ${currentPageIndex + 1} ${isEn ? "from" : "из"} ${lastWarlogPageIndex + 1}. ${isEn ? "Break?" : "Остановить?"}`;
        }
        if(terminateProcess) {
            break;
        }
        //console.log(`currentPageIndex: ${currentPageIndex}`);
        const wars = await parseWarlogPage(playerId, currentPageIndex);
        //console.log(wars);
        wars.forEach(x => {
            minWarId = !minWarId ? x.id : Math.min(minWarId, x.id);
            maxWarId = !maxWarId ? x.id : Math.max(maxWarId, x.id);
            minDate = !minDate || x.date < minDate ? x.date : minDate;
            maxDate = !maxDate || x.date > maxDate ? x.date : maxDate;
        });
        totalPages++;
        totalWars += wars.length;
        for(const war of wars) {
            if(isMercBattle(war.type) || war.type == 0) {
                storeWar(war, playerId);
            }
            if(!terminateProcess &&  warlogScanned && war.id < warStatistics.maxWarId) {
                console.log(`Прерываю процесс warlogScanned: ${warlogScanned}, war.id: ${war.id}, warStatistics.maxWarId: ${warStatistics.maxWarId}`);
                terminateProcess = true; // Для дополнительных сканирований после основного. Читаем не все страницы, а только новые
            }
        }
        if(!pages && currentPageIndex == lastWarlogPageIndex && minWarId > warStatistics.firstWarId) {
            lastWarlogPageIndex++; // Если зачитываем всю статистику до конца, то количество страниц могло возрасти. Тогда зачитаем ещё страницу.
        }
        currentPageIndex++;
    }
    warStatistics.minWarId = !warStatistics.minWarId || minWarId < warStatistics.minWarId ? minWarId : warStatistics.minWarId;
    warStatistics.maxWarId = !warStatistics.maxWarId || maxWarId > warStatistics.maxWarId ? maxWarId : warStatistics.maxWarId;
    warStatistics.minDate = !warStatistics.minDate || minDate < new Date(warStatistics.minDate) ? minDate : new Date(warStatistics.minDate);
    warStatistics.maxDate = !warStatistics.maxDate || maxDate > new Date(warStatistics.maxDate) ? maxDate : new Date(warStatistics.maxDate);
    warlogScanned = warStatistics.minWarId > 0 && warStatistics.firstWarId == warStatistics.minWarId;
    setValue(`WarStatistics${playerId}`, JSON.stringify(warStatistics));
    warlogProcessing = false;
    if(e) {
        const getWarsStatisticsName = warlogScanned ? (isEn ? "Append war statistics" : "Пополнить боевую статистику") : (isEn ? "Get war statistics" : "Получить боевую статистику");
        e.target.value = getWarsStatisticsName;
    }
}
async function parseWarlogPage(playerId, pageIndex) {
    const doc = await getRequest(`/pl_warlog.php?id=${playerId}&page=${pageIndex}`);
    const warRefs = Array.from(doc.querySelectorAll("div.global_a_hover > a[href^='warlog.php?warid=']"));
    const wars = [];
    for(const warRef of warRefs) {
        const warId = parseInt(getUrlParamValue(warRef.href, "warid"));
        const warDate = parseDate(warRef.innerText, false, true);
        const leftSideNodes = [];
        const rightSideNodes = [];
        let currentSide = leftSideNodes;
        let node = warRef;
        while((node = node.nextSibling) && node.nodeType != Node.COMMENT_NODE) {
            //console.log(`node.nodeType: ${node.nodeType}`);
            if(node.nodeType == Node.TEXT_NODE) {
                if(node.textContent == " vs ") {
                    currentSide = rightSideNodes;
                }
                continue;
            }
            currentSide.push(node);
        }
        const warType = parseInt(node.textContent); // Нашли комментарий с кодом типа боя
        let playerNode = leftSideNodes.find(x => x.outerHTML.includes(`pl_info.php?id=${playerId}`));
        const enemyNodes = playerNode ? rightSideNodes : leftSideNodes;
        if(!playerNode) {
            playerNode = rightSideNodes.find(x => x.outerHTML.includes(`pl_info.php?id=${playerId}`));
        }
        const isWin = playerNode.nodeName.toLowerCase() == "b";
        const playerNameExec = />(.+)\[(\d+)\]</.exec(playerNode.innerHTML);
        const playerLevel = parseInt(playerNameExec[2]);
        //console.log(`warId: ${warId}, warType: ${warType}, warDate: ${warDate}, isWin: ${isWin}, playerLevel: ${playerLevel}, isMercBattle: ${isMercBattle(warType)}`);
        const war = { id: warId, date: warDate, type: warType, isWin: isWin, playerLevel: playerLevel, enemyName: "", enemyLevel: "" };
        if(isMercBattle(warType)) {
             let enemyNode = enemyNodes[0];
             const enemyExec = /(.+) {(\d+)}/.exec(enemyNode.firstChild.innerText || enemyNode.firstChild.textContent);
             if(enemyExec) {
                 war.enemyName = enemyExec[1];
                 war.enemyLevel = parseInt(enemyExec[2]);
             }
        }
        if(warType == 0) {
             let enemyNode = enemyNodes[0];
             const enemyExec = /(.+) \((\d+)\)/.exec(enemyNode.firstChild.innerText || enemyNode.firstChild.textContent);
             if(enemyExec) {
                 war.enemyName = enemyExec[1];
                 war.enemyLevel = parseInt(enemyExec[2]);
             }
        }
        wars.push(war);
    }
    return wars;
}
async function getLastWarlogPageIndex(playerId = PlayerId) {
  const responseText = await getRequestText(`/pl_warlog.php?id=${playerId}&page=999999`);
  const pageExec = /a class="active" href="#">(\d+?)</gmi.exec(responseText);
  const doc = (new DOMParser).parseFromString(responseText, "text/html");
  const warRefs = Array.from(doc.querySelectorAll("div.global_a_hover > a[href^='warlog.php?warid=']"));
  const firstWarId = warRefs.map(x => parseInt(getUrlParamValue(x.href, "warid"))).reduce((t, x) => { return t == 0 || x < t ? x : t }, 0);
  return { lastWarlogPageIndex: pageExec ? (parseInt(pageExec[1]) - 1) : 0, firstWarId: firstWarId };
}
function isMercBattle(btype = win.btype) { return btype == _GN_OTRYAD || btype == _GN_MONSTER || btype == _GN_NABEGI || btype == _GN_ZASHITA || btype == _GN_ARMY || btype == _SURVIVALGN || btype == _NEWGNCARAVAN; }
function storeWar(war, playerId) {
    const enemyHistory = restoreWars(war.enemyName, playerId); //JSON.parse(getValue(`${war.enemyName}${playerId}`, "[]")).map(x => JSON.parse(x));
    let exists = enemyHistory.find(x => x.id == war.id);
    if(!exists) {
        enemyHistory.push(war);
        enemyHistory.sort((a, b) => b.id - a.id); // Сортируем по убыванию id

        //console.log(enemyHistory);
        setValue(`${war.enemyName}${playerId}`, JSON.stringify(enemyHistory.map(x => [x.id, (typeof x.date.getMonth === 'function') ? x.date.toISOString().substr(0, 16).replace("T", " ") : x.date, x.isWin ? 1 : 0, parseInt(x.playerLevel), parseInt(x.enemyLevel)])));
    }
    //console.log(getValue(`${war.enemyName}${playerId}`));
    //console.log(restoreWars(war.enemyName, playerId));
}
function toWar(warArray, name) { return { id: warArray[0], date: warArray[1], isWin: warArray[2] ? true : false, playerLevel: parseInt(warArray[3]), enemyLevel: parseInt(warArray[4]), enemyName: name }; }
function restoreWars(name, playerId) { return JSON.parse(getValue(`${name}${playerId}`, "[]")).map(x => toWar(x, name)); }
function clearWarsStatistics() {
    if(!confirm(isEn ? "Clear?" : "Очистить?")) {
        return;
    }
    let counter = 0;
    for(const key of GM_listValues()) {
        const value = getValue(key);
        if(value && key.startsWith("WarStatistics")) {
            deleteValue(key);
            counter++;
        }
        if(value && typeof(value) == "string" && value.startsWith("[[")) {
            //console.log(`${key}`);
            //console.log(value);
            try {
                const obj = JSON.parse(value);
                console.log(obj);
                if(obj[0]?.length == 5) {
                    deleteValue(key);
                    console.log(`Cleared ${key}`);
                    counter++;
                }
            } catch {
            }
        }
    }
    console.log(`Total cleared ${counter}`);
}
function getMercAgenciesTable() {
    return isEn ? `<table width="90%" border="1" align="center" cellspacing="0" cellpadding="3">
  <tbody><tr>
    <td><div align="center"><img src="//dcdn.heroeswm.ru/i/btns/job_fl_btn_mercenary.png" title="" alt="" width="15" height="15">
      </div>
    </td>
    <td><div align="center"><a href="plstats_merc.php?task=9&amp;level=0&amp;race=0"><b>Army</b></a>
      </div>
    </td>
    <td><div align="center"><a href="plstats_merc.php?task=10&amp;level=0&amp;race=0"><b>Conspirators</b></a>
      </div>
    </td>
    <td><div align="center"><a href="plstats_merc.php?task=2&amp;level=0&amp;race=0"><b>Invaders</b></a>
      </div>
    </td>
    <td><div align="center"><a href="plstats_merc.php?task=4&amp;level=0&amp;race=0"><b>Monster</b></a>
      </div>
    </td>
    <td><div align="center"><a href="plstats_merc.php?task=5&amp;level=0&amp;race=0"><b>Raid</b></a>
      </div>
    </td>
    <td><div align="center"><a href="plstats_merc.php?task=7&amp;level=0&amp;race=0"><b>Vanguard</b></a>
      </div>
    </td>
    <td><div align="center"><a href="plstats_merc.php?task=3&amp;level=0&amp;race=0"><b>Brigands</b></a>
      </div>
    </td>
  </tr>
  <tr>
    <td><div align="center"><b>East River</b></div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
  </tr>
  <tr>
    <td><div align="center"><b>Peaceful Camp</b></div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center">7%</div></td>
  </tr>
  <tr>
    <td><div align="center"><b>Fairy Trees</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center"><b>24%</b></div></td>
  </tr>
  <tr>
    <td><div align="center"><b>Fishing Village</b></div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
  </tr>
</tbody></table>` : `<table width="90%" border="1" align="center" cellspacing="0" cellpadding="3">
  <tbody><tr>
    <td><div align="center"><img src="//dcdn.heroeswm.ru/i/btns/job_fl_btn_mercenary.png" title="Представительство в секторе" alt="Представительство в секторе" width="15" height="15">
      </div>
    </td>
    <td><div align="center"><a href="plstats_merc.php?task=9&amp;level=0&amp;race=0"><b>Армии</b></a>
      </div>
    </td>
    <td><div align="center"><a href="plstats_merc.php?task=10&amp;level=0&amp;race=0"><b>Заговорщики</b></a>
      </div>
    </td>
    <td><div align="center"><a href="plstats_merc.php?task=2&amp;level=0&amp;race=0"><b>Захватчики</b></a>
      </div>
    </td>
    <td><div align="center"><a href="plstats_merc.php?task=4&amp;level=0&amp;race=0"><b>Монстры</b></a>
      </div>
    </td>
    <td><div align="center"><a href="plstats_merc.php?task=5&amp;level=0&amp;race=0"><b>Набеги</b></a>
      </div>
    </td>
    <td><div align="center"><a href="plstats_merc.php?task=7&amp;level=0&amp;race=0"><b>Отряды</b></a>
      </div>
    </td>
    <td><div align="center"><a href="plstats_merc.php?task=3&amp;level=0&amp;race=0"><b>Разбойники</b></a>
      </div>
    </td>
  </tr>
  <tr>
    <td><div align="center"><b>Восточная река</b></div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
  </tr>
  <tr>
    <td><div align="center"><b>Мирный лагерь</b></div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center">7%</div></td>
  </tr>
  <tr>
    <td><div align="center"><b>Магический лес</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center"><b>24%</b></div></td>
  </tr>
  <tr>
    <td><div align="center"><b>Рыбачье село</b></div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
    <td><div align="center"><b>24%</b></div></td>
    <td><div align="center">7%</div></td>
  </tr>
</tbody></table>`;
}
function groupToArray(list, keyFieldOrSelector) { return list.reduce(function(t, item) {
    const keyValue = typeof keyFieldOrSelector === 'function' ? keyFieldOrSelector(item) : item[keyFieldOrSelector];
    const existingGroup = t.find(x => x.key == keyValue);
    if(existingGroup) {
        existingGroup.values.push(item);
    } else {
        t.push({ key: keyValue, values: [item] });
    }
    return t;
}, []); };
// function correctWarsStatistics(e) {
    // if(!confirm(isEn ? "Correct?" : "Исправить?")) {
        // return;
    // }
    // for(const key of GM_listValues()) {
        // const value = getValue(key);
        // if(value && typeof(value) == "string" && value.startsWith("[[")) {
            // const wars = JSON.parse(value);
            // const pureWars = wars.filter(x => x[0] != "{");
            // if(wars.length > pureWars.length && pureWars.length > 0 && Array.isArray(pureWars[0]) && toWar(pureWars[0], key).date) {
                // setValue(key, JSON.stringify(pureWars));
                // e.target.insertAdjacentHTML("afterend", `<div>Очищен от старья ключ ${key}, удалено ${wars.length - pureWars.length} значений</div>`);
            // }
        // }
    // }
// }

// API
function getURL(url) { window.location.href = url; }
function createDataList(inputElement, dataListId, buttonsClass) {
    const datalist = addElement("datalist", { id: dataListId });
    const valuesData = getValue("DataList" + dataListId);
    let values = [];
    if(valuesData) {
        values = valuesData.split(",");
    }
    for(const value of values) {
        addElement("option", { value: value }, datalist);
    }
    inputElement.parentNode.insertBefore(datalist, inputElement.nextSibling);
    inputElement.setAttribute("list", dataListId);

    const clearListButton = addElement("input", { type: "button", value: "x", title: LocalizedString.ClearList, class: buttonsClass, style: "min-width: 20px; width: 20px; text-align: center; padding: 2px 2px 2px 2px;" });
    clearListButton.addEventListener("click", function() { if(window.confirm(LocalizedString.ClearList)) { deleteValue("DataList" + dataListId); datalist.innerHTML = ""; } }, false);
    inputElement.parentNode.insertBefore(clearListButton, datalist.nextSibling);

    return datalist;
}
function showCurrentNotification(html) {
    //GM_setValue("CurrentNotification", `{"Type":"1","Message":"The next-sibling combinator is made of the code point that separates two compound selectors. The elements represented by the two compound selectors share the same parent in the document tree and the element represented by the first compound selector immediately precedes the element represented by the second one. Non-element nodes (e.g. text between elements) are ignored when considering the adjacency of elements."}`);
    if(!isHeartOnPage) {
        return;
    }
    let currentNotificationHolder = document.querySelector("div#currentNotificationHolder");
    let currentNotificationContent = document.querySelector("div#currentNotificationContent");
    if(!currentNotificationHolder) {
        currentNotificationHolder = addElement("div", { id: "currentNotificationHolder", style: "display: flex; position: fixed; transition-duration: 0.8s; left: 50%; transform: translateX(-50%); bottom: -300px; width: 200px; border: 2px solid #000000; background-image: linear-gradient(to bottom, #EAE0C8 0%, #DBD1B9 100%); font: 10pt sans-serif;" }, document.body);
        currentNotificationContent = addElement("div", { id: "currentNotificationContent", style: "text-align: center;" }, currentNotificationHolder);
        const divClose = addElement("div", { title: isEn ? "Close" : "Закрыть", innerText: "x", style: "border: 1px solid #abc; flex-basis: 15px; height: 15px; text-align: center; cursor: pointer;" }, currentNotificationHolder);
        divClose.addEventListener("click", function() {
            const rect = currentNotificationHolder.getBoundingClientRect();
            currentNotificationHolder.style.bottom = `${-rect.height-1}px`;
        });
    }
    currentNotificationContent.innerHTML = html;
    const rect = currentNotificationHolder.getBoundingClientRect();
    currentNotificationHolder.style.bottom = `${-rect.height-1}px`;
    currentNotificationHolder.style.bottom = "0";
    setTimeout(function() { currentNotificationHolder.style.bottom = `${-rect.height-1}px`; }, 3000);
}
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
// Array and object
function groupBy(list, keyFieldOrSelector) { return list.reduce(function(t, item) { const keyValue = typeof keyFieldOrSelector === 'function' ? keyFieldOrSelector(item) : item[keyFieldOrSelector]; (t[keyValue] = t[keyValue] || []).push(item); return t; }, {}); };
function getKeyByValue(object, value) { return Object.keys(object).find(key => object[key] === value); }
function findKey(obj, selector) { return Object.keys(obj).find(selector); }
function pushNew(array, newValue) { if(array.indexOf(newValue) == -1) { array.push(newValue); } }
function sortBy(field, reverse, evaluator) {
    const key = evaluator ? function(x) { return evaluator(x[field]); } : function(x) { return x[field]; };
    return function(a, b) { return a = key(a), b = key(b), (reverse ? -1 : 1) * ((a > b) - (b > a)); }
}
// HttpRequests
function getRequest(url, overrideMimeType = "text/html; charset=windows-1251") {
    return new Promise((resolve, reject) => {
        GM.xmlHttpRequest({ method: "GET", url: url, overrideMimeType: overrideMimeType,
            onload: function(response) { resolve((new DOMParser).parseFromString(response.responseText, "text/html")); },
            onerror: function(error) { reject(error); }
        });
    });
}
function getRequestText(url, overrideMimeType = "text/html; charset=windows-1251") {
    return new Promise((resolve, reject) => {
        GM.xmlHttpRequest({ method: "GET", url: url, overrideMimeType: overrideMimeType,
            onload: function(response) { resolve(response.responseText); },
            onerror: function(error) { reject(error); }
        });
    });
}
function postRequest(url, data) {
    return new Promise((resolve, reject) => {
        GM.xmlHttpRequest({ method: "POST", url: url, headers: { "Content-Type": "application/x-www-form-urlencoded" }, data: data,
            onload: function(response) { resolve(response); },
            onerror: function(error) { reject(error); }
        });
    });
}
function fetch({ url, method = 'GET', type = 'document', body = null }) {
    return new Promise((resolve, reject) => {
          const xhr = new XMLHttpRequest();
          xhr.open(method, url);
          xhr.responseType = type;

          xhr.onload = () => {
            if (xhr.status === 200) return resolve(xhr.response);
            throwError(`Error with status ${xhr.status}`);
          };

          xhr.onerror = () => throwError(`HTTP error with status ${xhr.status}`);

          xhr.send(body);

          function throwError(msg) {
            const err = new Error(msg);
            err.status = xhr.status;
            reject(err);
          }
    });
}
// Storage
function getValue(key, defaultValue) { return GM_getValue(key, defaultValue); };
function setValue(key, value) { GM_setValue(key, value); };
function deleteValue(key) { return GM_deleteValue(key); };
function getPlayerValue(key, defaultValue) { return getValue(`${key}${PlayerId}`, defaultValue); };
function setPlayerValue(key, value) { setValue(`${key}${PlayerId}`, value); };
function deletePlayerValue(key) { return deleteValue(`${key}${PlayerId}`); };
function getPlayerBool(valueName, defaultValue = false) { return getBool(valueName + PlayerId, defaultValue); }
function getBool(valueName, defaultValue = false) {
    const value = getValue(valueName);
    //console.log(`valueName: ${valueName}, value: ${value}, ${typeof(value)}`)
    if(value != undefined) {
        if(typeof(value) == "string") {
            return value == "true";
        }
        if(typeof(value) == "boolean") {
            return value;
        }
    }
    return defaultValue;
}
function setOrDeleteNumberValue(key, value) {
    if(!value || value == "" || isNaN(Number(value))) {
        deleteValue(key);
    } else {
        setValue(key, value);
    }
}
function setOrDeleteNumberPlayerValue(key, value) { setOrDeleteNumberValue(key + PlayerId, value); }
function getStorageKeys(filter) { return listValues().filter(filter); }
// Html DOM
function addElement(type, data = {}, parent = undefined, insertPosition = "beforeend") {
    const el = document.createElement(type);
    for(const key in data) {
        if(key == "innerText" || key == "innerHTML") {
            el[key] = data[key];
        } else {
            el.setAttribute(key, data[key]);
        }
    }
    if(parent) {
        if(parent.insertAdjacentElement) {
            parent.insertAdjacentElement(insertPosition, el);
        } else if(parent.parentNode) {
            switch(insertPosition) {
                case "beforebegin":
                    parent.parentNode.insertBefore(el, parent);
                    break;
                case "afterend":
                    parent.parentNode.insertBefore(el, parent.nextSibling);
                    break;
            }
        }
    }
    return el;
}
function addStyle(css) { addElement("style", { type: "text/css", innerHTML: css }, document.head); }
function getParent(element, parentType, number = 1) {
    if(!element) {
        return;
    }
    let result = element;
    let foundNumber = 0;
    while(result = result.parentNode) {
        if(result.nodeName.toLowerCase() == parentType.toLowerCase()) {
            foundNumber++;
            if(foundNumber == number) {
                return result;
            }
        }
    }
}
function getNearestAncestorSibling(node) {
    let parentNode = node;
    while((parentNode = parentNode.parentNode)) {
        if(parentNode.nextSibling) {
            return parentNode.nextSibling;
        }
    }
}
function getNearestAncestorElementSibling(node) {
    let parentNode = node;
    while((parentNode = parentNode.parentNode)) {
        if(parentNode.nextElementSibling) {
            return parentNode.nextElementSibling;
        }
    }
}
function nextSequential(node) { return node.firstChild || node.nextSibling || getNearestAncestorSibling(node); }
function nextSequentialElement(element) { return element.firstElementChild || element.nextElementSibling || getNearestAncestorElementSibling(element); }
function getSequentialsUntil(firstElement, lastElementTagName) {
    let currentElement = firstElement;
    const resultElements = [currentElement];
    while((currentElement = nextSequential(currentElement)) && currentElement.nodeName.toLowerCase() != lastElementTagName.toLowerCase()) {
        resultElements.push(currentElement);
    }
    if(currentElement) {
        resultElements.push(currentElement);
    }
    return resultElements;
}
function findChildrenTextContainsValue(selector, value) { return Array.from(document.querySelectorAll(selector)).reduce((t, x) => { const match = Array.from(x.childNodes).filter(y => y.nodeName == "#text" && y.textContent.includes(value)); return [...t, ...match]; }, []); }
// Popup panel
function createPupupPanel(panelName, panelTitle, fieldsMap, panelToggleHandler) {
    const backgroundPopupPanel = addElement("div", { id: panelName, style: "position: fixed; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgb(0,0,0); background-color: rgba(0,0,0,0.4); z-index: 200;" }, document.body);
    backgroundPopupPanel.addEventListener("click", function(e) { if(e.target == this) { hidePupupPanel(panelName, panelToggleHandler); }});
    const topStyle = isMobileDevice ? "" : "top: 50%; transform: translateY(-50%);";
    const contentDiv = addElement("div", { style: `${topStyle} padding: 5px; display: flex; flex-wrap: wrap; position: relative; margin: auto; padding: 0; width: fit-content; background-image: linear-gradient(to right, #eea2a2 0%, #bbc1bf 19%, #57c6e1 42%, #b49fda 79%, #7ac5d8 100%); border: 1mm ridge rgb(211, 220, 50);` }, backgroundPopupPanel);
    if(panelTitle) {
        addElement("b", { innerHTML: panelTitle, style: "text-align: center; margin: auto; width: 90%; display: block;" }, contentDiv);
    }
    const divClose = addElement("span", { id: panelName + "close", title: isEn ? "Close" : "Закрыть", innerHTML: "&times;", style: "cursor: pointer; font-size: 20px; font-weight: bold;" }, contentDiv);
    divClose.addEventListener("click", function() { hidePupupPanel(panelName, panelToggleHandler); });

    addElement("div", { style: "flex-basis: 100%; height: 0;"}, contentDiv);

    if(fieldsMap) {
        let contentTable = addElement("table", { style: "flex-basis: 100%; width: min-content;"}, contentDiv);
        for(const rowData of fieldsMap) {
            if(rowData.length == 0) { // Спомощью передачи пустой стороки-массива, указываем, что надо начать новую таблицу после брейка
                addElement("div", { style: "flex-basis: 100%; height: 0;"}, contentDiv);
                contentTable = addElement("table", undefined, contentDiv);
                continue;
            }
            const row = addElement("tr", undefined, contentTable);
            for(const cellData of rowData) {
                const cell = addElement("td", undefined, row);
                if(cellData) {
                    if(typeof(cellData) == "string") {
                        cell.innerText = cellData;
                    } else {
                        cell.appendChild(cellData);
                    }
                }
            }
        }
    }
    if(panelToggleHandler) {
        panelToggleHandler(true);
    }
    return contentDiv;
}
function showPupupPanel(panelName, panelToggleHandler) {
    const backgroundPopupPanel = document.getElementById(panelName);
    if(backgroundPopupPanel) {
        backgroundPopupPanel.style.display = '';
        if(panelToggleHandler) {
            panelToggleHandler(true);
        }
        return true;
    }
    return false;
}
function hidePupupPanel(panelName, panelToggleHandler) {
    const backgroundPopupPanel = document.getElementById(panelName);
    backgroundPopupPanel.style.display = 'none';
    if(panelToggleHandler) {
        panelToggleHandler(false);
    }
}
// Script autor and url
function getScriptLastAuthor() {
    let authors = GM_info.script.author;
    if(!authors) {
        const authorsMatch = GM_info.scriptMetaStr.match(/@author(.+)\n/);
        authors = authorsMatch ? authorsMatch[1] : "";
    }
    const authorsArr = authors.split(",").map(x => x.trim()).filter(x => x);
    return authorsArr[authorsArr.length - 1];
}
function getDownloadUrl() {
    let result = GM_info.script.downloadURL;
    if(!result) {
        const downloadURLMatch = GM_info.scriptMetaStr.match(/@downloadURL(.+)\n/);
        result = downloadURLMatch ? downloadURLMatch[1] : "";
        result = result.trim();
    }
    return result;
}
function getScriptReferenceHtml() { return `<a href="${getDownloadUrl()}" title="${isEn ? "Check for update" : "Проверить обновление скрипта"}" target=_blanc>${GM_info.script.name} ${GM_info.script.version}</a>`; }
function getSendErrorMailReferenceHtml() { return `<a href="sms-create.php?mailto=${getScriptLastAuthor()}&subject=${isEn ? "Error in" : "Ошибка в"} ${GM_info.script.name} ${GM_info.script.version} (${GM_info.scriptHandler} ${GM_info.version})" target=_blanc>${isEn ? "Bug report" : "Сообщить об ошибке"}</a>`; }
// Server time
function getServerTime() { return Date.now() - parseInt(getValue("ClientServerTimeDifference", 0)); }
function getGameDate() { return new Date(getServerTime() + 10800000); } // Игра в интерфейсе всегда показывает московское время // Это та дата, которая в toUTCString покажет время по москве
function toServerTime(clientTime) { return clientTime -  parseInt(GM_getValue("ClientServerTimeDifference", 0)); }
function toClientTime(serverTime) { return serverTime +  parseInt(GM_getValue("ClientServerTimeDifference", 0)); }
function truncToFiveMinutes(time) { return Math.floor(time / 300000) * 300000; }
function today() { const now = new Date(getServerTime()); now.setHours(0, 0, 0, 0); return now; }
function tomorrow() { const today1 = today(); today1.setDate(today1.getDate() + 1); return today1; }
async function requestServerTime() {
    if(parseInt(getValue("LastClientServerTimeDifferenceRequestDate", 0)) + 6 * 60 * 60 * 1000 < Date.now()) {
        setValue("LastClientServerTimeDifferenceRequestDate", Date.now());
        const responseText = await getRequestText("/time.php");
        const responseParcing = /now (\d+)/.exec(responseText); //responseText: now 1681711364 17-04-23 09:02
        if(responseParcing) {
            setValue("ClientServerTimeDifference", Date.now() - parseInt(responseParcing[1]) * 1000);
        }
    } else {
        setTimeout(requestServerTime, 60 * 60 * 1000);
    }
}
// dateString - игровое время, взятое со страниц игры. Оно всегда московское // Как результат возвращаем серверную дату
function parseDate(dateString, isFuture = false, isPast = false) {
    //console.log(dateString)
    if(!dateString) {
        return;
    }
    const dateStrings = dateString.split(" ");

    let hours = 0;
    let minutes = 0;
    let seconds = 0;
    const gameDate = getGameDate();
    let year = gameDate.getUTCFullYear();
    let month = gameDate.getUTCMonth();
    let day = gameDate.getUTCDate();
    const timePart = dateStrings.find(x => x.includes(":"));
    if(timePart) {
        var time = timePart.split(":");
        hours = parseInt(time[0]);
        minutes = parseInt(time[1]);
        if(time.length > 2) {
            seconds = parseInt(time[2]);
        }
        if(dateStrings.length == 1) {
            let result = new Date(Date.UTC(year, month, day, hours, minutes, seconds));
            if(isPast && result > gameDate) {
                result.setUTCDate(result.getUTCDate() - 1);
            }
            if(isFuture && result < gameDate) {
                result.setUTCDate(result.getUTCDate() + 1);
            }
            //console.log(`result: ${result}, gameDate: ${gameDate}`)
            result.setUTCHours(result.getUTCHours() - 3);
            return result;
        }
    }

    const datePart = dateStrings.find(x => x.includes("-"));
    if(datePart) {
        const date = datePart.split("-");
        month = parseInt(date[isEn ? (date.length == 3 ? 1 : 0) : 1]) - 1;
        day = parseInt(date[isEn ? (date.length == 3 ? 2 : 1) : 0]);
        if(date.length == 3) {
            const yearText = isEn ? date[0] : date[2];
            year = parseInt(yearText);
            if(yearText.length < 4) {
                year += Math.floor(gameDate.getUTCFullYear() / 1000) * 1000;
            }
        } else {
            if(isFuture && month == 0 && gameDate.getUTCMonth() == 11) {
                year += 1;
            }
        }
    }
    if(dateStrings.length > 2) {
        const letterDateExec = /(\d{2}):(\d{2}) (\d{2}) (.{3,4})/.exec(dateString);
        if(letterDateExec) {
            //console.log(letterDateExec)
            day = parseInt(letterDateExec[3]);
            //const monthNames = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'];
            const monthShortNames = ['янв', 'фев', 'март', 'апр', 'май', 'июнь', 'июль', 'авг', 'сент', 'окт', 'ноя', 'дек'];
            month = monthShortNames.findIndex(x => x.toLowerCase() == letterDateExec[4].toLowerCase());
            if(isPast && Date.UTC(year, month, day, hours, minutes, seconds) > gameDate.getTime()) {
                year -= 1;
            }
        }
    }
    //console.log(`year: ${year}, month: ${month}, day: ${day}, time[0]: ${time[0]}, time[1]: ${time[1]}, ${new Date(year, month, day, parseInt(time[0]), parseInt(time[1]))}`);
    let result = new Date(Date.UTC(year, month, day, hours, minutes, seconds));
    result.setUTCHours(result.getUTCHours() - 3);
    return result;
}
// Misc
async function initUserName() {
    if(location.pathname == "/pl_info.php" && getUrlParamValue(location.href, "id") == PlayerId) {
        //console.log(document.querySelector("h1").innerText)
        setPlayerValue("UserName", document.querySelector("h1").innerText);
    }
    if(location.pathname == "/home.php") {
        //console.log(document.querySelector(`a[href='pl_info.php?id=${PlayerId}'] > b`).innerText)
        setPlayerValue("UserName", document.querySelector(`a[href='pl_info.php?id=${PlayerId}'] > b`).innerText);
    }
    if(!getPlayerValue("UserName")) {
        const doc = await getRequest(`/pl_info.php?id=${PlayerId}`);
        setPlayerValue("UserName", doc.querySelector("h1").innerText);
    }
}
function getUrlParamValue(url, paramName) { return (new URLSearchParams(url.split("?")[1])).get(paramName); }
function showBigData(data) { console.log(data); /*addElement("TEXTAREA", { innerText: data }, document.body);*/ }
function round0(value) { return Math.round(value * 10) / 10; }
function round00(value) { return Math.round(value * 100) / 100; }
function mobileCheck() {
    let check = false;
    (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
    return check;
};
// MutationObserver
function observe(targets, handler, config = { childList: true, subtree: true }) {
    targets = Array.isArray(targets) ? targets : [targets];
    targets = targets.map(x => { if(typeof x === 'function') { return x(document); } return x; }); // Можем передавать не элементы, а их селекторы
    const ob = new MutationObserver(async function(mut, observer) {
        //console.log(`Mutation start`);
        observer.disconnect();
        if(handler.constructor.name === 'AsyncFunction') {
            await handler();
        } else {
            handler();
        }
        for(const target of targets) {
            if(target) {
                observer.observe(target, config);
            }
        }
    });
    for(const target of targets) {
        if(target) {
            ob.observe(target, config);
        }
    }
}
// UpdatePanels
// Если используется url, то это должна быть та же локация с другими параметрами
async function refreshUpdatePanels(panelSelectors, postProcessor, url = location.href) {
    panelSelectors = Array.isArray(panelSelectors) ? panelSelectors : [panelSelectors];
    let freshDocument;
    for(const panelSelector of panelSelectors) {
        const updatePanel = panelSelector(document);
        //console.log(panelSelector.toString())
        //console.log(updatePanel)
        if(updatePanel) {
            freshDocument = freshDocument || await getRequest(url);
            const freshUpdatePanel = panelSelector(freshDocument);
            if(!freshUpdatePanel) {
                console.log(updatePanel)
                continue;
            }
            if(postProcessor) {
                postProcessor(freshUpdatePanel);
            }
            updatePanel.innerHTML = freshUpdatePanel.innerHTML;
            Array.from(updatePanel.querySelectorAll("script")).forEach(x => {
                x.insertAdjacentElement("afterend", addElement("script", { innerHTML: x.innerHTML })); // Передобавляем скрипты, как элементы, что они сработали
                x.remove();
            });
        }
    }
    if(typeof win.hwm_hints_init === 'function') win.hwm_hints_init();
    return freshDocument;
}