hwmAdvancedPlayerInfo

Добавляет в инфу персов и на домашнюю: ХП армии, очки и загрузку навыков, баланс рулетки и таверны, сумму умений, день рождения персонажа

目前为 2024-01-31 提交的版本。查看 最新版本

// ==UserScript==
// @name hwmAdvancedPlayerInfo
// @author alex_kocharin 2008-2012, Demin 2013-2015, Tamozhnya1 2024
// @namespace Tamozhnya1
// @version 17.4
// @description Добавляет в инфу персов и на домашнюю: ХП армии, очки и загрузку навыков, баланс рулетки и таверны, сумму умений, день рождения персонажа
// @include     /^https{0,1}:\/\/(www|my)\.(heroeswm|lordswm)\.(ru|com)\/(home|pl_info)\.php/
// @grant GM_deleteValue
// @grant GM_getValue
// @grant GM_setValue
// @grant GM.xmlHttpRequest
// @license MIT
// ==/UserScript==

if(typeof GM_deleteValue != 'function') {
    this.GM_getValue = function(key, def) { return localStorage[key] || def; };
    this.GM_setValue = function(key, value) { localStorage[key] = value; };
    this.GM_deleteValue = function(key) { return delete localStorage[key]; };
}
const playerIdMatch = document.cookie.match(/pl_id=(\d+)/);
if(playerIdMatch) {
    var PlayerId = playerIdMatch[1];
}
const windowObject = window.wrappedJSObject || unsafeWindow;
const lang = document.documentElement.lang || (location.hostname == "www.lordswm.com" ? "en" : "ru");
const isEn = lang == "en";
let playerFraction;
if(location.pathname == '/home.php') {
    // for new home page
    let currentFractionIconContainer = document.querySelector("div.home_css_pl_fract.show_hint");
    if(!currentFractionIconContainer) {
        currentFractionIconContainer = document.querySelector("a[href^='castle.php?change_faction_dialog']");
    }
    if(currentFractionIconContainer) {
        const currentFractionIconImg = currentFractionIconContainer.querySelector("img");
        playerFraction = currentFractionIconImg.src.split("i/f/r")[1].split(".png")[0];
    }
} else {
    const playerFractionExec = /\/i\/f\/r(\d+)\.png/.exec(document.querySelector("body").innerHTML);
    //console.log(playerFractionExec);
    if(!playerFractionExec) {
        console.log("Unknown player fraction");
        return;
    };
    playerFraction = playerFractionExec[1];
    //console.log(playerFraction);
}
const isNewPersonPage = document.querySelector("div#hwm_no_zoom") ? true : false;
let playerLevel;
if(isNewPersonPage) {
    const levelInfoCell = Array.from(document.querySelectorAll("div.home_pers_info")).find(x => x.innerHTML.includes(isEn ? "Combat level" : "Боевой уровень"));
    playerLevel = parseInt(levelInfoCell.querySelector("div[id=bartext] > span").innerText);
} else {
    playerLevel = parseInt(new RegExp(`<b>${isEn ? "Combat level" : "Боевой уровень"}: (\\d+?)<\\/b>`).exec(document.documentElement.innerHTML)[1]) || 0;
}
const artsInfo = {
    '2year_amul_lords': [2],
    '3arrows': [5],
    '3year_amul': [2],
    '3year_art': [3],
    '4year_klever': [3],
    '5years_star': [5],
    a_mallet: [1],
    amf_body: [8],
    amf_boot: [7],
    amf_cl: [8],
    amf_helm: [6],
    amf_scroll: [8],
    amf_weap: [11],
    antifire_cape: [3],
    barb_armor: [6],
    barb_boots: [6],
    barb_club: [7],
    barb_helm: [4],
    barb_shield: [6],
    bfly: [5],
    blacksword: [10],
    blacksword1: [10],
    bludgeon: [9],
    bril_pendant: [6],
    bril_ring: [5],
    brush_2010y: [15],
    brush_2011y: [15],
    brush_2012y: [15],
    bunt_medal1: [11],
    bunt_medal2: [6],
    bunt_medal3: [4],
    bwar1: [15],
    bwar2: [12],
    bwar3: [10],
    bwar4: [8],
    bwar5: [7],
    bwar6: [6],
    bwar7: [5],
    bwar_splo: [8],
    bwar_stoj: [8],
    bwar_takt: [8],
    centaurbow: [5],
    d_spray: [4],
    darkelfboots: [7],
    darkelfciras: [7],
    darkelfcloack: [6],
    darkelfcloak: [6],
    darkelfkaska: [6],
    darkelfpendant: [9],
    darkelfstaff: [10],
    defender_dagger: [2],
    dem_amulet: [9],
    dem_armor: [6],
    dem_axe: [10],
    dem_bootshields: [6],
    dem_dmech: [6],
    dem_dtopor: [11],
    dem_helmet: [6],
    dem_kosa: [9],
    dem_shield: [6],
    demwar1: [14],
    demwar2: [11],
    demwar3: [9],
    demwar4: [7],
    demwar5: [5],
    demwar6: [4],
    druid_amulet: [11],
    druid_armor: [8],
    druid_boots: [7],
    druid_cloack: [8],
    druid_staff: [11],
    dubina: [11],
    elfamulet: [9],
    elfboots: [7],
    elfbow: [8],
    elfshirt: [7],
    elfwar1: [13],
    elfwar2: [11],
    elfwar3: [8],
    elfwar4: [7],
    elfwar5: [6],
    elfwar6: [4],
    finecl: [6],
    flower_heart: [1],
    flowers1: [1],
    flowers2: [1],
    flowers3: [4],
    flowers4: [5],
    flowers5: [5],
    gdubina: [7],
    gm_3arrows: [5],
    gm_abow: [6],
    gm_amul: [5],
    gm_arm: [5],
    gm_defence: [5],
    gm_hat: [4],
    gm_kastet: [8],
    gm_protect: [6],
    gm_rring: [2],
    gm_spdb: [2],
    gm_sring: [2],
    gm_sword: [8],
    gmage_armor: [8],
    gmage_boots: [7],
    gmage_cloack: [8],
    gmage_crown: [6],
    gmage_scroll: [8],
    gmage_staff: [11],
    gnome_hammer: [2],
    gnomearmor: [6],
    gnomeboots: [5],
    gnomehammer: [9],
    gnomehelmet: [5],
    gnomem_amulet: [11],
    gnomem_armor: [8],
    gnomem_boots: [7],
    gnomem_hammer: [10],
    gnomem_helmet: [6],
    gnomem_shield: [7],
    gnomeshield: [6],
    gnomewar1: [15],
    gnomewar2: [12],
    gnomewar3: [10],
    gnomewar4: [8],
    gnomewar5: [7],
    gnomewar6: [6],
    gnomewar7: [5],
    gnomewar_splo: [8],
    gnomewar_stoj: [8],
    gnomewar_takt: [8],
    goldciras: [4],
    half_heart_m: [2],
    half_heart_w: [2],
    hunter_amulet1: [3],
    hunter_armor1: [3],
    hunter_arrows1: [3],
    hunter_boots1: [1],
    hunter_boots2: [2],
    hunter_boots3: [2],
    hunter_bow1: [2],
    hunter_bow2: [3],
    hunter_gloves1: [1],
    hunter_hat1: [1],
    hunter_helm: [2],
    hunter_jacket1: [1],
    hunter_mask1: [3],
    hunter_pendant1: [1],
    hunter_ring1: [2],
    hunter_ring2: [3],
    hunter_roga1: [2],
    hunter_shield1: [2],
    hunter_sword1: [1],
    hunterboots: [1],
    hunterdagger: [2],
    hunterdsword: [4],
    huntershield2: [3],
    huntersword2: [4],
    inq_body: [9],
    inq_boot: [7],
    inq_cl: [8],
    inq_helm: [6],
    inq_weap: [12],
    kn_body: [6],
    kn_helm: [5],
    kn_shield: [6],
    kn_weap: [9],
    knightarmor: [6],
    knightboots: [5],
    knighthelmet: [5],
    knightshield: [6],
    knightsword: [9],
    koltsou: [6],
    kopie: [9],
    kwar1: [15],
    kwar2: [12],
    kwar3: [10],
    kwar4: [8],
    kwar5: [7],
    kwar6: [6],
    kwar7: [5],
    kwar_splo: [8],
    kwar_stoj: [8],
    kwar_takt: [8],
    lizard_armor: [2],
    lizard_boots: [2],
    lizard_helm: [2],
    mage_boots: [7],
    mage_cape: [6],
    mage_hat: [6],
    mage_robe: [7],
    mage_scroll: [8],
    mage_staff: [11],
    magewar1: [12],
    magewar2: [9],
    magewar3: [7],
    magewar4: [5],
    magewar5: [4],
    mart8_flowers1: [4],
    mart8_ring1: [5],
    merc_armor: [6],
    merc_boots: [6],
    merc_dagger: [6],
    merc_sword: [8],
    meshok: [2],
    meshok2: [2],
    molot_tan: [12],
    necr_amulet: [5],
    necr_helm: [5],
    necr_robe: [5],
    necr_staff: [6],
    necrwar1st: [14],
    necrwar2st: [10],
    necrwar3st: [6],
    necrwar4st: [4],
    necrwar5st: [2],
    nv_body: [7],
    nv_boot: [6],
    nv_helm: [6],
    nv_shield: [7],
    nv_weap: [10],
    ny_bag: [3],
    ny_beard: [2],
    ny_bell: [5],
    ny_candle: [4],
    ny_cap: [4],
    ny_dfur: [5],
    ny_fir: [7],
    ny_flaps: [3],
    ny_fur: [5],
    ny_furcap: [6],
    ny_gloves: [3],
    ny_horns: [3],
    ny_icicle: [4],
    ny_muff: [3],
    ny_rat: [4],
    ny_ring: [7],
    ny_sbag: [5],
    ny_sock: [4],
    ny_staff: [4],
    ny_star: [4],
    ny_toy: [4],
    paladin_armor: [8],
    paladin_boots: [7],
    paladin_bow: [8],
    paladin_helmet: [6],
    paladin_shield: [7],
    paladin_sword: [11],
    pen: [9],
    pen_2010y: [15],
    pen_2011y_clan: [15],
    pen_2012y: [15],
    pika: [9],
    protazan: [2],
    ring_of_thief: [5],
    rog_demon: [10],
    roses: [9],
    round_shiled: [1],
    ru_statue: [10],
    sea_trident: [7],
    sh_4arrows: [7],
    sh_amulet2: [7],
    sh_armor: [7],
    sh_boots: [4],
    sh_bow: [8],
    sh_cloak: [8],
    sh_helmet: [6],
    sh_ring1: [6],
    sh_ring2: [4],
    sh_shield: [7],
    sh_spear: [10],
    sh_sword: [10],
    shpaga: [10],
    slayersword: [11],
    snowflake_1: [4],
    snowflake_2: [6],
    soul_cape: [2],
    staff2010: [1],
    sword5: [5],
    sunart1: [7],
    sunart2: [9],
    sunart3: [11],
    sunart4: [12],
    sv_arb: [8],
    sv_body: [8],
    sv_boot: [7],
    sv_helm: [6],
    sv_shield: [7],
    sv_weap: [11],
    tact1w1_wamulet: [10],
    tact765_bow: [7],
    tactaz_axe: [11],
    tactcv1_armor: [9],
    tactdff_shield: [8],
    tacthapp_helmet: [8],
    tactmag_staff: [10],
    tactms1_mamulet: [10],
    tactpow_cloack: [9],
    tactsm0_dagger: [8],
    tactspw_mring: [7],
    tactwww_wring: [7],
    tactzl4_boots: [9],
    testring: [6],
    thief_arb: [9],
    thief_cape: [5],
    thief_fastboots: [6],
    thief_goodarmor: [6],
    thief_ml_dagger: [7],
    thief_msk: [5],
    thief_neckl: [8],
    thief_premiumring1: [8],
    thief_premiumring2: [7],
    thief_premiumring3: [6],
    thief_unique_secretops: [3],
    tl_medal1: [9],
    tl_medal2: [4],
    tl_medal3: [3],
    tm_amulet: [11],
    tm_arb: [12],
    tm_armor: [10],
    tm_boots: [8],
    tm_cape: [7],
    tm_knife: [11],
    tm_mring: [8],
    tm_msk: [8],
    tm_wring: [8],
    topor_skelet: [7],
    tunnel_kirka: [7],
    v_1armor: [9],
    ve_helm: [8],
    venok: [2],
    verb11_sword: [11],
    verbboots: [9],
    vrb_shild: [8],
    warmor: [6],
    warthief_medal1: [7],
    warthief_medal2: [6],
    warthief_medal3: [5],
    warthief_medal4: [4],
    warthief_medal5: [3],
    wboots: [6],
    welfarmor: [6],
    welfboots: [5],
    welfbow: [6],
    welfhelmet: [5],
    welfshield: [6],
    welfsword: [9],
    whelmet: [6],
    wolfjacket: [2],
    zub: [10],
    r_bigsword: [13],
    r_magy_staff: [13],
    r_dagger: [8],
    r_goodscroll: [9],
    r_bootsmb: [10],
    r_zarmor: [10],
    r_clck: [11],
    r_bow: [7],
    r_warriorsamulet: [11],
    r_m_amulet: [11],
    r_warring: [7],
    r_magicsring: [7],
    r_helmb: [10],
    tj_helmet3: [7],
    tj_helmet2: [9],
    tj_helmet1: [12],
    tjarmor3: [7],
    tjarmor2: [10],
    tjarmor1: [12],
    tj_vboots3: [7],
    tj_vboots2: [9],
    tj_vboots1: [12],
    necrohelm3: [9],
    necrohelm2: [8],
    necrohelm1: [4],
    '6ring': [5],
    goblin_bow: [8],
    orc_axe: [12],
    ogre_bum: [14],
    ogre_helm: [12],
    orc_hat: [8],
    ring2013: [3],
    sharik: [4],
    meshok_2014: [3],
    meshok2_2014: [3],
    snowjinka: [4],
    sosulka: [4],
    'tj-shield3': [7],
    'tj-shield2': [9],
    'tj-shield1': [10],
    '7ka': [7],
    tjam3: [7],
    tjam2: [9],
    tjam1: [12],
    n_sword: [1],
    n_helmet: [1],
    n_armor: [1],
    n_boots: [1],
    n_shield: [1],
    n_amul: [2],
    n_ringd: [1],
    n_ringa: [1],
    n_clk: [1],
    gargoshield: [8],
    battlem_cape: [11],
    magneticarmor: [14],
    'v-ring3': [5],
    'v-ring2': [6],
    'v-ring1': [8],
    wshield: [6],
    trinitypendant: [7],
    quest_pendant1: [1],
    dragon_crown: [5],
    blackring: [4],
    dudka: [5],
    windsword: [10],
    pegaskop: [14],
    elfdagger: [12],
    sniperbow: [8],
    vtjcloak3: [5],
    vtjcloak2: [7],
    vtjcloak1: [8],
    coldring_n: [6 + Math.floor(playerLevel / 4)],
    cold_sword2014: [4 + Math.floor(playerLevel / 2)],
    sun_armor: [1 + Math.floor(playerLevel / 2)],
    cold_shieldn: [5 + Math.floor(playerLevel / 4)],
    piratehat3: [7],
    piratehat2: [9],
    piratehat1: [12],
    ttring: [4],
    '8amul_inf': [8],
    vbow3: [5],
    vbow2: [6],
    vbow1: [8],
    pir_armor3: [7],
    pir_armor2: [9],
    pir_armor1: [12],
    vbolt3: [5],
    vbolt2: [6],
    vbolt1: [8],
    neut_amulet: [10],
    bshield3: [7],
    bshield2: [9],
    bshield1: [10],
    compass: [7],
    lbow: [7],
    ankh1: [7],
    obereg: [4],
    runkam: [4],
    sandglass: [3],
    rdagger1: [9],
    trogloditkop: [10],
    dagger_dex: [4],
    dagger_myf: [6],
    dagger16: [7],
    dagger20: [8],
    super_dagger: [7],
    clover_amul: [11],
    pn_ring1: [13],
    sun_ring: [6],
    imp_helmet: [14],
    imp_amul: [19],
    imp_ring: [17],
    imp_armor: [14],
    imp_cloak: [11],
    imp_crossbow: [10],
    imp_sword: [17],
    imp_boots: [15],
    imp_shield: [15],
    imp_dagger: [14],
    wood_sword: [1, 20.00],
    gnome_hammer: [2, 12.00],
    steel_blade: [2, 15.83],
    dagger: [1, 32.00],
    def_sword: [3, 32.98],
    shortbow: [1, 17.45],
    staff: [6, 64.50],
    requital_sword: [5, 64.50],
    broad_sword: [6, 80.33],
    long_bow: [4, 129.00],
    sor_staff: [8, 124.92],
    power_sword: [8, 124.76],
    mstaff8: [8, 98.27],
    ssword8: [8, 97.95],
    mif_staff: [9, 239.03],
    mif_sword: [9, 247.34],
    mstaff10: [9, 113.71],
    ssword10: [9, 110.13],
    energy_scroll: [6, 131.91],
    composite_bow: [5, 153.07],
    mm_staff: [10, 247.76],
    mm_sword: [10, 250.81],
    mstaff13: [10, 122.45],
    ssword13: [10, 122.22],
    bow14: [6, 156.23],
    ffstaff15: [11, 257.87],
    firsword15: [11, 257.74],
    smstaff16: [11, 134.73],
    ssword16: [11, 134.30],
    bow17: [7, 163.69],
    staff18: [12, 266.86],
    scroll18: [9, 155.00],
    sword18: [12, 267.00],
    leatherhat: [1, 15.00],
    leather_helm: [1, 21.33],
    knowledge_hat: [2, 39.96],
    chain_coif: [2, 39.27],
    wizard_cap: [2, 46.54],
    mage_helm: [4, 66.92],
    steel_helmet: [3, 53.61],
    shelm8: [3, 40.73],
    mif_lhelmet: [5, 76.49],
    mif_hhelmet: [5, 91.87],
    shelm12: [5, 67.90],
    mhelmetzh13: [6, 93.11],
    zxhelmet13: [6, 93.11],
    myhelmet15: [7, 96.03],
    xymhelmet15: [7, 96.44],
    shelm16: [7, 70.80],
    helmet17: [8, 108.86],
    mhelmet17: [8, 108.86],
    bravery_medal: [2, 22.88],
    amulet_of_luck: [2, 39.16],
    power_pendant: [7, 125.60],
    samul8: [7, 115.40],
    warrior_pendant: [8, 164.30],
    magic_amulet: [7, 171.10],
    wzzamulet13: [9, 169.75],
    mmzamulet13: [9, 169.75],
    smamul14: [9, 148.73],
    samul14: [9, 148.73],
    bafamulet15: [9, 169.82],
    mmzamulet16: [10, 172.35],
    wzzamulet16: [10, 172.35],
    samul17: [10, 154.00],
    smamul17: [10, 154.00],
    mamulet19: [11, 178.77],
    amulet19: [11, 178.77],
    leather_shiled: [1, 15.06],
    leatherplate: [2, 46.23],
    hauberk: [3, 58.42],
    ciras: [4, 64.99],
    mage_armor: [5, 91.18],
    mif_light: [5, 91.17],
    sarmor9: [5, 63.27],
    full_plate: [6, 125.84],
    wiz_robe: [7, 136.76],
    miff_plate: [7, 133.99],
    sarmor13: [7, 88.26],
    robewz15: [8, 135.80],
    armor15: [8, 135.80],
    sarmor16: [8, 100.95],
    marmor17: [9, 140.00],
    armor17: [9, 142.71],
    scoutcloack: [1, 15.50],
    soul_cape: [2, 40.73],
    antiair_cape: [3, 49.78],
    powercape: [4, 136.28],
    scloack8: [4, 69.83],
    antimagic_cape: [5, 101.06],
    wiz_cape: [7, 148.23],
    cloackwz15: [8, 151.02],
    scloack16: [8, 108.63],
    cloack17: [9, 161.54],
    round_shiled: [1, 15.71],
    s_shield: [2, 18.07],
    defender_shield: [3, 28.85],
    sshield5: [4, 73.70],
    dragon_shield: [5, 128.03],
    large_shield: [6, 139.67],
    sshield11: [6, 98.92],
    shield13: [7, 148.40],
    sshield14: [7, 105.42],
    shield16: [8, 150.20],
    sshield17: [8, 120.86],
    shield19: [9, 157.43],
    leatherboots: [1, 14.50],
    hunter_boots: [1, 31.03],
    boots2: [2, 29.91],
    shoe_of_initiative: [3, 60.85],
    steel_boots: [4, 84.39],
    mif_lboots: [6, 132.80],
    sboots9: [5, 72.73],
    mif_hboots: [6, 121.77],
    sboots12: [6, 87.29],
    wiz_boots: [6, 125.80],
    boots13: [7, 124.01],
    mboots14: [8, 128.73],
    boots15: [8, 124.84],
    sboots16: [8, 110.23],
    boots17: [9, 130.57],
    mboots17: [9, 130.57],
    i_ring: [1, 17.40],
    sring4: [2, 39.40],
    doubt_ring: [2, 90.50],
    verve_ring: [2, 89.44],
    rashness_ring: [2, 65.63],
    circ_ring: [4, 132.88],
    powerring: [4, 132.40],
    smring10: [5, 100.33],
    sring10: [5, 97.30],
    warriorring: [5, 170.95],
    darkring: [5, 171.10],
    magring13: [6, 174.92],
    warring13: [6, 174.92],
    bring14: [6, 176.53],
    wwwring16: [6, 176.54],
    mmmring16: [6, 176.54],
    smring17: [6, 102.00],
    sring17: [6, 98.93],
    ring19: [7, 183.08],
    mring19: [7, 184.46],
    flowers1: [1, 35.00],
    flowers2: [1, 35.00],
    venok: [2, 35.00],
    defender_dagger: [2, 93.33],
    flower_heart: [3, 87.50],
    flowers3: [4, 233.33],
    half_heart_m: [2, 210.00],
    half_heart_w: [2, 210.00],
    bril_pendant: [6, 490.00],
    bril_ring: [5, 875.00],
    d_spray: [5, 233.33],
    flowers4: [5, 210.00],
    flowers5: [5, 210.00],
    protazan: [2, 218.75],
    wboots: [6, 350.00],
    roses: [9, 218.75],
    goldciras: [4, 280.00],
    warmor: [6, 350.00],
    whelmet: [6, 350.00],
    shpaga: [10, 466.67],
    bfly: [5, 1050.00],
    koltsou: [6, 612.50],
    dagger_dex: [4, 121],
    dagger_myf: [6, 151.33],
    dagger16: [7, 160],
    dagger20: [8, 163],
    dring5: [4, 92],
    dring9: [6, 211.2],
    dring12: [6, 216.31],
    dring15: [8, 218.57],
    dring18: [9, 222.86],
    dring21: [10, 227.14]
};
const unitsHealth = {
    peasant: [1, 4],
    conscript: [1, 6],
    archer: [1, 7],
    marksman: [1, 10],
    footman: [1, 16],
    squire: [1, 26],
    griffon: [1, 30],
    impergriffin: [1, 35],
    priest: [1, 54],
    inquisitor: [1, 80],
    cavalier: [1, 90],
    paladin: [1, 100],
    angel: [1, 180],
    archangel: [1, 220],

    brute: [101, 8],
    crossman: [101, 8],
    vindicator: [101, 23],
    battlegriffon: [101, 52],
    zealot: [101, 80],
    champion: [101, 100],
    seraph2: [101, 220],

    skeleton: [2, 4],
    skeletonarcher: [2, 4],
    zombie: [2, 17],
    plaguezombie: [2, 17],
    ghost: [2, 8],
    spectre: [2, 19],
    vampire: [2, 30],
    vampirelord: [2, 35],
    lich: [2, 50],
    archlich: [2, 55],
    wight: [2, 95],
    wraith: [2, 100],
    bonedragon: [2, 150],
    spectraldragon: [2, 160],

    sceletonwar: [102, 5],
    rotzombie: [102, 23],
    poltergeist: [102, 20],
    vampireprince: [102, 40],
    masterlich: [102, 55],
    banshee: [102, 110],
    ghostdragon: [102, 150],

    gremlin: [3, 5],
    mastergremlin: [3, 6],
    stone_gargoyle: [3, 15],
    obsgargoyle: [3, 20],
    iron_golem: [3, 18],
    steelgolem: [3, 24],
    mage: [3, 18],
    archmage: [3, 30],
    djinn: [3, 40],
    djinn_sultan: [3, 45],
    rakshasa_rani: [3, 120],
    rakshasa_raja: [3, 140],
    colossus: [3, 175],
    titan: [3, 190],

    saboteurgremlin: [103, 6],
    elgargoly: [103, 16],
    magneticgolem: [103, 28],
    battlemage: [103, 29],
    djinn_vizier: [103, 50],
    rakshasa_kshatra: [103, 135],
    stormtitan: [103, 190],

    pixel: [4, 5],
    sprite: [4, 6],
    dancer: [4, 12],
    wardancer: [4, 12],
    elf: [4, 10],
    masterhunter: [4, 14],
    druid: [4, 34],
    druideld: [4, 38],
    unicorn: [4, 57],
    silverunicorn: [4, 77],
    treant: [4, 175],
    ancienent: [4, 181],
    greendragon: [4, 200],
    emeralddragon: [4, 200],

    dryad_: [104, 6],
    winddancer: [104, 14],
    arcaneelf: [104, 12],
    ddhigh: [104, 34],
    pristineunicorn: [104, 80],
    savageent: [104, 175],
    crystaldragon: [104, 200],

    goblin: [5, 3],
    hobgoblin: [5, 4],
    wolfrider: [5, 10],
    wolfraider: [5, 12],
    orc: [5, 12],
    orcchief: [5, 18],
    ogre: [5, 50],
    ogremagi: [5, 65],
    rocbird: [5, 55],
    thunderbird: [5, 65],
    cyclop: [5, 85],
    cyclopking: [5, 95],
    behemoth: [5, 210],
    ancientbehemoth: [5, 250],

    goblinarcher: [105, 3],
    boarrider: [105, 14],
    orcrubak: [105, 20],
    ogrebrutal: [105, 70],
    firebird: [105, 65],
    cyclopod: [105, 100],
    dbehemoth: [105, 280],

    goblinmag: [205, 3],
    orcshaman: [205, 13],
    darkbird: [205, 60],
    hyenarider: [205, 13],
    ogreshaman: [205, 55],
    shamancyclop: [205, 105],
    cursedbehemoth: [205, 250],

    scout: [6, 10],
    assassin: [6, 14],
    stalker: [6, 15],
    maiden: [6, 16],
    fury: [6, 16],
    bloodsister: [6, 24],
    minotaur: [6, 31],
    minotaurguard: [6, 35],
    taskmaster: [6, 40],
    darkrider: [6, 40],
    grimrider: [6, 50],
    briskrider: [6, 50],
    hydra: [6, 80],
    deephydra: [6, 125],
    foulhydra: [6, 125],
    witch: [6, 80],
    shadow_witch: [6, 90],
    mistress: [6, 100],
    shadowdragon: [6, 200],
    blackdragon: [6, 240],
    reddragon: [6, 235],

    imp: [7, 4],
    familiar: [7, 6],
    horneddemon: [7, 13],
    hornedoverseer: [7, 13],
    hellhound: [7, 15],
    cerberus: [7, 15],
    succubus: [7, 20],
    succubusmis: [7, 30],
    hellcharger: [7, 50],
    stallion: [7, 66],
    pitfiend: [7, 110],
    pitlord: [7, 120],
    devil: [7, 166],
    archdevil: [7, 199],

    vermin: [107, 6],
    jdemon: [107, 13],
    hotdog: [107, 15],
    seducer: [107, 26],
    hellkon: [107, 66],
    pity: [107, 140],
    archdemon: [107, 211],

    defender: [8, 7],
    shieldguard: [8, 12],
    spearwielder: [8, 10],
    skirmesher: [8, 12],
    bearrider: [8, 25],
    blackbearrider: [8, 30],
    brawler: [8, 20],
    berserker: [8, 25],
    runepriest: [8, 60],
    runepatriarch: [8, 70],
    thane: [8, 100],
    thunderlord: [8, 120],
    firedragon: [8, 230],
    magmadragon: [8, 280],

    mountaingr: [108, 12],
    harpooner: [108, 10],
    whitebearrider: [108, 30],
    battlerager: [108, 30],
    runekeeper: [108, 65],
    flamelord: [108, 120],
    lavadragon: [108, 275],

    goblinus: [9, 3],
    trapper: [9, 4],
    fcentaur: [9, 6],
    ncentaur: [9, 9],
    warrior: [9, 12],
    mauler: [9, 12],
    shamaness: [9, 30],
    sdaughter: [9, 35],
    slayer: [9, 34],
    executioner: [9, 40],
    wyvern: [9, 90],
    foulwyvern: [9, 105],
    cyclopus: [9, 220],
    untamedcyc: [9, 225],

    goblinshaman: [109, 5],
    mcentaur: [109, 10],
    warmong: [109, 20],
    eadaughter: [109, 35],
    chieftain: [109, 48],
    poukai: [109, 120],
    bloodeyecyc: [109, 235],

    scorp: [10, 4],
    scorpup: [10, 5],
    duneraider: [10, 12],
    duneraiderup: [10, 12],
    shakal: [10, 24],
    shakalup: [10, 30],
    dromad: [10, 40],
    dromadup: [10, 45],
    priestmoon: [10, 50],
    priestsun: [10, 55],
    slon: [10, 100],
    slonup: [10, 110],
    anubis: [10, 160],
    anubisup: [10, 200]
};
const perkBranchCosts = {
    1: {
        knight_mark: 5,
        attack: 9,
        defense: 8,
        luck: 10,
        leadership: 7,
        dark: 8,
        light: 7
    },
    101: {
        benediction: 7,
        defense: 10,
        leadership: 10,
        enlightenment: 8,
        light: 6,
        summon: 10,
        sorcery: 7
    },
    2: {
        necr_soul: 5,
        defense: 11,
        enlightenment: 9,
        dark: 7,
        summon: 8,
        sorcery: 8
    },
    102: {
        powerraise: 6,
        attack: 11,
        luck: 12,
        enlightenment: 8,
        summon: 6,
        sorcery: 7
    },
    3: {
        magic_mirror: 7,
        enlightenment: 9,
        light: 10,
        summon: 8,
        destructive: 10,
        sorcery: 7
    },
    103: {
        nomagicdamage: 7,
        attack: 8,
        luck: 10,
        leadership: 9,
        enlightenment: 8,
        destructive: 9,
        sorcery: 8
    },
    4: {
        elf_shot: 7,
        attack: 10,
        defense: 9,
        luck: 7,
        leadership: 10,
        enlightenment: 10,
        light: 7,
        summon: 9
    },
    104: {
        zakarrow: 4,
        attack: 9,
        defense: 8,
        luck: 10,
        leadership: 8,
        enlightenment: 12
    },
    5: {
        barb_skill: 7,
        attack: 7,
        defense: 9,
        luck: 9,
        leadership: 10
    },
    105: {
        save_rage: 6,
        attack: 7,
        defense: 8,
        luck: 7,
        leadership: 9
    },
    205: {
        dark_blood: 5,
        defense: 9,
        luck: 10,
        leadership: 10,
        enlightenment: 8,
        dark: 6,
        sorcery: 7
    },
    6: {
        dark_power: 7,
        attack: 8,
        luck: 9,
        leadership: 10,
        enlightenment: 10,
        dark: 8,
        destructive: 9,
        sorcery: 7
    },
    106: {
        cre_master: 5,
        attack: 8,
        defense: 11,
        leadership: 8,
        luck: 10,
        enlightenment: 8,
        dark: 8
    },
    7: {
        hellfire: 6,
        attack: 7,
        defense: 9,
        luck: 10,
        dark: 8,
        destructive: 10,
        sorcery: 8
    },
    107: {
        consumecorpse: 5,
        defense: 9,
        enlightenment: 9,
        dark: 6,
        sorcery: 7
    },
    8: {
        runeadv: 7,
        defense: 9,
        destructive: 11,
        light: 7,
        leadership: 9,
        luck: 10
    },
    108: {
        firelord: 5,
        attack: 7,
        defense: 10,
        leadership: 8,
        luck: 8,
        destructive: 6,
    },
    9: {
        memoryblood: 6,
        attack: 7,
        enlightenment: 9,
        leadership: 9,
        luck: 10,
        defense: 9
    },
    10: {
        dayandnight: 7,
        attack: 8,
        defense: 10,
        leadership: 10,
        light: 6,
        dark: 6,
        sorcery: 9,
        enlightenment: 9
    }
};

main();
async function main() {
    //battleCostAndAmmunitionPoints();
    tavernAndRouletteBalances();
    countExp();
    birthday();
    await getTalentsToHome();
    if(location.pathname == "/pl_info.php") {
        talentsStatistics();
    }
    calcArmyHealth(); // После загрузки навыков, если она есть, чтоб обработать навык "vitality"
    setTimeout(function() {
        const talentsChanger = document.getElementById("hwmSetsMasterSkillSetSelectedValue");
        const armyChanger = document.getElementById("hwmSetsMasterArmySetSelectedValue");
        if(talentsChanger) {
            if(location.pathname == "/pl_info.php" && getUrlParamValue(location.href, "id") == PlayerId) { 
                observe([talentsChanger], talentsStatistics);
            }
            if(location.pathname == "/home.php" || location.pathname == "/pl_info.php" && getUrlParamValue(location.href, "id") == PlayerId) {
                const panels = [armyChanger];
                if(location.pathname == "/pl_info.php" && getUrlParamValue(location.href, "id") == PlayerId) {
                    panels.push(talentsChanger);
                }
                observe(panels, calcArmyHealth);
            }
        }
    }, 1500); // Здесь ждем загрузки hwmSetsMaster, чтоб подписаться на элемент hwmSetsMasterSkillSetSelectedValue и hwmSetsMasterArmySetSelectedValue
}
async function getTalentsToHome() {
    if(playerLevel < 5) {
        return;
    }
    if(location.pathname == '/home.php') {
        let hwmAdvancedPlayerInfoTalentsContainer = document.getElementById("hwmAdvancedPlayerInfoTalentsContainer");
        if(!hwmAdvancedPlayerInfoTalentsContainer) {
            let homePageTalentsContainer;
            if(isNewPersonPage) {
                homePageTalentsContainer = document.querySelector("div.home_friends_block");
            } else {
                homePageTalentsContainer = document.querySelector("body > center > table:nth-child(2) > tbody > tr:nth-child(1) > td:nth-child(1) > table > tbody > tr:nth-child(2) > td:nth-child(1) > table > tbody > tr > td > table > tbody > tr > td");
            }
            addElement("br", homePageTalentsContainer);
            const ShowTalentsTitleSpan = addElement("span", homePageTalentsContainer, { id: "hwmAdvancedPlayerInfoTalentsCaptionContainer", innerHTML: `&nbsp;&raquo;&nbsp;<b>${isEn ? "Talents" : "Навыки"}:</b><b id="hwmAdvancedPlayerInfoTalentsPointsContainer"></b>`, title: getShowTalentsTitleSpanTitle() });
            ShowTalentsTitleSpan.addEventListener("click", function() { setValue("ShowTalents", !getBool("ShowTalents")); this.title = getShowTalentsTitleSpanTitle(); getTalentsToHomeCore(); }, false);
            addElement("br", homePageTalentsContainer);
            hwmAdvancedPlayerInfoTalentsContainer = addElement("div", homePageTalentsContainer, { id: "hwmAdvancedPlayerInfoTalentsContainer" });
        }
        await getTalentsToHomeCore();
        const talentsChanger = document.getElementById("hwmSetsMasterSkillSetSelectedValue");
        if(talentsChanger) {
            observe([talentsChanger], getTalentsToHomeCore);
            //setTimeout(function() { observe([talentsChanger], getTalentsToHomeCore); }, 3000);
        }
    }
}
async function getTalentsToHomeCore() {
    if(location.pathname == '/home.php' && getBool("ShowTalents")) {
        const doc = await getRequest(`/pl_info.php?id=${PlayerId}`);
        const perksTable = getParent(doc.querySelector("a[href^='showperkinfo.php']"), "table", 2);
        if(perksTable) {
            Array.from(perksTable.querySelectorAll("a[href^='showperkinfo.php'] > img")).forEach(x => { x.style.width = `48px`; x.style.height = "auto"; });
            //Array.from(perksTable.querySelectorAll("a[href^='showperkinfo.php'] > img")).forEach(x => { x.setAttribute("title", x.getAttribute("hint")); x.style.width = `48px`; x.style.height = "auto"; });
            document.getElementById("hwmAdvancedPlayerInfoTalentsContainer").innerHTML = perksTable.outerHTML;
            if(typeof windowObject.hwm_hints_init === 'function') windowObject.hwm_hints_init();
            talentsStatistics();
            calcArmyHealth();
        }
    }
}
function getShowTalentsTitleSpanTitle() { return isEn ? `Click for ${getBool("ShowTalents") ? "disable" : "enable"} talents loading` : `Нажмите для ${getBool("ShowTalents") ? "выключения" : "включения"} загрузки навыков`; }
function battleCostAndAmmunitionPoints() {
    let left_td;
    let arts_td;
    Array.from(document.querySelectorAll('img')).forEach(x => {
        if(x.src.indexOf('/i/icons/attr_initiative.png') !== -1 && !left_td) {
            if(Array.from(x.parentNode.parentNode.parentNode.querySelectorAll('img')).length >= 7) {
                left_td = x.parentNode.parentNode.parentNode;
            }
        } else if(x.src.match(/\/i\/transport\/\d+\.png/) || x.src.match(/\/i\/slots_png\/slot0010.png/) || x.src.match(/\/i\/deer/)) {
            arts_td = x.parentNode.parentNode.parentNode;
        }
    });
    if(!left_td || !arts_td) {
        return;
    }
    let ammunitionPointsTotal = 0;
    let craftTotal = 0;
    const unknownArts = [];
    let battleCostTotal = 0;
    let unknown_cost = false;
    const artsRefs = Array.from(document.querySelectorAll("div[id^=slot] a[href^='art_info.php?id=']"));
    artsRefs.forEach(x => {
        const hint = x.querySelector("img[hint]").getAttribute("hint");
        const craftExec = /\[(([IDN]\d{1,2})?(E\d{1,2})?(A\d{1,2})?(W\d{1,2})?(F\d{1,2})?)\]/.exec(hint);
        let craftRate = 1;
        if(craftExec) {
            const craftInfo = craftExec[1];
            const craftExec2 = craftInfo.match(/\d{1,2}/g);
            const craftSum = craftExec2.reduce((t, x) => t + parseInt(x), 0);
            //console.log(craftExec2)
            craftTotal += craftSum;
            craftRate += craftSum * 0.02;
            unknown_cost = true;
            //console.log(`craftInfo: ${craftInfo}, craftSum: ${craftSum}, craftRate: ${craftRate}`);
        }
        const artName = getUrlParamValue(x.href, "id");
        const artInfo = artsInfo[artName];
        if(artInfo) {
            ammunitionPointsTotal += Math.floor(artInfo[0] * craftRate);
            if(artInfo.length > 1) {
                battleCostTotal += artInfo[1];
            } else {
                unknown_cost = true;
            }
        } else {
            unknownArts.push(artName);
            unknown_cost = true;
        }
    });
    left_td.insertAdjacentHTML("beforeend", `
<tr height="23">
    <td align="center">
        <img title="${isEn ? "AP" : "ОА"}" src="https://dcdn.heroeswm.ru/i/icons/attr_oa.png?v=1" width="24" height="24" />
    </td>
    <td id="unknownArtsCell" align="center">
        <b>${ammunitionPointsTotal}</b>
    </td>
</tr>`);
    const unknownArtsCell = document.getElementById("unknownArtsCell");
    if(unknownArts.length > 0) {
        const text_unknown_art = isEn ? 'Arts not found: %s. Contact developer.' : "Не найдены артефакты: %s. Сообщите разработчику.";
        const hint = text_unknown_art.replace('%s', unknownArts.join(', '));
        unknownArtsCell.insertAdjacentHTML("beforeend", ` (<a href="javascript:alert('${hint}');" title="${hint}">?</a>)`);
    }
    if(craftTotal > 0) {
        left_td.insertAdjacentHTML("beforeend", `
<tr height="23">
    <td align="center">
        <img title="${isEn ? "Craft" : "Крафт"}" src="/i/mod_common.gif" width="18" height="18" />
    </td>
    <td align="center">
        <b>${craftTotal}%</b>
    </td>
</tr>`);
    }
    if(battleCostTotal > 0) {
        left_td.insertAdjacentHTML("beforeend", `
<tr height="23">
    <td align="center">
        <img title="${isEn ? "Cost per battle" : "Цена за бой"}" src="https://dcdn2.heroeswm.ru/i/r/48/gold.png?v=3.23de65" width="24" height="24" />
    </td>
    <td align="center">
        <b>${(Math.round(battleCostTotal) + (unknown_cost ? '+' : ''))}</b>
    </td>
</tr>`);
    }
}
function talentsStatistics() {
    if(playerLevel < 5) {
        return;
    }
    let talentsContainer;
    let talentsCaptionContainer;
    let talentsPointsContainer;
    if(location.pathname == "/home.php") {
        talentsContainer = document.getElementById("hwmAdvancedPlayerInfoTalentsContainer");
        talentsCaptionContainer = document.getElementById("hwmAdvancedPlayerInfoTalentsCaptionContainer");
        talentsPointsContainer = document.getElementById("hwmAdvancedPlayerInfoTalentsPointsContainer");
    }
    if(location.pathname == "/pl_info.php") {
        talentsContainer = getParent(document.querySelector("a[href^='showperkinfo.php?name=']"), "td", 3);
        const layerTable = getParent(talentsContainer, "table");
        talentsCaptionContainer = Array.from(layerTable.rows[0].cells).find(x => x.innerHTML.includes(isEn ? "Talents" : "Навыки")).querySelector("b");
        talentsPointsContainer = document.getElementById("hwmAdvancedPlayerInfoTalentsPointsContainer") || addElement("span", talentsCaptionContainer, { id: "hwmAdvancedPlayerInfoTalentsPointsContainer" });
    }
    if(!talentsContainer || !talentsCaptionContainer) {
        return;
    }
    const talentBranchRows = talentsContainer.querySelectorAll(":scope > table > tbody > tr");
    const playerTalentBranches = Array.from(talentBranchRows).map(x => Array.from(x.querySelectorAll("a[href^='showperkinfo.php?name=']")).map(y => getUrlParamValue(y.href, "name")));
    //console.log(playerTalentBranches);
    let talentPoints = 0;
    const playerPerkBranchCosts = perkBranchCosts[playerFraction];
    //console.log(playerPerkBranchCosts);
    for(const playerPerkBranche of playerTalentBranches) {
        let branchName = playerPerkBranche[0];
        let firstPerkPromout = 1;
        if(["1", "2", "3"].includes(branchName.slice(-1))) {
            firstPerkPromout = parseInt(branchName.slice(-1));
            branchName = branchName.slice(0, -1);
        }
        //console.log(`branchName: ${branchName}, branchCost: ${playerPerkBranchCosts[branchName]}, branchePerks: ${playerPerkBranche.length}, firstPerkPromout: ${firstPerkPromout}`);
        talentPoints += playerPerkBranchCosts[branchName] * (playerPerkBranche.length + firstPerkPromout - 1);
    }
    talentsPointsContainer.innerText = ` (${isEn ? "points" : "очки"} ${talentPoints} ${isEn ? "from" : "из"} ${10 + 5 * (playerLevel - 5)})`;
}
function calcArmyHealth() {
    let armyContainer;
    if(location.pathname == "/pl_info.php") {
        armyContainer = getParent(document.querySelector(".cre_creature72"), "center");
    }
    if(location.pathname == "/home.php") {
        if(isNewPersonPage) {
            armyContainer = document.querySelector("div.home_css_creature_list");
        } else {
            armyContainer = getParent(document.querySelector(".cre_creature72"), "center");
        }
    }
    if(!armyContainer) {
        return;
    }
    const creatures = Array.from(document.querySelectorAll(`div.${isNewPersonPage ? "castle_creature54" : "cre_creature72"}`)).filter(x => x.querySelector("div#add_now_count")).map(x => ({ Name: getUrlParamValue(x.querySelector("a[href^='army_info.php?name=']").href, "name"),  Amount: parseInt(x.querySelector("div#add_now_count").innerText) }));
    const hasVitality = document.querySelector("a[href='showperkinfo.php?name=vitality']") ? true : false;
    const sum = creatures.reduce((t, x) => {
        const army = unitsHealth[x.Name]; 
        if(army) {
            t += x.Amount * (army[1] + (hasVitality ? 2 : 0));
        }
        return t;
    }, 0);
    const unknownCreatures = creatures.filter(x => !unitsHealth[x.Name]);
    let unknownCreaturesMessage = "";
    if(unknownCreatures.length > 0) {
        unknownCreaturesMessage = isEn ? `Creatures not found: ${unknownCreatures.map(x => x.Name).join(', ')}. Please, contact developer.` : `Существа не найдены: ${unknownCreatures.map(x => x.Name).join(', ')}. Пожалуйста, сообщите разработчику.`;
    }
    let hwmAdvancedPlayerInfoArmyHealthContainer = document.getElementById("hwmAdvancedPlayerInfoArmyHealthContainer");
    if(!hwmAdvancedPlayerInfoArmyHealthContainer) {
        armyContainer.insertAdjacentHTML("afterend", `&nbsp;»&nbsp;<b>${isEn ? "Total HP" : "Общее HP"}:&nbsp;</b><span id=hwmAdvancedPlayerInfoArmyHealthContainer>${sum}</span>
<a id=hwmAdvancedPlayerInfouUknownCreaturesMessageContainer href="javascript:alert('${unknownCreaturesMessage}');" title="${unknownCreaturesMessage}"> (?)</a>`);
        hwmAdvancedPlayerInfoArmyHealthContainer = document.getElementById("hwmAdvancedPlayerInfoArmyHealthContainer");
    }
    hwmAdvancedPlayerInfoArmyHealthContainer.innerText = sum;
    hwmAdvancedPlayerInfoArmyHealthContainer.style.color = hasVitality ? "#ff0000" : "";
    const hwmAdvancedPlayerInfouUknownCreaturesMessageContainer = document.getElementById("hwmAdvancedPlayerInfouUknownCreaturesMessageContainer");
    hwmAdvancedPlayerInfouUknownCreaturesMessageContainer.style.display = unknownCreaturesMessage ? "" : "none";
    hwmAdvancedPlayerInfouUknownCreaturesMessageContainer.title = unknownCreaturesMessage;
    hwmAdvancedPlayerInfouUknownCreaturesMessageContainer.href = `javascript:alert('${unknownCreaturesMessage}');`;
}
function tavernAndRouletteBalances() {
    if(location.pathname != "/pl_info.php") {
        return;
    }
    // Баланс рулетки
    const rouletteDebitText = findChildrenTextContainsValue("td", isEn ? "Roulette bets total" : "Поставлено в рулетке");
    const rouletteCreditText = findChildrenTextContainsValue("td", isEn ? "Roulette winnings total" : "Выиграно в рулетке");
    if(rouletteDebitText.length == 1 && rouletteCreditText.length == 1 && rouletteDebitText[0].nextSibling.tagName.toLowerCase() == "b" && rouletteCreditText[0].nextSibling.tagName.toLowerCase() == "b") {
        const rouletteBalance = rouletteCreditText[0].nextSibling.innerText.replace(/,/g, "") - rouletteDebitText[0].nextSibling.innerText.replace(/,/g, "");
        rouletteCreditText[0].nextSibling.insertAdjacentHTML("afterend", `<br>&nbsp;&nbsp;${isEn ? 'Balance' : 'Баланс'}: <b>${rouletteBalance.toLocaleString()}</b>`);
    }
    // Баланс таверны
    var statisticsSecondCell = getParent(document.querySelector("td.wb > a[href^='pl_transfers.php?id']"), "td").nextSibling;
    var tavern_parent = statisticsSecondCell.querySelector("tr").parentNode.childNodes[0].childNodes[1].firstChild.firstChild.childNodes;
    const winsRow = tavern_parent[1];
    const failsRow = tavern_parent[2];
    tavern_parent[0].childNodes[1].setAttribute('style', 'white-space: nowrap;');
    winsRow.childNodes[1].setAttribute('style', 'white-space: nowrap;');
    //console.log(winsRow)
    failsRow.childNodes[1].setAttribute('style', 'white-space: nowrap;');
    var tavern_0bal = winsRow.querySelector("tr");
    var tavern_1bal = failsRow.querySelector("tr");
    if(!tavern_0bal && !tavern_1bal) return;
    let wins = 0;
    let fails = 0;
    if(tavern_0bal) {
        wins = parseInt(winsRow.cells[1].querySelector("b").innerText.replace(/,/g, ""));
        tavern_0bal.childNodes[1].setAttribute('style', 'text-align: right; padding-right: 5px;');
        tavern_0bal = tavern_0bal.childNodes[1].innerHTML.replace(/,/g, "");
        winsRow.childNodes[3].firstChild.width = "100%";
        var totalRow = winsRow.cloneNode(true);
    } else {
        tavern_0bal = 0;
    }
    if(tavern_1bal) {
        fails = parseInt(failsRow.cells[1].querySelector("b").innerText.replace(/,/g, ""));
        tavern_1bal.childNodes[1].setAttribute('style', 'text-align: right; padding-right: 5px;');
        tavern_1bal = tavern_1bal.childNodes[1].innerHTML.replace(/,/g, "");
        failsRow.childNodes[3].firstChild.width = "100%";
        var totalRow = totalRow || failsRow.cloneNode(true);
    } else {
        tavern_1bal = 0;
    }
    var tavern_bal = tavern_0bal - tavern_1bal;
    totalRow.firstChild.innerHTML = `&nbsp;&nbsp;${isEn ? 'Balance:' : 'Баланс:'}`;
    totalRow.childNodes[1].innerHTML = `<b>${(wins - fails).toLocaleString()}</b>`;
    totalRow.childNodes[2].innerHTML = "&nbsp;";
    totalRow.childNodes[3].innerHTML = `
<table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tbody>
        <tr>
            <td>
                <img class="rs" width="24" height="24" src="https://dcdn2.heroeswm.ru/i/r/48/gold.png?v=3.23de65" border="0" title="${isEn ? "Gold" : "Золото"}" alt="">
            </td>
            <td style="text-align: right; padding-right: 5px;">
            ${tavern_bal.toLocaleString()}
            </td>
        </tr>
    </tbody>
</table>`;
    failsRow.insertAdjacentElement("afterend", totalRow);
}
function countExp() {
    if(location.pathname == '/home.php' || location.pathname == '/pl_info.php') {
        const cells = Array.from(document.querySelectorAll("td"));
        const skillInfoCell = cells.find(x => x.innerHTML.includes(isEn ? "Knight:" : "Рыцарь:") && x.innerHTML.includes(isEn ? "Enchanters' guild" : "Гильдия Оружейников") && !x.innerHTML.includes("<td"));
        if(!skillInfoCell) {
            return;
        }
        let totalSkill = 0;
        const regex = /\(([\d\.\,]+)\)/g;
        for(let i = 1; i <= 10; i++) {
            const skillsData = regex.exec(skillInfoCell.innerHTML);
            //console.log(skillsData);
            if(skillsData) {
                totalSkill += parseFloat(skillsData[1]);
            }
        }
        totalSkill = round00(totalSkill);
        const levelInfoBold = Array.from(document.querySelectorAll("td > b")).find(x => x.innerHTML.includes(isEn ? "Combat level:" : "Боевой уровень:"));
        const levelInfoCell = levelInfoBold.parentNode;
        const expRegex = /\(([\d\.\,]+)\)/g;
        const expExec = expRegex.exec(levelInfoCell.innerHTML);
        if(!expExec) {
            console.log("Parameters hided");
            return;
        }
        const exp = parseInt(expExec[1].replace(/,/g, ""));
        const br = levelInfoCell.querySelector("br");
        br.parentNode.insertBefore(createElement("span", { innerHTML: `&nbsp;&raquo;&nbsp;<b>${isEn ? "Skills count" : "Сумма умений"}: </b>${totalSkill.toLocaleString()}, ${isEn ? "ratio" : "соотношение"}: <span title="${isEn ? "Expirience points to one skill point" : "Очков опыта на одно очко умения"}">${ Math.round(exp / totalSkill).toLocaleString() }</span>` }), br.nextSibling);
    }
}
function birthday() {
    if(location.pathname == "/pl_info.php") {
        const playerId = getUrlParamValue(location.href, "id");
        let bifthday = GM_getValue(`PlayerBifthday${playerId}`, "");
        const districtBold = Array.from(document.querySelectorAll("b")).find(x => x.innerHTML.includes(isEn ? "Location" : "Район"));
        districtBold.nextElementSibling.nextElementSibling.insertAdjacentHTML("afterend", `&nbsp;&raquo;&nbsp;<b id=hwmAdvancedPlayerInfoBirthdayCaption title="${isEn ? "Click to download birthday" : "Нажмите для загрузки дня рождения"}">${isEn ? "Birthday" : "День рождения"}: </b><span id=hwmAdvancedPlayerInfoBirthday>${bifthday}</span>`);
        document.getElementById("hwmAdvancedPlayerInfoBirthdayCaption").addEventListener("click", loadBirthday);
    }
}
async function loadBirthday() {
    const playerId = getUrlParamValue(location.href, "id");
    const firstProtocolPage = await getRequest(`/pl_transfers.php?id=${playerId}&page=50000`);
    const lines = firstProtocolPage.querySelector(`div#set_mobile_max_width > div > div`).innerHTML.split("<br>").filter(x => x != "");
    bifthday = lines[lines.length - 2];
    bifthday = bifthday.replace(/&nbsp;/g, "");
    GM_setValue(`PlayerBifthday${playerId}`, bifthday);
    document.getElementById("hwmAdvancedPlayerInfoBirthday").innerHTML = bifthday;
}
// API
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 getUrlParamValue(url, paramName) { return (new URLSearchParams(url.split("?")[1])).get(paramName); }
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]; }, []); }
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) {
        if(typeof(value) == "string") {
            return value == "true";
        }
        if(typeof(value) == "boolean") {
            return value;
        }
    }
    return defaultValue;
}
function round00(value) { return Math.round(value * 100) / 100; }
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 addElement(type, parent, data) {
    let el = createElement(type, data);
    if(parent) {
        parent.appendChild(el);
    }
    return el;
}
function createElement(type, data) {
    let el = document.createElement(type);
    if(data) {
        for(let key in data) {
            if(key == "innerText" || key == "innerHTML") {
                el[key] = data[key];
            } else {
                el.setAttribute(key, data[key]);
            }
        }
    }
    return el;
}
function getRequest(url, overrideMimeType) {
    return new Promise((resolve, reject) => {
        GM.xmlHttpRequest({ method: "GET", url: url, overrideMimeType: overrideMimeType || "text/html; charset=windows-1251",
            onload: function(response) { resolve((new DOMParser).parseFromString(response.responseText, "text/html")); },
            onerror: function(error) { reject(error); }
        });
    });
}
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);
        }
    }
}