hwmTimers

Таймеры гильдии рабочих, воров, наёмников, рейнджеров, охотников, кузнецов, восстановления здоровья и маны

目前为 2023-12-16 提交的版本。查看 最新版本

// ==UserScript==
// @name           hwmTimers
// @namespace      Tamozhnya1
// @author         Tamozhnya1
// @description    Таймеры гильдии рабочих, воров, наёмников, рейнджеров, охотников, кузнецов, восстановления здоровья и маны
// @version        7.0
// @include        https://www.heroeswm.ru/*
// @include        https://www.lordswm.com/*
// @exclude        */rightcol.php*
// @exclude        */ch_box.php*
// @exclude        */chat*
// @exclude        */ticker.html*
// @exclude        */frames*
// @exclude        */brd.php*
// @grant          GM_deleteValue
// @grant          GM_getValue
// @grant          GM_setValue
// @grant 		   GM.notification
// @license        MIT
// ==/UserScript==

if(!this.GM_getValue || (this.GM_getValue.toString && this.GM_getValue.toString().indexOf("not supported") > -1)) {
    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) {
    return;
}
const PlayerId = playerIdMatch[1];
const isEn = document.documentElement.lang == "en";
const isHeartOnPage = document.querySelector("canvas#heart") || document.querySelector("div#heart_js_mobile") ? true : false;
const isNewInterface = document.querySelector("div#hwm_header") ? true : false;
const mooving = location.pathname == '/map.php' && !document.getElementById("map_right_block");
const windowObject = window.wrappedJSObject || unsafeWindow;
let tickTimer;
const ChallengeState = { Thrown: 1, Battle: 2 };
// в бою
if(location.pathname == '/war.php') {
    onWarDetected();
    return;
}
if(!isHeartOnPage) {
    return;
}
const [army_percent] = healthTimer();
var disable_alarm_delay = 30; //секунд задержки после предыдущего сигнала
if(!GM_getValue(`hwmTimersOptions${PlayerId}`)) {
    GM_setValue(`hwmTimersOptions${PlayerId}`, JSON.stringify({
    "time_health_alert": "no",
    "time_work_alert": "yes",
    "time_work_trudogolik": "0",
    "time_sm_alert": "yes",
    "time_gn_alert": "yes",
    "time_go_alert": "yes",
    "map_hunter": "false",
    "time_gv_alert": "yes",
    "map_thief_ambush": "false",
    "time_percent_faster": "1",
    "time_percent_prem": "1",
    "time_percent_prem_exp": "0",
    "time_percent_prem_title": "",
    "time_percent_lic_mo": "1",
    "time_percent_lic_mo_exp": "0",
    "time_percent_lic_mo_title": "",
    "gv_or_gre": "0",
    "gre_check": "0",
    "time_work_trudogolik_show": "1",
    "time_work_trudogolik_off": "0",
    "isShowWorkTimer": "1",
    "isShowSmithTimer": "1",
    "isShowMercTimer": "1",
    "isShowHuntTimer": "1",
    "isShowThiefTimer": "1",
    "disable_multiple_alarms": "1",
    "audio_file_gr": "",
    "audio_file_gonv": "",
    "audio_file_gk": "",
    "audio_file_h": "",
    "gl_attack": "false"
    }));    
}

let options = JSON.parse(GM_getValue(`hwmTimersOptions${PlayerId}`));;
var audio_default;
var audio_gr;
var audio_gonv;
var audio_gk;
var audio_h;
initAudios();

var texts = setTexts();
main();
function main() {
    initUserName();
    if(location.pathname == '/object_do.php' || location.href.indexOf('/object-info.php') > -1) {
        if(document.body.innerHTML.match(texts.work_obj_do)) {
            GM_setValue(`WorkEnd${PlayerId}`, Date.now() + 60 * 60000);
            GM_setValue(`LastWorkObjectId${PlayerId}`, getUrlParamValue(location.href, "id"));
            options.time_work_trudogolik = '' + (Number(options.time_work_trudogolik) + 1);
        }
    }
    if(location.pathname == '/home.php') {
        const workPlace = Array.from(document.querySelectorAll("a[href^='object-info.php']")).find(x => getParent(x, "td").innerHTML.includes(isEn ? "Currently employed at:" : "Место работы:"))
        if(workPlace) {
            GM_setValue(`LastWorkObjectId${PlayerId}`, getUrlParamValue(workPlace.href, "id"));
        }
    }
    createTimersPanel();
    requestServerTime();
    loadWorkEndTime();
    checkPremiumTime();
    checkLicMoO();
    checkWar();
    checkWork();
    checkMercenary();
    if(location.pathname == "/leader_guild.php") {
        Array.from(document.querySelectorAll("form[name^='f'] input[type='submit']")).forEach(x => x.addEventListener("click", function () { updateOption("gl_attack", 'true'); }));
    }
    checkRangerGuild();
    checkModWorkebench();
    if(location.pathname == '/map.php') {
        checkMapThief();
        checkMapRanger();
        checkMapHunter();
    }
    bindTimersPanel();
    launchTimers();
    GM_setValue(`hwmTimersOptions${PlayerId}`, JSON.stringify(options));
    console.log(`AmbushTimeout: ${GM_getValue(`AmbushTimeout${PlayerId}`)}, map_thief_ambush: ${options.map_thief_ambush}, map_hunter: ${options.map_hunter}, army_percent: ${army_percent}, HoldBattle: ${GM_getValue(`HoldBattle${PlayerId}`)}`);
}
function onWarDetected() {
    if(/warlog\|0/.exec(document.querySelector("html").innerHTML)) {
        //flash & html: warlog|0| -> бой происходит сейчас, warlog|1| -> запись боя, |player|7146446| -> id текущего игрока
        const playerIdExec = /\|player\|(\d+)\|/.exec(document.querySelector("html").innerHTML);
        if(playerIdExec && playerIdExec[1] == PlayerId) {
            GM_setValue(`HoldBattle${PlayerId}`, true);
        }
    }
    if(location.pathname == '/war.php') {
        const warId = getUrlParamValue(location.href, "warid");
        const lt = getUrlParamValue(location.href, "lt");
        const finalResultDiv = document.getElementById("finalresult_text");
        if(lt != "-1" && finalResultDiv.innerHTML.length <= 10 && GM_getValue("ChallengeState") == ChallengeState.Thrown) {
            GM_deleteValue("AmbushBeginDate");
            GM_setValue("ChallengeState", ChallengeState.Battle);
            observe(finalResultDiv, parseBattleResultPanel);
        }
    }
}
function parseBattleResultPanel() {
    const finalResultDiv = document.getElementById("finalresult_text");
    if(GM_getValue("ChallengeState") == ChallengeState.Battle && finalResultDiv.innerHTML.length > 10) {
        GM_deleteValue("ChallengeState");
        const bolds = finalResultDiv.querySelectorAll("font b");
        let result = "fail";
        for(const bold of bolds) {
            if(bold.innerHTML == (isEn ? "Victorious:" : "Победившая сторона:")) {
                //console.log(`${bold.parentNode.nextSibling.nextSibling.firstChild.innerText}, UserName: ${GM_getValue("UserName")}`);
                if(bold.parentNode.nextSibling.nextSibling.firstChild.innerText == GM_getValue("UserName")) {
                    result = "win";
                }
                break;
            }
        }
        if(result == "fail") {
            GM_setValue("AmbushSuspendExpireDate", Date.now() + AmbushMinutesInterval * 60 * 1000);
        }
        //console.log(`result: ${result}, AmbushSuspendExpireDate: ${GM_getValue("AmbushSuspendExpireDate")}`);
    }
}
function updateOption(key, val) {
    options = JSON.parse(GM_getValue(`hwmTimersOptions${PlayerId}`));
    options[key] = val;
    GM_setValue(`hwmTimersOptions${PlayerId}`, JSON.stringify(options));
}
function initAudios() {
    audio_default = new Audio(
        'data:audio/mp3;base64,' +
        '/+OAxAAAAAAAAAAAAEluZm8AAAAPAAAABQAACcoAMzMzMzMzMzMzMzMzMzMzMzMzM2ZmZmZmZmZmZmZmZmZmZmZmZmZmmZmZmZmZmZmZmZmZmZmZmZmZmZnMzMzMzMzMzMzMzMzMzMzMzMzMzP//////////////////////////AAAAOUxBTUUzLjk4cgE3AAAAAAAAAAAUQCQCTiIAAEAAAAnKGRQoyQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/+OAxABX1F4koVjAAQjCEwjMYQMNFN52kFuDMg7zN6S6b5yx01M0x11uJOV6eYZQoAsSQOw1xyGGKAISEUHFBIzpQ4IL0Piieg+pvC30VO49A5D8R9h6gag6YDTJKsOmOseB4gzhU6Y6g7E37tSik5MMoRMLYFtEUGmQaoGWkLwLonYbcty2tqnQCJEMsnK9Pbr07+P5GKTGvK4bf9yH8lmFSURixK2cM4dyWXYbcty5fz5h2GGKAKCOo4ZdxBxTRrjkNYdyUqZlkCzCKDEIpjTxt/3IchyIcxlb/v/D8s5Xp+yh/IcvUljCpKHYdyWXXYYYoAhIQCIOKaQlc5aQuIuicz1SVXbVIoAqRYjEIcvSt/3IfycrxuNy+/Uht/3/l9yGGsM4a4xN36ZlCJhchAAzRgYAAYAFmEHFiPxVhty2uO5OV43G7esK8bdt34vchhrC7FB2XypciEhAImA8jSy7iABdEUrxuNy/sdUgMCEYDAYDIYDEYDEYCeapz8c1sF1vw7MA2FaUsp8YwZDBEYNhWZMjfLOfb9r5p0lxsxHh/+OCxDRkHGbSX5nqA8jG0fWPNSWWZzFJWn3iM+keNcjuMPAiMRxVMchckCm7dWzuJA7X25tHSGDhiM0jUGg8MwA6MVRlMeRFc4LgGgPTMdOTpuI4vqhQgA4YtFoZTF4aHDYY3j+FQNMJQfAAi4ax7z82SvnelEritIYJgGucGiKYohiYMAUZKC4YkCcTDAZFD134cs58m6fmMst8qcprjzGKwLgIXzAkATBsETDcUzIgPDDwQjDgFTBwCQoEZgqBJhEF2OfcOc/Cn7hqWxqSTk3STW5fP0XgIdDBABjGAMDCQJAKCYQHaYBheG5YCoqAOYMA6BBHIQqMFgDblLOU/cKev2nzz53fK+7dLQasZSvPlXDehUIQ4CCIADBYCGJGCgFGBAZEIEgEFjB0AAQIqQxg4Dq9QgHUrTBsATAsGRCBBhuD///8z1+ff/P////+7/Llzes8/u/++cw59bO7zD///33////V4SolSuRCmPL6nAqR9ZQ0l+oyuAOCyR+7FK1oVDzAwRqbMUv6FhjNAQEMzLsmIgS1UOBgAImIjQoipf/jgsQ4ZLx2nAGY2ADAELIgUAh5h5eawLGRKBiAwYwIDS0ZmSGrrBAOmEGpgouigCBMxr2N3HiEvAQ2aIDGiCZphKHYxkpACC0WAgEWEJSRLJMWI9mGDJdQCFQcamMhKN7LzABcSEjHA8AA5elmCe6Wyi8XQAKiAgOjA3eGCAEC4GQCqXiwTLlTL5YaBQRe6EhFFL9fUOA0AL3Q64KYyQbgt8mkv1/V9P4JChgQoIASD1WhYEVpesZBH3VMAQBB5E1E5H4mAwAALneJRhsr1OGyC1DFaKvMma+jkOosKrLL2iNOadDTcpLBz1Mob+FzywCx3ThmMsqTXZiplIWdwPIXRj7WqRrDayxfVC8V+dl1aRR2NtKd6IwPBzgOHArgzcOydwWEtee5yqC3EKOBYBlNSIajDvVs696AXWjEzYj0zWiESlUWuWsb+M/aiFL3KW5SCe1fmpBWfr/+kk8SlmOX/9LVpKtJMzwBIiRGAngdQbAVvPs+70vm3FR5QGDWsugz5YIx02MFFn6TrWuxJy7xiJkYuqGZsQKPgUHGFgQUFQr/44LEOmbMdnABmdgAhKn3zEAY9pkI2cEtkxQaUamfHRgpKYkJoiCQyjYDgEw0JAwcu8oDzYms8RzMdCgUxpsEIUDSIEgZkBmBQsQASPSb7jusKggBA0bDEgFDEtgRBDSAMhKao2qGq3ofo0Q+pg+rdk92msTdeNCMGMCHzCgMUDQsEjAAFi9CS2NSLCkt1uQ+mMtOEyt6EAa4FRqWr4f2BncV48oMCRoXTaC4EoEAjss8vQVBCAAXmuFmzrq+bm26eLBIQ6LLnpruZTO0uh2WRZOBAEFID2syWVM6CoEIwRJp2m7JdqmZul6sLATxwJC3QdtNVrssgZuLSoKguZbDIG4uk+9O3sATbiWKSBtOUpasEyNjmC5Y7EZUwaJtNhpXUudGaf9nNO1xsbcFG2MwFLnphyLy+JPO0xpD708akEpls9Ny2Q0sbi71zrcYzFYlGnqxr7d+UvHK4nDjnf/wbDz0WJFR//tfoLTcY9mqAQMgAqUQjTA76PNjioDGCBQNciLWVhUVUiVilrWC2KV2VhS/qgKJpbEABLIqbRNHks6W/+OCxDNgzGY2JdjIAGUFX4R6LZMFZkWeMMQxQEuhEGaDZvQmaMmtfyoVKQASaC5sNmWQXSdaOsNSFQkoqoml/i0xbZMKFOCoCiqiqu53n+f6HpdnKX1ZUmMisptAzopelsS0qRSxlhkTi7xeJMJl0ndJL4u8g8sZymHJDISmWyhcyQyAZB5IpUzEp19lhlAlTLuZ0153qjKlAkVkVkVi7xaYtMumDFAkJSAZIpQYvEhKL+lpS2qKLTXiQTAEIwxEHXVw7KXZWFTFRVXc/Wcpf1/X9f2WzLWWIuLOPssMoEkMkKgFQCpgurAScxd4uUsWQ/Vdlhq7VSrti0y/stwymXBZzFoi1lhrEWuw7hammtM6fqbXKXVAAJhBoPOtnS8rQ1DUPWa0af52nKcpynKayu1drOX5vSp/n+hmMwy/rWVMS4JgCmIKuqVspXau1iLOXJcmNS7tWlpcJVGqXlVMQU1FMy45OC40VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVQ=='
    );
    audio_default.preload = 'auto';
    audio_gr = initAudio(options.audio_file_gr);
    audio_gonv = initAudio(options.audio_file_gonv);
    audio_gk = initAudio(options.audio_file_gk);
    audio_h = initAudio(options.audio_file_h);
}
function initAudio(src) {
    if(src && src !== '') {
        var audio = new Audio();
        audio.src = src;
        audio.preload = 'auto';
        return audio;
    } else {
        return audio_default;
    }
}
function setTexts() {
    var obj;
    if(isEn) {
        obj = {
            health_alert_ty: 'Army restore alarm on',
            health_alert_tn: 'Alarm once at army restore',
            work_alert_ty: 'Workshift alarm on',
            work_alert_tn: 'Alarm off',
            sm_alert_ty: 'Blacksmith alarm on',
            gn_alert_ty: 'Mercenaries Guild alarm on',
            regexp_timegn0: /Come back in (\d+) minutes\./,
            regexp_timegn1: /\. Time left: (\d+) minutes\./,
            regexp_timegn2: /ou have (\d+) minutes left/,
            regexp_timegn3: /\. Time left: (\d+) minutes\./,
            regexp_timegn4: /still have (\d+) minutes/,
            regexp_timegn5: /you still have \d+ attempts and (\d+) minutes/,
            regexp_gn_rep: /Reputation: <b>([\d\.]+)/,
            go_alert_ty: 'Hunters Guild alarm on',
            regexp_go_timer: 'Next hunt available in',
            gv_alert_ty: 'Thieves Guild alarm on',
            gre_alert_ty: 'Rangers Guild alarm on',
            regexp_timegre: /Come in (\d+) min/,
            time_home: /You may enroll again in (\d+) min/,
            time_home2: / since (\d{1,2}):(\d{1,2})/,
            workPlace: 'Work place:',
            alert_health: 'Troops ready: 100%',
            alert_work: 'LG: You may enroll again',
            alert_sm: 'BS: Blacksmith works are finished',
            alert_gn: 'MG: Mercenaries Guild has a quest for you',
            alert_go: 'HG: You notice traces ...',
            alert_gv: 'TG: You may set an ambush',
            alert_gre: 'RG: Rangers Guild has a quest for you',
            audio_file: 'Audio file ',
            alarm_mode: '<b>Timer alarm mode</b>:',
            alarm_mode_sound: 'audio',
            alarm_mode_alert: 'message',
            alarm_mode_both: 'notification',
            alarm_mode_none: 'both',
            h_t: 'health',
            gonv_t: 'MHT(R)G',
            gr_t: 'LG',
            gk_t: 'BS',
            gk_title: 'To Blacksmith',
            gn_t: 'MG',
            gn_title: 'To Mercenaries\' Guild',
            go_t: 'HG',
            go_title: 'To Hunters\' Guild',
            gv_t: 'TG',
            gv_title: 'To Thieves\' Guild',
            gre_t: 'RG',
            gre_title: 'To Rangers Guild post',
            mana_title: 'Settings',
            work_obj_do: 'You have successfully enrolled',
            work_unemployed: 'You are currently unemployed',
            regexp_map_go: 'During the journey you have access to the',
            go_title_lic: 'The license expires ',
            alert_go_lic_exp: 'HG: Hunter license has expired',
            alert_prem_exp: 'Abu-Bakir\'s Charm has expired',
            st_start: 'All settings adjustments will apply after page is reloaded',
            st_null_timers: 'Reset all timers',
            st_gv_n_time: 'Set TG/RG timer for once to',
            st_percent_faster: 'Quests HG, MG, TG, RG more often',
            st_gre_check: 'Immediately initiate Rangers\' guild battle on arrival',
            st_show_timers: 'Show timers:',
            st_predupr_pa: '<b>Abu-Bakir\'s Charm</b> is detected automatically',
            st_work_trudogolik_show: 'Notify about workaholic penalty only 2 workshifts away',
            st_work_trudogolik_off: 'Turn off all notifications on workaholic penalty',
            st_predupr_go_lic: '<b>Hunter license</b> is detected automatically in Hunters\' Guild',
            st_go_timer_hide: 'Hide',
            st_disable_multiple_alarms: 'Disable repeat signals for ' + disable_alarm_delay + ' sec',
            workaholic_penalty: 'Workaholic penalty',
            workaholic_penalty_regexp: 'workaholic penalty',
            regexp_sm: /Completion time: (\d+)-(\d+) (\d+):(\d+)/,
            workaholic_text1: ' approximately through ',
            workaholic_text2: ' enrollments.',
            workaholic_text3: '',
            workaholic_text1_replace: ' <font color:"red">enabled</font> approximately ',
            uze_ustroen: 'You are already employed\.',
            uze_ustroen2: 'Less than one hour passed since last enrollment\. Please wait\.',
            uze_ustroen3: 'No vacancies\.'
        };
    } else {
        obj = {
            health_alert_ty: 'Будет предупреждение о восстановлении армии',
            health_alert_tn: 'Установить единоразово предупреждение о восстановлении армии',
            work_alert_ty: 'Будет предупреждение о конце рабочего часа',
            work_alert_tn: 'Не будет предупреждения',
            sm_alert_ty: 'Будет предупреждение о завершении работ в Кузнице',
            gn_alert_ty: 'Будет предупреждение Гильдии Наемников',
            regexp_timegn0: /Приходи через (\d+) мин/,
            regexp_timegn1: /Осталось времени: (\d+) минут/,
            regexp_timegn2: /тебя осталось (\d+) минут/,
            regexp_timegn3: /у тебя еще есть (\d+) минут/,
            regexp_timegn4: /\. Осталось (\d+) минут\./,
            regexp_timegn5: /осталось \d+ попыток и (\d+) минут/,
            regexp_gn_rep: /Репутация: <b>([\d\.]+)/,
            go_alert_ty: 'Будет предупреждение Гильдии Охотников',
            regexp_go_timer: 'Следующая охота будет доступна через',
            gv_alert_ty: 'Будет предупреждение Гильдии Воров',
            gre_alert_ty: 'Будет предупреждение Гильдии Рейнджеров',
            regexp_timegre: /приходи через (\d+) мин/,
            time_home: /Вы можете устроиться на работу через (\d+)/,
            time_home2: / с (\d{1,2}):(\d{1,2})/,
            workPlace: 'Место работы:',
            alert_health: 'Готовность армии: 100%',
            alert_work: 'ГР: Пора на работу',
            alert_sm: 'ГК: Работа в Кузнице завершена',
            alert_gn: 'ГН: Для Вас есть задание в Гильдии Наемников',
            alert_go: 'ГО: Вы увидели следы ...',
            alert_gv: 'ГВ: Вы можете устроить засаду',
            alert_gre: 'ГРж: Есть задание в Гильдии Рейнджеров',
            audio_file: 'Звук сигнала ',
            alarm_mode: '<b>Режим оповещения</b> окончания таймера:',
            alarm_mode_sound: 'звук',
            alarm_mode_alert: 'сообщение',
            alarm_mode_both: 'оповещение',
            alarm_mode_none: 'отключен',
            h_t: 'здоровья',
            gonv_t: 'ГОНВ(Рж)',
            gr_t: 'ГР',
            gk_t: 'ГК',
            gk_title: 'В Кузницу',
            gn_t: 'ГН',
            gn_title: 'В здание Гильдии Наемников',
            go_t: 'ГО',
            go_title: 'В здание Гильдии Охотников',
            gv_t: 'ГВ',
            gv_title: 'В здание Гильдии Воров',
            gre_t: 'ГРж',
            gre_title: 'В здание Гильдии Рейнджеров',
            mana_title: 'Настройки',
            work_obj_do: 'Вы устроены на работу',
            work_unemployed: 'Вы нигде не работаете',
            regexp_map_go: 'Во время пути Вам доступны',
            go_title_lic: 'Лицензия истекает ',
            alert_go_lic_exp: 'ГО: Лицензия охотника истекла',
            alert_prem_exp: 'Благословение Абу-Бекра истекло',
            workaholic_penalty: 'Штраф трудоголика',
            workaholic_penalty_regexp: 'штраф трудоголика',
            regexp_sm: /Завершение работы: (\d+)-(\d+) (\d+):(\d+)/,
            st_start: 'Все изменения будут видны после перезагрузки страницы',
            st_null_timers: 'Обнулить все таймеры',
            st_gv_n_time: 'Единоразово установить таймер ГВ/ГРж равным',
            st_percent_faster: 'Задания ГО, ГН, ГВ, ГРж чаще на',
            st_gre_check: 'По прибытии вступать в бои Гильдии Рейнджеров',
            st_show_timers: '<b>Отображать:</b>',
            st_predupr_pa: '<b>Благословение Абу-Бекра</b> определяется автоматически',
            st_work_trudogolik_show: '<b>Показывать</b> штраф трудоголика только <b>за 2 часа</b>',
            st_work_trudogolik_off: '<b>Отключить</b> ВСЕ уведомления о штрафе трудоголика',
            st_predupr_go_lic: '<b>Лицензия охотника</b> определяется автоматически (в Гильдии Охотников)',
            st_go_timer_hide: '<b>Скрывать</b>',
            st_disable_multiple_alarms: 'Запретить повторные сигналы в течении ' + disable_alarm_delay + ' секунд',
            workaholic_text1: ' примерно через ',
            workaholic_text2: ' устройств',
            workaholic_text3: ' на работу.',
            workaholic_text1_replace: ' <font color:"red">активен</font> примерно ',
            uze_ustroen: 'Вы уже устроены\.',
            uze_ustroen2: 'Прошло меньше часа с последнего устройства на работу\. Ждите\.',
            uze_ustroen3: 'Нет рабочих мест\.'
        };
    }

    obj.regexp_time_server = /(\d+):(\d+), \d+ online/;
    obj.regexp_time_server2 = /(\d+):(\d+):(\d+), \d+ online/;
    obj.regexp_lic_mo = /(\d+)-(\d+)-(\d+) (\d+):(\d+)/;
    obj.regexp_prem = /(\d+)-(\d+)-(\d+) (\d+):(\d+)/;
    obj.sm_alert_tn = obj.work_alert_tn;
    obj.gn_alert_tn = obj.work_alert_tn;
    obj.go_alert_tn = obj.work_alert_tn;
    obj.gv_alert_tn = obj.work_alert_tn;
    obj.gre_alert_tn = obj.work_alert_tn;
    obj.gv_tit = '/thief_guild.php';
    obj.gre_tit = '/ranger_guild.php';

    if(options.gv_or_gre == '1') {
        obj.alert_gv = obj.alert_gre;
        obj.gv_alert_ty = obj.gre_alert_ty;
        obj.gv_alert_tn = obj.gre_alert_tn;
        obj.gv_t = obj.gre_t;
        obj.gv_title = obj.gre_title;
        obj.gv_tit = obj.gre_tit;
    }
    return obj;
}
function createTimersPanel() {
    const canvasHeart = document.querySelector("canvas#heart");
    const canvasMana = document.querySelector("canvas#mana");
    
    const shContainer = document.querySelector("div.sh_container");
    const sh_MenuPanel = document.querySelector("div.sh_MenuPanel");
    
    const mainTopTable = document.querySelector("table#main_top_table");
    const capContainer = mainTopTable || shContainer;
    
    const backgroundColor = isNewInterface ? "linear-gradient(to top, #09203f 0%, #537895 100%)" : (document.querySelector("img[src*='i/top_ny']") ? "#003399" : "#6b6b69");
    const foreColor = "#f5c137";
    const cellStyle = `background: ${backgroundColor}; color: ${foreColor};`;


    // const timersTable = addElement("table", capContainer, { style: "position: absolute;" });
    // const timersRow = addElement("tr", timersTable);
    
    // const healthCell = addElement("td", timersRow, { id: "healthTimerPanel", style: cellStyle });
    const dragonLeft = document.querySelector("img[src*='i/top'][src*='/dragon__left']"); // https://dcdn1.heroeswm.ru/i/top_ny_rus/dragon__left_.jpg
    const dragonRight = document.querySelector("img[src*='i/top'][src*='/dragon__right']");
    
    //document.querySelector("img.mm_decor1") // https://dcdn.heroeswm.ru/i/new_top_ny/mm_decor1.png
    
    let folder = "https://dcdn2.heroeswm.ru/i/top_ny_rus/line/";
    const img_link = document.querySelector("img[src*='i/top'][src*='/line/t_end']");
    if(img_link) {
        folder = /(\S*\/line\/)/.exec(img_link.src)[1]; 
    }
    const newYearSuffix = document.querySelector("img[src*='i/top_ny']") || document.querySelector("img[src*='i/new_top_ny']") ? "_" : ""; // если новый год
    //console.log(`folder: ${folder}, newYearSuffix: ${newYearSuffix}, ${folder}t_end${newYearSuffix}.jpg`); // folder: https://dcdn2.heroeswm.ru/i/top_ny_rus/line/, newYearSuffix: _
    
    let container = dragonLeft?.parentNode || sh_MenuPanel;
    let timersContainerWidth;
    let zIndex = 0;
    let leftMargin = 0;
    let topMargin = 0;
    let height;
    if(isNewInterface) {
        console.log(`width: ${shContainer.getBoundingClientRect().width}, paddingLeft: ${shContainer.style.paddingRight}`);
        timersContainerWidth = shContainer.getBoundingClientRect().width - 30 * 2;
        topMargin = -67;
        leftMargin = 159;
        zIndex = 2;
        height = 26;
        //GM_addStyle(`.noTransition { -webkit-transition: none !important; -moz-transition: none !important; -o-transition: none !important; transition: none !important; }`);
        //Array.from(document.querySelectorAll(".mm_item")).forEach(x => { x.classList.add('noTransition'); x.style.marginTop = "18px"; }); window.innerHeight; // Не получилось убрать плавный сдвиг меню вниз
        document.querySelector("div#ResourcesPanel").style.height = "20px";
    } else {
        timersContainerWidth = dragonRight.getBoundingClientRect().left - dragonLeft.getBoundingClientRect().left + 124;
        topMargin = -26;
        leftMargin = -43;
        height = 26;
    }
    const timersHtml = `
<style>
    .hwm_tb * {font-size: 11px; color: #f5c137;}
    .hwm_tb_cell {border-collapse: collapse; background-color: #6b6b69;}
    .hwm_tb_cell TD {padding: 0px;}
    .cell_t {height: 3px; background: url(${folder}t_top_bkg${newYearSuffix}.jpg);}
    .cell_c {white-space: nowrap; height: 18px; background: url(${folder}t_com_bkg${newYearSuffix}.jpg); font-weight: bold;}
    .cell_b {height: 5px; background: url(${folder}t_bot_bkg${newYearSuffix}.jpg); text-align: center;}
    .cell_b IMG {width: 17px; height: 5px;}
</style>
<table cellpadding=0 cellspacing=0 align="center" class="hwm_tb" style="width: ${timersContainerWidth}px;">
    <tr>
        <td>
            <table width="100%" cellpadding=0 cellspacing=0 style="background: url(${folder}t_bkg${newYearSuffix}.jpg);">
                <tr valign=middle align=center>
                    <td width=5 style="overflow: hidden;">
                        <img src="${folder}t_end${newYearSuffix}.jpg" alt="" width=9 height=${height}px style="margin:0px 0px 0px -4px;">
                    </td>
                    <td width=44>
                        <table class="hwm_tb_cell">
                            <tr>
                                <td class="cell_t" />
                            </tr>
                            <tr>
                                <td class="cell_c" style="cursor: pointer;" id="healthTimerPanel">00:00</td>
                            </tr>
                            <tr>
                                <td class="cell_b">
                                    <img src="${folder}t_center${newYearSuffix}.jpg">
                                </td>
                            </tr>
                        </table>
                    </td>
                    <td width=9>
                        <img src="${folder}t_end${newYearSuffix}.jpg" alt="" width=9 height=${height}px>
                    </td>
                    <td id="gr_show1">
                        <table class="hwm_tb_cell">
                            <tr>
                                <td class="cell_t" />
                            </tr>
                            <tr>
                                <td class="cell_c">
                                    <span style="cursor: pointer" id="workTimerPanelCaption">${texts.gr_t}</span>: 
                                    <a id="workTimerPanel" href="${GM_getValue(`LastWorkObjectId${PlayerId}`) ? `object-info.php?id=${GM_getValue(`LastWorkObjectId${PlayerId}`)}` : 'javascript:void(0);'}" style="text-decoration: none;">00:00</a>
                                </td>
                            </tr>
                            <tr>
                                <td class="cell_b">
                                    <img src="${folder}t_center${newYearSuffix}.jpg">
                                </td>
                            </tr>
                        </table>
                    </td>
                    <td id="gr_show2" width=9>
                        <img src="${folder}t_end${newYearSuffix}.jpg" alt="" width=9 height=${height}px>
                    </td>
                    <td id="gk_show1">
                        <table class="hwm_tb_cell">
                            <tr>
                                <td class="cell_t" />
                            </tr>
                            <tr>
                                <td class="cell_c">
                                    <span style="cursor:pointer" id="smithTimerPanelCaption">${texts.gk_t}</span>: 
                                    <a href="/mod_workbench.php?type=repair" title="${texts.gk_title}" style="text-decoration: none;" id="smithTimerPanel">00:00</a>
                                </td>
                            </tr>
                            <tr>
                                <td class="cell_b">
                                    <img src="${folder}t_center${newYearSuffix}.jpg">
                                </td>
                            </tr>
                        </table>
                    </td>
                    <td id="gk_show2" width=9>
                        <img src="${folder}t_end${newYearSuffix}.jpg" alt="" width=9 height=${height}px>
                    </td>
                    <td id="gn_show1">
                        <table class="hwm_tb_cell">
                            <tr>
                                <td class="cell_t" />
                            </tr>
                            <tr>
                                <td class="cell_c">
                                    <span style="cursor:pointer" id="mercTimerPanelCaption">${texts.gn_t}</span>: 
                                    <a href="/mercenary_guild.php" title="${texts.gn_title}" style="text-decoration: none;" id="mercTimerPanel">00:00</a>
                                </td>
                            </tr>
                            <tr>
                                <td class="cell_b">
                                    <img src="${folder}t_center${newYearSuffix}.jpg">
                                </td>
                            </tr>
                        </table>
                    </td>
                    <td id="gn_show2" width=9>
                        <img src="${folder}t_end${newYearSuffix}.jpg" alt="" width=9 height=${height}px>
                    </td>
                    <td id="go_show1">
                        <table class="hwm_tb_cell">
                            <tr>
                                <td class="cell_t" />
                            </tr>
                            <tr>
                                <td class="cell_c">
                                    <span style="cursor: pointer;" id="huntTimerPanelCaption"></span>: 
                                    <a href="/hunter_guild.php" style="text-decoration: none;" id="huntTimerPanel">00:00</a>
                                </td>
                            </tr>
                            <tr>
                                <td class="cell_b">
                                    <img src="${folder}t_center${newYearSuffix}.jpg">
                                </td>
                            </tr>
                        </table>
                    </td>
                    <td id="go_show2" width=9>
                        <img src="${folder}t_end${newYearSuffix}.jpg" alt="" width=9 height=${height}px>
                    </td>
                    <td id="gv_show1">
                        <table class="hwm_tb_cell">
                            <tr>
                                <td class="cell_t" />
                            </tr>
                            <tr>
                                <td class="cell_c">
                                    <span style="cursor:pointer" id="thiefTimerPanelCaption">${texts.gv_t}</span>: 
                                    <a href="${texts.gv_tit}" title="${texts.gv_title}" style="text-decoration: none;" id="thiefTimerPanel">00:00</a>
                                </td>
                            </tr>
                            <tr>
                                <td class="cell_b">
                                    <img src="${folder}t_center${newYearSuffix}.jpg">
                                </td>
                            </tr>
                        </table>
                    </td>
                    <td id="gv_show2" width=9>
                        <img src="${folder}t_end${newYearSuffix}.jpg" alt="" width=9 height=${height}px>
                    </td>
                    <td width=44>
                        <table class="hwm_tb_cell">
                            <tr>
                                <td class="cell_t" />
                            </tr>
                            <tr>
                                <td class="cell_c" style="cursor: pointer;" id="manaTimerPanel" title="${texts.mana_title}">00:00</td>
                            </tr>
                            <tr>
                                <td class="cell_b">
                                    <img src="${folder}t_center${newYearSuffix}.jpg">
                                </td>
                            </tr>
                        </table>
                    </td>
                    <td width=5 style="overflow: hidden;">
                        <img src="${folder}t_end${newYearSuffix}.jpg" alt="" width=9 height=${height}px style="margin:0px -4px 0px 0px;">
                    </td>
                </tr>
            </table>
        </td>
    </tr>
</table>`;
    const timersPanel = addElement("div", container, { style: `position: absolute; margin: ${topMargin}px 0px 0px ${leftMargin}px; text-align: center; z-index: ${zIndex};`, innerHTML: timersHtml });
    timersPanel.querySelector("#manaTimerPanel").addEventListener("click", settings);
    timersPanel.querySelector('#healthTimerPanel').addEventListener("click", function() { updateOption("time_health_alert", options.time_health_alert == 'yes' ? 'no' : 'yes'); bindTimersPanel(); });
    timersPanel.querySelector('#workTimerPanelCaption').addEventListener("click", function() { updateOption("time_work_alert", options.time_work_alert == 'yes' ? 'no' : 'yes'); bindTimersPanel(); });
    timersPanel.querySelector('#smithTimerPanelCaption').addEventListener("click", function() { updateOption("time_sm_alert", options.time_sm_alert == 'yes' ? 'no' : 'yes'); bindTimersPanel(); });
    timersPanel.querySelector('#mercTimerPanelCaption').addEventListener("click", function() { updateOption("time_gn_alert", options.time_gn_alert == 'yes' ? 'no' : 'yes'); bindTimersPanel(); });
    timersPanel.querySelector('#huntTimerPanelCaption').addEventListener("click", function() { updateOption("time_go_alert", options.time_go_alert == 'yes' ? 'no' : 'yes'); bindTimersPanel(); });
    timersPanel.querySelector('#thiefTimerPanelCaption').addEventListener("click", function() { updateOption("time_gv_alert", options.time_gv_alert == 'yes' ? 'no' : 'yes'); bindTimersPanel(); });
}
function bindTimersPanel() {
    const workTimerPanelCaption = document.getElementById('workTimerPanelCaption');
    workTimerPanelCaption.style.color = options.time_work_alert == 'yes' ? '#FF0000' : '#f5c137';
    workTimerPanelCaption.title = options.time_work_alert == 'yes' ?  texts.work_alert_ty : texts.work_alert_tn;
    const workTimerPanel = document.getElementById('workTimerPanel');
    let workTimerPanelTtitle = options.time_percent_prem_title;
    if(options.time_work_trudogolik) {
        if(workTimerPanelTtitle) {
            workTimerPanelTtitle += '\n';
        }
        workTimerPanelTtitle += texts.workaholic_penalty + ": " + (11 - Number(options.time_work_trudogolik));
        if(options.time_work_trudogolik_off == '0' && options.time_work_trudogolik > 10) {
            workTimerPanel.style.color = '#ff9c00';
        }
    }
    workTimerPanel.title = workTimerPanelTtitle;
    
    const healthTimerPanel = document.getElementById('healthTimerPanel');
    healthTimerPanel.style.color = options.time_health_alert == 'yes' ? '#ff9c00' : '#f5c137';
    healthTimerPanel.title = options.time_health_alert == 'yes' ?  texts.health_alert_ty : texts.health_alert_tn;
    
    const smithTimerPanelCaption = document.getElementById('smithTimerPanelCaption');
    smithTimerPanelCaption.style.color = options.time_sm_alert == 'yes' ? '#FF0000' : '#f5c137';
    smithTimerPanelCaption.title = options.time_sm_alert == 'yes' ?  texts.sm_alert_ty : texts.sm_alert_tn;
    const mercTimerPanelCaption = document.getElementById('mercTimerPanelCaption');
    mercTimerPanelCaption.style.color = options.time_gn_alert == 'yes' ? '#FF0000' : '#f5c137';
    mercTimerPanelCaption.title = options.time_gn_alert == 'yes' ?  texts.gn_alert_ty : texts.gn_alert_tn;

    const huntTimerPanelCaption = document.getElementById('huntTimerPanelCaption');
    huntTimerPanelCaption.innerText = texts.go_t;
    huntTimerPanelCaption.style.color = options.time_go_alert == 'yes' ? '#FF0000' : '#f5c137';
    huntTimerPanelCaption.title = options.time_go_alert == 'yes' ?  texts.go_alert_ty : texts.go_alert_tn;
    const huntTimerPanel = document.getElementById('huntTimerPanel');
    let huntTimerPanelTitle = texts.go_title;
    if(texts.go_title_lic) {
        huntTimerPanelTitle += '\n' + texts.go_title_lic + options.time_percent_lic_mo_title;
    }
    huntTimerPanel.title = huntTimerPanelTitle;

    const thiefTimerPanelCaption = document.getElementById('thiefTimerPanelCaption');
    thiefTimerPanelCaption.style.color = options.time_gv_alert == 'yes' ? '#FF0000' : '#f5c137';
    thiefTimerPanelCaption.title = options.time_gv_alert == 'yes' ?  texts.gv_alert_ty : texts.gv_alert_tn;
    
    document.getElementById("gr_show1").style.display = document.getElementById("gr_show2").style.display = (options.isShowWorkTimer == "1" ? '' : "none");
    document.getElementById("gk_show1").style.display = document.getElementById("gk_show2").style.display = (options.isShowSmithTimer == "1" ? '' : "none");
    document.getElementById("gn_show1").style.display = document.getElementById("gn_show2").style.display = (options.isShowMercTimer == "1" ? '' : "none");
    document.getElementById("go_show1").style.display = document.getElementById("go_show2").style.display = (options.isShowHuntTimer == "1" ? '' : "none");
    document.getElementById("gv_show1").style.display = document.getElementById("gv_show2").style.display = (options.isShowThiefTimer == "1" ? '' : "none");
}
function loadWorkEndTime() {
    if(location.pathname == '/home.php') {
        if(document.body.innerHTML.match(texts.work_unemployed)) {
            GM_deleteValue(`WorkEnd${PlayerId}`);
            return;
        }
        let newWorkEnd;
        var gr_temp;
        // подхватывание времени окончания работы с home.php и его проверка
        var time_home_time = texts.time_home.exec(document.body.innerHTML);
        const workEnd = parseInt(GM_getValue(`WorkEnd${PlayerId}`, 0));
        if(time_home_time) {
            newWorkEnd = getServerTime() + Number(time_home_time[1]) * 60000;
        } else {
            time_home_time = texts.time_home2.exec(document.body.innerHTML)
            if(time_home_time) {
                const serverDateTime = getServerDateTime();
                let workBegin = new Date(serverDateTime.getFullYear(), serverDateTime.getMonth(), serverDateTime.getDate(), Number(time_home_time[1]), Number(time_home_time[2]), 0);
                if(workBegin > serverDateTime) {
                    workBegin.setDate(workBegin.getDate() - 1);
                }
                newWorkEnd = workBegin.getTime() + 60 * 60 * 1000;
            }
        }
        if(newWorkEnd && (workEnd == 0 || Math.abs(workEnd - newWorkEnd) > 70000)) {
            GM_setValue(`WorkEnd${PlayerId}`, newWorkEnd);
        }
    }
}
function checkPremiumTime() {
    // проверка наличия эффекта блага АБУ Бекра (премиум аккаунт)
    // skipn=1 это 'Ознакомился' или 'Got it!'
    if(location.pathname == '/home.php' && document.querySelector("img[src*='i/icons/attr_defense.png']") && !document.querySelector("a[href*='home.php?skipn=1']")) {
        const img_star_prem = document.querySelector("img[src$='i/star_extend.png']") || document.querySelector("img[src$='i/star.png']");
        options.time_percent_prem = img_star_prem ? "0.7" : "1";
        options.time_percent_prem_exp = '0';
        options.time_percent_prem_title = img_star_prem ? img_star_prem.title : '';
        if(img_star_prem) {
            img_star_prem.align = "absmiddle";
            const time_prem = /(\d+-\d+-\d+ \d+:\d+)/.exec(img_star_prem.title);
            if(time_prem) {
                const abuEnd = parseDate(time_prem[1], true);
                console.log(abuEnd);
                options.time_percent_prem_exp = abuEnd.getTime();
            }
        }
    }
    if(options.time_percent_prem_title && Number(options.time_percent_prem_exp) < serverNow()) {
        options.time_percent_prem = '1';
        options.time_percent_prem_exp = '0';
        options.time_percent_prem_title = '';
    }
}
function checkLicMoO() {
    var form_f2 = document.querySelector("form[name='f2']");
    if(location.pathname == '/hunter_guild.php' && form_f2) {
        while(form_f2.tagName != 'TR') {
            form_f2 = form_f2.parentNode;
        }
        options.time_percent_lic_mo = '1';
        options.time_percent_lic_mo_exp = '0';
        options.time_percent_lic_mo_title = '';
        if(texts.regexp_lic_mo.exec(form_f2.innerHTML)) {
            if(!form_f2.querySelector("input[type='submit'][onclick*='confirm']")) {
                // лицензия МО
                options.time_percent_lic_mo = '' + (50 / 100);
            } else {
                // лицензия О
                options.time_percent_lic_mo = '' + (75 / 100);
            }
            const forms = form_f2.querySelectorAll("td");
            var time_lic_mo_max = 0;
            for(const form of forms) {
                if(form.innerHTML.indexOf("<td") != -1) {
                    continue;
                }
                var time_lic_mo = /(\d+-\d+-\d+ \d+:\d+)/.exec(form.innerHTML);
                if(time_lic_mo) {
                    const licEndTime = parseDate(time_lic_mo[1], true).getTime();
                    if(licEndTime > time_lic_mo_max) {
                        time_lic_mo_max = licEndTime;
                        options.time_percent_lic_mo_exp = licEndTime;
                        options.time_percent_lic_mo_title = time_lic_mo[0];
                    }
                }
            }
        }
    }
    if(options.time_percent_lic_mo_title && Number(options.time_percent_lic_mo_exp) < serverNow()) {
        // лицензия охотника истекла
        options.time_percent_lic_mo = '1';
        options.time_percent_lic_mo_exp = '0';
        options.time_percent_lic_mo_title = '';
    }
}
function checkWar() {
    console.log(`checkWar AmbushTimeout: ${GM_getValue(`AmbushTimeout${PlayerId}`)}, map_thief_ambush: ${options.map_thief_ambush}, map_hunter: ${options.map_hunter}, army_percent: ${army_percent}, HoldBattle: ${GM_getValue(`HoldBattle${PlayerId}`)}`);
    if(gmGetBool(`HoldBattle${PlayerId}`)) {
        var bselect_link = document.querySelector("a[href='bselect.php']") || document.querySelector("a[href='plstats.php']");
        if(bselect_link && bselect_link.parentNode.innerHTML.indexOf("#ff0000") === -1) {
            GM_deleteValue(`HoldBattle${PlayerId}`);
            if(options.map_thief_ambush == 'true') {
                if(army_percent < 100) {
                    GM_setValue(`AmbushTimeout${PlayerId}`, Date.now() + 60 * 60000 * options.time_percent_faster * options.time_percent_prem);
                } else {
                    GM_deleteValue(`AmbushTimeout${PlayerId}`);
                }
            }
            if(options.map_hunter == 'true') {
                setHuntTimeout();
            }
            if(army_percent == 100 && options.gl_attack != 'true') {
                options.time_work_trudogolik = '0';
            }
            options.gl_attack = 'false';
            options.map_thief_ambush = 'false';
            options.map_hunter = 'false';
        }
    }
    console.log(`checkWar AmbushTimeout: ${GM_getValue(`AmbushTimeout${PlayerId}`)}`);
}
function setHuntTimeout(restSeconds) {
    restSeconds = restSeconds || ((getServerDateTime().getHours() < 8 ? 20 : 40) * 60 * options.time_percent_faster * options.time_percent_prem * options.time_percent_lic_mo);
    const huntTimeout = Date.now() + restSeconds * 1000;
    GM_setValue(`HuntTimeout${PlayerId}`, huntTimeout);
    launchTimers();
}
function skipHunt() {
    const restSeconds = ((getServerDateTime().getHours() < 8 ? 10 : 20) * 60 * options.time_percent_faster * options.time_percent_prem * options.time_percent_lic_mo)
    setHuntTimeout(restSeconds);
    const map_hunt_block_div = document.querySelector("div#map_hunt_block_div");
    if(map_hunt_block_div) {
        observe(map_hunt_block_div, hideNextHuntTimer, true);
    }
}
function checkWork() {
    if(location.pathname == '/object-info.php') {
        var parent_trud = document.querySelector("a[href*='objectworkers.php']");
        if(parent_trud) {
            var regexp_workaholic = new RegExp('\\*\\&nbsp;0\\.(\\d) ' + texts.workaholic_penalty_regexp);
            // отработано смен
            var workaholic_WORK = Number(options.time_work_trudogolik);
            if(regexp_workaholic.exec(document.body.innerHTML)) {
                regexp_workaholic = Number(regexp_workaholic.exec(document.body.innerHTML)[1]);
                if(regexp_workaholic == 8) {
                    workaholic_WORK = 11;
                } else if(regexp_workaholic == 6) {
                    workaholic_WORK = 12;
                } else if(regexp_workaholic == 4) {
                    workaholic_WORK = 13;
                } else if(regexp_workaholic == 2) {
                    workaholic_WORK = 14;
                } else if(regexp_workaholic == 1 && workaholic_WORK < 15) {
                    workaholic_WORK = 15;
                }
                options.time_work_trudogolik = '' + workaholic_WORK;
            } else if(workaholic_WORK > 10) {
                workaholic_WORK = 10;
                options.time_work_trudogolik = '' + workaholic_WORK;
            }
            var add_trud = document.createElement('span');
            if(workaholic_WORK == 9 || workaholic_WORK == 10) {
                // выделить цветом
                add_trud.setAttribute('style', 'color:red; font-weight:bold;');
            } else if(workaholic_WORK > 10) {
                texts.workaholic_text1 = texts.workaholic_text1_replace;
            }
            // осталось работать
            var workaholic_ENROLL = Math.abs(11 - workaholic_WORK);
            if(workaholic_WORK > 14) {
                workaholic_ENROLL = workaholic_ENROLL + '+';
            }
            // правильные окончания слов
            if(!isEn) {
                if(workaholic_WORK == 9 || workaholic_WORK == 8 || workaholic_WORK == 7) {
                    texts.workaholic_text2 += '\u0430';
                } else if(workaholic_WORK == 10) {
                    texts.workaholic_text2 += '\u043E';
                }
            }
            if(options.time_work_trudogolik_off == '0') {
                if(options.time_work_trudogolik_show == '1' && workaholic_WORK != 9 && workaholic_WORK != 10) {} else {
                    add_trud.innerHTML = texts.workaholic_penalty + texts.workaholic_text1 + workaholic_ENROLL + texts.workaholic_text2 + texts.workaholic_text3;
                    parent_trud = parent_trud.parentNode.previousSibling.previousSibling;
                    parent_trud.parentNode.insertBefore(add_trud, parent_trud);
                }
            }
            // замена "Уже устроен"
            parent_trud = document.querySelector("a[href*='objectworkers.php']").parentNode.parentNode;
            if(Date.now() > parseInt(GM_getValue(`WorkEnd${PlayerId}`, 0)) && (parent_trud.innerHTML.match(texts.uze_ustroen) || (texts.uze_ustroen = parent_trud.innerHTML.match(texts.uze_ustroen2)) || (texts.uze_ustroen = parent_trud.innerHTML.match(texts.uze_ustroen3)))) {
                parent_trud.innerHTML = parent_trud.innerHTML.replace(texts.uze_ustroen, '<style>@-webkit-keyframes blink {80% {opacity:0.0;}} @-moz-keyframes blink {80% {opacity:0.0;}} @-o-keyframes blink {80% {opacity:0.0;}} @keyframes blink {80% {opacity:0.0;}}</style><font color=blue style="-webkit-animation: blink 1s steps(1,end) 0s infinite; -moz-animation: blink 1s steps(1,end) 0s infinite; -o-animation: blink 1s steps(1,end) 0s infinite; animation: blink 1s steps(1,end) 0s infinite"><b>' + texts.uze_ustroen + '</b></font>');
            }
        }
    }
}
function checkMercenary() {
    if(location.pathname == '/mercenary_guild.php') {
        var time_gn;
        if(document.querySelector("a[href^='/mercenary_guild.php?action=accept']")) {
            GM_deleteValue(`MercenaryTimeout${PlayerId}`);
        } else if((time_gn = texts.regexp_timegn0.exec(document.body.innerHTML)) || (time_gn = texts.regexp_timegn1.exec(document.body.innerHTML)) || (time_gn = texts.regexp_timegn2.exec(document.body.innerHTML)) || (time_gn = texts.regexp_timegn3.exec(document.body.innerHTML)) || (time_gn = texts.regexp_timegn4.exec(document.body.innerHTML)) || (time_gn = texts.regexp_timegn5.exec(document.body.innerHTML))) {
            time_gn = Number(time_gn[1]);
            if(texts.regexp_timegn0.exec(document.body.innerHTML) && (time_gn == 19 || time_gn == 13))
                time_gn++;
            time_gn = time_gn * 60000; // в миллисекундах
            const now = Date.now();
            var time_gn_temp = time_gn - Math.abs(parseInt(GM_getValue(`MercenaryTimeout${PlayerId}`, 0)) - now);
            if(Math.abs(time_gn_temp) > 70000) {
                var reputation_gn = texts.regexp_gn_rep.exec(document.body.innerHTML);
                reputation_gn = (40 - Number(reputation_gn[1]) * 2) * options.time_percent_faster * options.time_percent_prem * 60000;
                // в миллисекундах
                time_gn_temp = time_gn - reputation_gn;
                GM_setValue(`MercenaryTimeout${PlayerId}`, now + (Math.abs(time_gn_temp) > 70000 ? time_gn : reputation_gn))
            }
        }
        // options.grandma = '1';
        if(document.body.innerHTML.match('¬ы получаете') || document.body.innerHTML.match('You receive')) {
            var flash_heart = document.querySelector("object > param[value*='mercenary.swf']");
            if(flash_heart) {
                var rand_f;
                if(new Date().getHours() == 23) {
                    rand_f = "d8EWAZm.jpg";
                } else if(options.grandma) {
                    var img_win = new Array("3xVyD9G.jpg", "rdc2phi.jpg", "4Sz0fZh.jpg", "EeSup0D.jpg", "cfqFars.jpg", "HCuDAHi.jpg", "pYaFMyE.jpg");
                    rand_f = Math.floor(Math.random() * img_win.length);
                    rand_f = img_win[rand_f];
                }
                if(rand_f) {
                    flash_heart.parentNode.style.display = 'none';
                    var add_el = document.createElement('img');
                    add_el.height = "150";
                    add_el.width = "150";
                    add_el.src = "https://i.imgur.com/" + rand_f;
                    flash_heart.parentNode.parentNode.appendChild(add_el);
                }
            }
        }
    }
}
function checkRangerGuild() {
    if(location.pathname == '/ranger_guild.php') {
        if(document.querySelector("a[href^='ranger_guild.php?action=accept']")) {
            options.map_thief_ambush = 'false';
            GM_deleteValue(`AmbushTimeout${PlayerId}`)
            options.gv_or_gre = '1';
        }
        var time_gv = texts.regexp_timegre.exec(b.innerHTML);
        if(time_gv) {
            time_gv = Number(time_gv[1]) * 60000; // в миллисекундах
            const now = Date.now();
            var time_gv_temp = time_gv - Math.abs(parseInt(GM_getValue(`AmbushTimeout${PlayerId}`, 0)) - now);
            if(Math.abs(time_gv_temp) > 70000) {
                options.map_thief_ambush = 'false';
                GM_setValue(`AmbushTimeout${PlayerId}`, now + time_gv)
                options.gv_or_gre = '1';
            }
        }
    }
    if(location.pathname == '/ranger_list.php') {
        var link_ranger_attack = document.querySelectorAll("a[href^='ranger_attack.php?join']");
        if(link_ranger_attack.length > 0) {
            options.map_thief_ambush = 'false';
            GM_deleteValue(`AmbushTimeout${PlayerId}`)
            options.gv_or_gre = '1';
            for(const link_ranger_attackItem of link_ranger_attack) {
                link_ranger_attackItem.addEventListener("click", set_thief_ambush);
            }
        }
    }
}
function checkModWorkebench() {
    if(location.pathname == '/mod_workbench.php') {
        parseSmithPage(document);
    }
}
function parseSmithPage(doc) {
    const allb = doc.querySelectorAll("b");
    for(const bold of allb) {
        if(bold.innerText.includes(isEn ? "Under repair" : "В ремонте")) {
            var repairData = bold.innerText;
            break;
        }
    }
    if(repairData) {
        const restRepairTime = { Hours: 0, Minutes: 0, Seconds: 59 };
        //В ремонте: еще 1 ч. 31 мин. //Under repair another 1 h. 17 min.
        const hoursRegex = new RegExp(`(\\d+) ${isEn ? "h" : "ч"}\\.`);
        const hoursRegexResult = hoursRegex.exec(repairData);
        if(hoursRegexResult) {
            restRepairTime.Hours = parseInt(hoursRegexResult[1]);
        }
        const minutesRegex = new RegExp(`(\\d+) ${isEn ? "min" : "мин"}\\.`);
        const minutesRegexResult = minutesRegex.exec(repairData);
        if(minutesRegexResult) {
            restRepairTime.Minutes = parseInt(minutesRegexResult[1]);
        }
        //console.log(repairData);
        //console.log(restRepairTime);
        const repairEnd = new Date();
        repairEnd.setHours(repairEnd.getHours() + restRepairTime.Hours);
        repairEnd.setMinutes(repairEnd.getMinutes() + restRepairTime.Minutes);
        repairEnd.setSeconds(repairEnd.getSeconds() + restRepairTime.Seconds);
        //console.log(repairEnd);
        
        const savedRepairEnd = GM_getValue(`RepairEnd${PlayerId}`);
        if(!savedRepairEnd || Math.abs(repairEnd.getTime() - parseInt(savedRepairEnd)) / 1000 / 60 > 2) {
            GM_setValue(`RepairEnd${PlayerId}`, repairEnd.getTime());
        }
    } else {
        GM_deleteValue(`RepairEnd${PlayerId}`);
    }
}
function checkMapThief() {
    console.log(`checkMapThief map_thief_ambush: ${options.map_thief_ambush}, gv_or_gre: ${options.gv_or_gre}`);
    var thief_ambush_cancel = document.querySelector("a[href^='thief_ambush_cancel.php']");
    if(thief_ambush_cancel) {
        options.map_thief_ambush = 'true';
        GM_deleteValue(`AmbushTimeout${PlayerId}`);
        options.gv_or_gre = '0';
        thief_ambush_cancel.addEventListener("click", function(event) { updateOption("map_thief_ambush", 'false'); });
    }
    if(document.querySelector("a[href='ecostat.php']")) {
        if(options.gv_or_gre == '0' && !thief_ambush_cancel) {
            options.map_thief_ambush = 'false';
        }
        if(options.gv_or_gre == '1' && !document.querySelector("a[href='ranger_guild.php']")) {
            options.map_thief_ambush = 'false';
        }
    }
    var form_thief_ambush = document.querySelector("form[action='thief_ambush.php']");
    if(form_thief_ambush) {
        options.map_thief_ambush = 'false';
        GM_deleteValue(`AmbushTimeout${PlayerId}`);
        options.gv_or_gre = '0';
        var input_form_thief_ambush = form_thief_ambush.querySelector("input[type='submit']");
        input_form_thief_ambush.addEventListener("click", set_thief_ambush);
    }
    console.log(`checkMapThief map_thief_ambush: ${options.map_thief_ambush}, gv_or_gre: ${options.gv_or_gre}`);
}
function checkMapRanger() {
    var form_ranger_attack = document.querySelector("form[action='ranger_attack.php']");
    if(form_ranger_attack) {
        options.map_thief_ambush = 'false';
        GM_deleteValue(`AmbushTimeout${PlayerId}`);
        options.gv_or_gre = '1';
        form_ranger_attack.querySelector("input[type='submit']").addEventListener("click", function() { updateOption("map_thief_ambush", 'true'); });
        if(options.gre_check == '1') {
            options.map_thief_ambush = 'true';
            setTimeout(function() { form_ranger_attack.submit(); }, 500);
        }
    }
}
function checkMapHunter() {
    const map_hunt_block_div = document.querySelector("div#map_hunt_block_div");
    if(map_hunt_block_div) {
        const next_ht_new = map_hunt_block_div.querySelector("div#next_ht_new");
        options.map_hunter = 'false';
        if(next_ht_new) {
            setHuntTimeout(windowObject.MapHunterDelta);
        } else {
            GM_deleteValue(`HuntTimeout${PlayerId}`);
            const attackButtons = map_hunt_block_div.querySelectorAll("div[hint='Напасть']");
            for(const button of attackButtons) {
                button.addEventListener("click", function() { updateOption("map_hunter", 'true'); }, false);
            }
            const skipButtons = map_hunt_block_div.querySelectorAll("div[hint^='Пройти']");
            for(const button of skipButtons) {
                button.addEventListener("click", function() { skipHunt(); }, false);
            }
            const callButtons = map_hunt_block_div.querySelectorAll("div[hint^='Позвать']");
            for(const button of callButtons) {
                button.addEventListener("click", function() { setTimeout(onclick_hunter_help, 200); }, false);
            }
        }
    }
    if(mooving && !GM_getValue(`HuntTimeout${PlayerId}`)) {
        skipHunt();
    }
    hideNextHuntTimer();
}
function hideNextHuntTimer() {
    const next_ht_new = document.querySelector("div#next_ht_new");
    if(next_ht_new && gmGetBool("HideHuntTimer")) {
        document.querySelector("div#map_hunt_block_div").style.display = "none";
    }
}
function parseWaitTime(timeText) {
    const restTime = parseTime(timeText);
    const date = new Date();
    date.setHours(date.getHours() + restTime.Hours);
    date.setMinutes(date.getMinutes() + restTime.Minutes);
    date.setSeconds(date.getSeconds() + restTime.Seconds);
    return date;
}
function parseTime(timeText) {
    const time = { Hours: 0, Minutes: 0, Seconds: 0 };
    const hoursRegex = new RegExp(`(\\d+) ${isEn ? "h" : "ч"}\\.`);
    const hoursRegexResult = hoursRegex.exec(timeText);
    if(hoursRegexResult) {
        time.Hours = parseInt(hoursRegexResult[1]);
    }
    const minutesRegex = new RegExp(`(\\d+) ${isEn ? "min" : "мин"}\\.`);
    const minutesRegexResult = minutesRegex.exec(timeText);
    if(minutesRegexResult) {
        time.Minutes = parseInt(minutesRegexResult[1]);
    }
    const secondsRegex = new RegExp(`(\\d+) ${isEn ? "sec" : "с"}\\.`);
    const secondsRegexResult = secondsRegex.exec(timeText);
    if(secondsRegexResult) {
        time.Seconds = parseInt(secondsRegexResult[1]);
    }
    return time;
}
function onclick_hunter_help() {
    var forms = document.querySelectorAll("form[action='/map.php']");
    for(const form of forms) {
        const input_form_go_link_help = form.querySelector("input[type='submit']");
        input_form_go_link_help.addEventListener("click", function() { updateOption("map_hunter", 'true'); }, false);
    }
}
function set_thief_ambush() {
    updateOption("map_thief_ambush", 'true');
}
function launchTimers() {
    const time = { healthTimerPanel: -1, manaTimerPanel: -1, workTimerPanel: -1, mercTimerPanel: -1, thiefTimerPanel: -1, huntTimerPanel: -1, smithTimerPanel: -1 };
    const now = Date.now();
    if(GM_getValue(`HealthRestoreTime${PlayerId}`)) {
        time.healthTimerPanel = parseInt(GM_getValue(`HealthRestoreTime${PlayerId}`)) - now;
    }
    const workEnd = parseInt(GM_getValue(`WorkEnd${PlayerId}`, 0));
    if(now < workEnd) {
        time.workTimerPanel = workEnd - now;
    } else {
        GM_deleteValue(`WorkEnd${PlayerId}`);
    }
    const repairEnd = parseInt(GM_getValue(`RepairEnd${PlayerId}`, 0));
    if(now < repairEnd) {
        time.smithTimerPanel = repairEnd - now;
    } else {
        GM_deleteValue(`RepairEnd${PlayerId}`);
    }
    const mercenaryTimeout = parseInt(GM_getValue(`MercenaryTimeout${PlayerId}`, 0));
    if(now < mercenaryTimeout) {
        time.mercTimerPanel = mercenaryTimeout - now;
    } else {
        GM_deleteValue(`MercenaryTimeout${PlayerId}`);
    }
    const huntTimeout = parseInt(GM_getValue(`HuntTimeout${PlayerId}`, 0));
    if(now < huntTimeout) {
        time.huntTimerPanel = huntTimeout - now;
    } else {
        GM_deleteValue(`HuntTimeout${PlayerId}`);
    }
    const ambushTimeout = parseInt(GM_getValue(`AmbushTimeout${PlayerId}`, 0));
    if(now < ambushTimeout) {
        time.thiefTimerPanel = ambushTimeout - now;
    } else {
        GM_deleteValue(`AmbushTimeout${PlayerId}`);
    }
    clearTimeout(tickTimer);
    tick(time);
}
function signal(message, sound) {
    if(options.disable_multiple_alarms == '1') {
        if(parseInt(GM_getValue(`LastNotificationTime${PlayerId}`, 0)) + disable_alarm_delay * 1000 > Date.now()) {
            return;
        }
        GM_setValue(`LastNotificationTime${PlayerId}`, Date.now());
    }
    switch(GM_getValue(`NotificationType${PlayerId}`, '0')) {
        case '0':
            sound.play();
            break;
        case '1':
            alert(message);
            break;
        case '2':
            GM.notification(message, "ГВД", "https://dcdn.heroeswm.ru/i/rewards/fast_t/3x3_1.png", function() { window.focus(); });
            break;
        default: //including '3'
    }
}
function milisecondsFormat(milisecondsLeft) {
    const secondsLeft = Math.floor(milisecondsLeft / 1000);
    const days = Math.floor(secondsLeft / 86400);
    const hours = Math.floor((secondsLeft - days * 86400) / 3600);
    const minutes = Math.floor((secondsLeft - days * 86400 - hours * 3600) / 60);
    const seconds = secondsLeft % 60;
    return (days === 0 ? '' : ((days < 10) ? '0' : '') + days + ':') + (days === 0 && hours === 0 ? '' : ((hours < 10) ? '0' : '') + hours + ':') + ((minutes < 10) ? '0' : '') + minutes + ':' + ((seconds < 10) ? '0' : '') + seconds;
}
function tick(time) {
    //console.log(time);
    for(const timerPanelId in time) {
        //console.log(timerPanelId)
        const milisecondsLeft = time[timerPanelId];
        if(milisecondsLeft >= 0) {
            document.getElementById(timerPanelId).innerHTML = milisecondsFormat(milisecondsLeft);
        }
        if(milisecondsLeft > 0) {
            time[timerPanelId] -=  Math.min(1000, milisecondsLeft);
        }
        if(milisecondsLeft == 0) {
            time[timerPanelId] = -1;
            if(timerPanelId == 'healthTimerPanel') {
                var healthTimerPanel = document.getElementById('healthTimerPanel');
                healthTimerPanel.style.color = '#f5c137';
                healthTimerPanel.title = texts.health_alert_tn;
                options = JSON.parse(GM_getValue(`hwmTimersOptions${PlayerId}`));
                if(options.time_health_alert == 'yes') {
                    options.time_health_alert = 'no';
                    GM_setValue(`hwmTimersOptions${PlayerId}`, JSON.stringify(options));
                    setTimeout(function() { signal(texts.alert_health, audio_h); }, 100);
                }
            }
            if(timerPanelId == 'workTimerPanel' && parseInt(GM_getValue(`WorkEnd${PlayerId}`, 0)) > 0 && options.time_work_alert == 'yes') {
                GM_deleteValue(`WorkEnd${PlayerId}`);
                setTimeout(function() { signal(texts.alert_work, audio_gr); }, 100);
            }
            if(timerPanelId == 'smithTimerPanel' && parseInt(GM_getValue(`RepairEnd${PlayerId}`, 0)) > 0 && options.time_sm_alert == 'yes') {
                GM_deleteValue(`RepairEnd${PlayerId}`);
                setTimeout(function() { signal(texts.alert_sm, audio_gk); }, 100);
            }
            if(timerPanelId == 'mercTimerPanel' && parseInt(GM_getValue(`MercenaryTimeout${PlayerId}`, 0)) > 0 && options.time_gn_alert == 'yes') {
                GM_deleteValue(`MercenaryTimeout${PlayerId}`);
                setTimeout(function() { signal(texts.alert_gn, audio_gonv); }, 100);
            }
            if(timerPanelId == 'huntTimerPanel' && parseInt(GM_getValue(`HuntTimeout${PlayerId}`, 0)) > 0 && options.time_go_alert == 'yes') {
                GM_deleteValue(`HuntTimeout${PlayerId}`);
                setTimeout(function() { signal(texts.alert_go, audio_gonv); }, 100);
            }
            if(timerPanelId == 'thiefTimerPanel' && parseInt(GM_getValue(`AmbushTimeout${PlayerId}`, 0)) > 0 && options.time_gv_alert == 'yes') {
                GM_deleteValue(`AmbushTimeout${PlayerId}`);
                setTimeout(function() { signal(texts.alert_gv, audio_gonv); }, 100);
            }
        }
    }
    if(Object.keys(time).reduce((t, c) => Math.max(t, time[c]), -1) > -1) {
        tickTimer = setTimeout(function() { tick(time); }, 1000);
    }
}
function settings() {
    if(showPupupPanel(GM_info.script.name)) {
        return;
    }
    options = JSON.parse(GM_getValue(`hwmTimersOptions${PlayerId}`));
    const bgcinnerHTML = `
<tr>
    <td align="center"> <b>${texts.st_start}</b> </td>
</tr>
<tr>
    <td>${texts.st_show_timers}&nbsp;&nbsp;${texts.gr_t}:<input type=checkbox ${add_checked(options.isShowWorkTimer)} id=isShowWorkTimerCheckbox title="">
&nbsp;&nbsp;${texts.gk_t}:<input type=checkbox ${add_checked(options.isShowSmithTimer)} id=isShowSmithTimerCheckbox title="">
&nbsp;&nbsp;${texts.gn_t}:<input type=checkbox ${add_checked(options.isShowMercTimer)} id=isShowMercTimerCheckbox title="">
&nbsp;&nbsp;${texts.go_t}:<input type=checkbox ${add_checked(options.isShowHuntTimer)} id=isShowHuntTimerCheckbox title="">
&nbsp;&nbsp;${texts.gv_t} (${texts.gre_t}):<input type=checkbox ${add_checked(options.isShowThiefTimer)} id=isShowThiefTimerCheckbox title="">
    </td>
</tr>
<tr>
    <td>${texts.st_gre_check}: <input type=checkbox ${add_checked(options.gre_check)} id=gre_check_id title=""></td>
</tr>
<tr>
    <td>${texts.st_go_timer_hide} "<i>${texts.regexp_go_timer} ..</i>": <input type=checkbox id=go_timer_hide_id title=""></td>
</tr>
<tr>
    <td>${texts.st_work_trudogolik_off}: <input type=checkbox ${add_checked(options.time_work_trudogolik_off)} id=trudogolik_off_id title=""></td>
</tr>
<tr>
    <td>${texts.st_work_trudogolik_show}: <input type=checkbox ${add_checked(options.time_work_trudogolik_show)} id=trudogolik_show_id title=""></td>
</tr>
<tr>
    <td>${texts.st_disable_multiple_alarms}: <input type=checkbox ${add_checked(options.disable_multiple_alarms)} id=disable_multiple_alarms_id title=""></td>
</tr>
<tr>
    <td>${texts.st_predupr_pa}</td>
</tr>
<tr>
    <td>${texts.st_predupr_go_lic}</td>
</tr>
<tr>
    <td>${texts.st_percent_faster} <input id="gv_n_percent" value="${(100 - options.time_percent_faster * 100)}" style="width: 25px;" maxlength="2"> <b>%</b> <input type="submit" id="gv_n_percent_ok" value="ok"></td>
</tr>
<tr>
    <td>${texts.st_gv_n_time} <input id="gv_n_time" type="number" value="${(60 * options.time_percent_faster * options.time_percent_prem)}" style="width: 25px;" maxlength="2"> <b>min</b>
    <input type="submit" id="gv_n_time_ok" value="ok"></td>
</tr>
<tr>
    <td> <input type="submit" id="null_tr_id" value="${texts.st_null_timers}">&nbsp;&nbsp;&nbsp;</td>
</tr>
<tr>
    <td>${texts.alarm_mode} <input type="radio" name="r_notify_type" id="r_notify_0">${texts.alarm_mode_sound}
    <input type="radio" name="r_notify_type" id="r_notify_1">${texts.alarm_mode_alert}
    <input type="radio" name="r_notify_type" id="r_notify_2">${texts.alarm_mode_both}
    <input type="radio" name="r_notify_type" id="r_notify_3">${texts.alarm_mode_none}
    </td>
</tr>
<tr>
    <td>
        <table>
            <tr>
                <td>${texts.audio_file + texts.gr_t}</td>
                <td><input size=55 type="text" id="audio_file_gr" value="${options.audio_file_gr || ''}"></td>
                <td><input size=55 type="button" id="play_audio_gr" value="Play!">  </td>
            </tr>
            <tr>
                <td>${texts.audio_file + texts.gonv_t}</td>
                <td><input size=55 type="text" id="audio_file_gonv" value="${options.audio_file_gonv || ''}"></td>
                <td><input size=55 type="button" id="play_audio_gonv" value="Play!">  </td>
            </tr>
            <tr>
                <td>${texts.audio_file + texts.gk_t}</td>
                <td><input size=55 type="text" id="audio_file_gk" value="${options.audio_file_gk || ''}"></td>
                <td><input size=55 type="button" id="play_audio_gk" value="Play!">  </td>
            </tr>
            <tr>
                <td>${texts.audio_file + texts.h_t}</td>
                <td><input size=55 type="text" id="audio_file_h" value="${options.audio_file_h || ''}"></td>
                <td><input size=55 type="button" id="play_audio_h" value="Play!">  </td>
            </tr>
        </table>
    </td>
</tr>
`;
    const optionsContainer = createElement("table", { innerHTML: bgcinnerHTML });

    optionsContainer.querySelector("#null_tr_id").addEventListener("click", null_tr);
    optionsContainer.querySelector("#gv_n_time_ok").addEventListener("click", function() { if(Number(document.getElementById("gv_n_time").value) >= 0) { GM_setValue(`AmbushTimeout${PlayerId}`, Date.now() + document.getElementById("gv_n_time").value * 60000); } });
    optionsContainer.querySelector("#gv_n_percent_ok").addEventListener("click", gv_n_percent_f);
    optionsContainer.querySelector("#gre_check_id").addEventListener("click", function() { updateOption("gre_check", this.checked ? '1' : '0'); });
    optionsContainer.querySelector("#trudogolik_show_id").addEventListener("click", function() { updateOption("time_work_trudogolik_show", this.checked ? '1' : '0'); });
    optionsContainer.querySelector("#trudogolik_off_id").addEventListener("click", function() { updateOption("time_work_trudogolik_off", this.checked ? '1' : '0'); });
    optionsContainer.querySelector("#disable_multiple_alarms_id").addEventListener("click", function() { updateOption("disable_multiple_alarms", this.checked ? '1' : '0'); });
    
    const go_timer_hide_id = optionsContainer.querySelector("#go_timer_hide_id");
    go_timer_hide_id.checked = gmGetBool("HideHuntTimer");
    go_timer_hide_id.addEventListener("click", function() { GM_setValue("HideHuntTimer", this.checked); }, false);
    
    optionsContainer.querySelector("#isShowWorkTimerCheckbox").addEventListener("click", function() { updateOption("isShowWorkTimer", this.checked ? '1' : '0'); bindTimersPanel(); });
    optionsContainer.querySelector("#isShowSmithTimerCheckbox").addEventListener("click", function() { updateOption("isShowSmithTimer", this.checked ? '1' : '0'); bindTimersPanel(); });
    optionsContainer.querySelector("#isShowMercTimerCheckbox").addEventListener("click", function() { updateOption("isShowMercTimer", this.checked ? '1' : '0'); bindTimersPanel(); });
    optionsContainer.querySelector("#isShowHuntTimerCheckbox").addEventListener("click", function() { updateOption("isShowHuntTimer", this.checked ? '1' : '0'); bindTimersPanel(); });
    optionsContainer.querySelector("#isShowThiefTimerCheckbox").addEventListener("click", function() { updateOption("isShowThiefTimer", this.checked ? '1' : '0'); bindTimersPanel(); });

    optionsContainer.querySelector("#audio_file_gr").addEventListener("change", function() { updateOption("audio_file_gr", this.value.trim()); audio_gr = initAudio(options.audio_file_gr); });
    optionsContainer.querySelector("#audio_file_gonv").addEventListener("change", function() { updateOption("audio_file_gonv", this.value.trim()); audio_gonv = initAudio(options.audio_file_gonv); });
    optionsContainer.querySelector("#audio_file_gk").addEventListener("change", function() { updateOption("audio_file_gk", this.value.trim()); audio_gk = initAudio(options.audio_file_gk); });
    optionsContainer.querySelector("#audio_file_h").addEventListener("change", function() { updateOption("audio_file_h", this.value.trim()); audio_h = initAudio(options.audio_file_h); });

    optionsContainer.querySelector("#play_audio_gr").addEventListener("click", function() { play_audio(options.audio_file_gr); });
    optionsContainer.querySelector("#play_audio_gonv").addEventListener("click", function() { play_audio(options.audio_file_gonv); });
    optionsContainer.querySelector("#play_audio_gk").addEventListener("click", function() { play_audio(options.audio_file_gk); });
    optionsContainer.querySelector("#play_audio_h").addEventListener("click", function() { play_audio(options.audio_file_h); });
    
    optionsContainer.querySelector("#r_notify_0").addEventListener("click", function() { if(this.checked) { GM_setValue(`NotificationType${PlayerId}`, "0"); } });
    optionsContainer.querySelector("#r_notify_1").addEventListener("click", function() { if(this.checked) { GM_setValue(`NotificationType${PlayerId}`, "1"); } });
    optionsContainer.querySelector("#r_notify_2").addEventListener("click", function() { if(this.checked) { GM_setValue(`NotificationType${PlayerId}`, "2"); } });
    optionsContainer.querySelector("#r_notify_3").addEventListener("click", function() { if(this.checked) { GM_setValue(`NotificationType${PlayerId}`, "3"); } });
    optionsContainer.querySelector(`#r_notify_${GM_getValue(`NotificationType${PlayerId}`, 0)}`).checked = true;
    
    createPupupPanel(GM_info.script.name, `${isEn ? "Options" : "Настройки"} ${GM_info.script.name}`, [[optionsContainer]]);
}
function add_checked(val) { return val == '1' ? 'checked' : ''; }
function play_audio(src) {
    if(src && src != '') {
        var paudio = new Audio();
        paudio.preload = 'auto';
        paudio.src = src;
        paudio.play();
    } else {
        audio_default.play();
    }
}
function gv_n_percent_f() {
    if(Number(document.getElementById("gv_n_percent").value) >= 0) {
        options = JSON.parse(GM_getValue(`hwmTimersOptions${PlayerId}`));
        options.time_percent_faster = '' + ((100 - document.getElementById("gv_n_percent").value) / 100);
        document.getElementById("gv_n_time").value = (60 * options.time_percent_faster * options.time_percent_prem);
        GM_setValue(`hwmTimersOptions${PlayerId}`, JSON.stringify(options));
    }
}
function null_tr() { // обнуление всех таймеров
    GM_deleteValue(`WorkEnd${PlayerId}`);
    GM_deleteValue(`RepairEnd${PlayerId}`);
    GM_deleteValue(`MercenaryTimeout${PlayerId}`);
    GM_deleteValue(`HuntTimeout${PlayerId}`);
    GM_deleteValue(`AmbushTimeout${PlayerId}`);
}
function getUrlParamValue(url, paramName) { return (new URLSearchParams(url.split("?")[1])).get(paramName); }
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 GM_addStyle(css) { addElement("style", document.head, { type: "text/css", innerHTML: css }); }
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 getServerTime() { return Date.now() + parseInt(GM_getValue("ClientServerTimeDifference", 0)); }
function getServerDateTime() { return new Date(getServerTime()); }
function toServerTime(clientTime) { return clientTime -  parseInt(GM_getValue("ClientServerTimeDifference", 0)); }
function serverNow() { return toServerTime(Date.now()); }
function requestServerTime() {
    if(parseInt(GM_getValue("LastClientServerTimeDifferenceRequestDate", 0)) + 60 * 60 * 1000 < (new Date().getTime())) {
        GM_setValue("LastClientServerTimeDifferenceRequestDate", new Date().getTime());
        const objXMLHttpReqTime = new XMLHttpRequest();
        objXMLHttpReqTime.open('GET', '/time.php?rand=' + (Math.random() * 1000000), true);
        objXMLHttpReqTime.onreadystatechange = function() {
            if(objXMLHttpReqTime.readyState == 4 && objXMLHttpReqTime.status == 200) {
                let responseParcing = /now (\d+)/.exec(objXMLHttpReqTime.responseText); //objXMLHttpReqTime.responseText: now 1681711364 17-04-23 09:02
                if(responseParcing) {
                    GM_setValue("ClientServerTimeDifference", new Date().getTime() - parseInt(responseParcing[1]) * 1000);
                }
            }
        }
        objXMLHttpReqTime.send(null);
    } else {
        setTimeout(function() { requestServerTime(); }, 60 * 60 * 1000);
    }
}
function gmGetBool(valueName) {
    const value = GM_getValue(valueName);
    if(value) {
        if(typeof(value) == "string") {
            return value == "true";
        }
        if(typeof(value) == "boolean") {
            return value;
        }
    }
    return false;
}
function observe(target, handler, once = false) {
    const config = { childList: true, subtree: true };
    const ob = new MutationObserver(async function(mut, observer) {
        observer.disconnect();
        if(handler.constructor.name === 'AsyncFunction') {
            await handler();
        } else {
            handler();
        }
        if(!once) {
            observer.observe(target, config);
        }
    });
    ob.observe(target, config);
}
function createPupupPanel(panelName, panelTitle, fieldsMap, panelToggleHandler) {
    const backgroundPopupPanel = addElement("div", document.body, { id: panelName + "1", style: "position: fixed; left: 0pt; width: 100%; background: none repeat scroll 0% 0% gray; opacity: 0.5; top: 0px; height: 100%; display: block; z-index: 200;" });
    backgroundPopupPanel.addEventListener("click", function() { hidePupupPanel(panelName, panelToggleHandler); });

    const popupPanel = addElement("div", document.body, { id: panelName + "2", style: `position: fixed; width: 650px; background: none repeat scroll 0% 0%; background-image: linear-gradient(to right, #eea2a2 0%, #bbc1bf 19%, #57c6e1 42%, #b49fda 79%, #7ac5d8 100%); left: ${((document.body.offsetWidth - 650) / 2)}px; top: 150px; display: block; z-index: 200; border: 4mm ridge rgba(211, 220, 50, .6);` });
    const contentDiv = addElement("div", popupPanel, { id: panelName + "3", style: "border: 1px solid #abc; padding: 5px; margin: 2px; display: flex; flex-wrap: wrap;" });

    if(panelTitle) {
        addElement("b", contentDiv, { innerText: panelTitle, style: "text-align: center; margin: auto; width: 90%; display: block;" });
    }
    const divClose = addElement("div", contentDiv, { id: panelName + "close", title: "Close", innerText: "x", style: "border: 1px solid #abc; width: 15px; height: 15px; text-align: center; cursor: pointer;" });
    divClose.addEventListener("click", function() { hidePupupPanel(panelName, panelToggleHandler); });

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

    if(fieldsMap) {
        let contentTable = addElement("table", contentDiv);
        for(const rowData of fieldsMap) {
            if(rowData.length == 0) { // Спомощью передачи пустой стороки-массива, указываем, что надо начать новую таблицу после брейка
                addElement("div", contentDiv, { style: "flex-basis: 100%; height: 0;"});
                contentTable = addElement("table", contentDiv);
                continue;
            }
            const row = addElement("tr", contentTable);
            for(const cellData of rowData) {
                const cell = addElement("td", row);
                if(cellData) {
                    if(typeof(cellData) == "string") {
                        cell.innerText = cellData;
                    } else {
                        cell.appendChild(cellData);
                    }
                }
            }
        }
    }
    if(panelToggleHandler) {
        panelToggleHandler(true);
    }
    return contentDiv;
}
function showPupupPanel(panelName, panelToggleHandler) {
    let backgroundPopupPanel = document.getElementById(panelName + "1");
    let popupPanel = document.getElementById(panelName + "2");
    if(backgroundPopupPanel) {
        backgroundPopupPanel.style.display = popupPanel.style.display = 'block';
        if(panelToggleHandler) {
            panelToggleHandler(true);
        }
        return true;
    }
    return false;
}
function hidePupupPanel(panelName, panelToggleHandler) {
    let backgroundPopupPanel = document.getElementById(panelName + "1");
    let popupPanel = document.getElementById(panelName + "2");
    backgroundPopupPanel.style.display = popupPanel.style.display = 'none';
    if(panelToggleHandler) {
        panelToggleHandler(false);
    }
}
function healthTimer() {
    if(isHeartOnPage) {
        const health_amount = document.getElementById("health_amount");
        let heart; // 78
        let maxHeart; // 100
        let timeHeart; // 405
        if(health_amount) {
            const res = /top_line_draw_canvas_heart\((\d+), (\d+), (\d+)\);/.exec(document.body.innerHTML); // top_line_draw_canvas_heart(0, 100, 405);
            if(res) {
                heart = parseInt(res[1]);
                maxHeart = parseInt(res[2]);
                timeHeart = parseInt(res[3]);
            }
        } else {
            heart = windowObject.heart;
            maxHeart = windowObject.max_heart;
            timeHeart = windowObject.time_heart;
        }
        //console.log(`healthTimer heart: ${heart}, maxHeart: ${maxHeart}, timeHeart: ${timeHeart}`);
        let restSeconds = timeHeart * (maxHeart - heart) / maxHeart;
        if(restSeconds > 0) {
            GM_setValue(`HealthRestoreTime${PlayerId}`, Date.now() + restSeconds * 1000);
        } else {
            GM_deleteValue(`HealthRestoreTime${PlayerId}`);
        }
        return [heart, maxHeart, timeHeart];
    }
}
async function initUserName() {
    if(GM_getValue("TransporterUserName")) {
        GM_deleteValue("UserName");
        GM_deleteValue("TransporterUserName");
    }
    if(location.pathname == "/pl_info.php" && getUrlParamValue(location.href, "id") == PlayerId) {
        //console.log(document.querySelector("h1").innerText)
        GM_setValue("UserName", document.querySelector("h1").innerText);
    }
    if(location.pathname == "/home.php") {
        //console.log(document.querySelector(`a[href='pl_info.php?id=${PlayerId}'] > b`).innerText)
        GM_setValue("UserName", document.querySelector(`a[href='pl_info.php?id=${PlayerId}'] > b`).innerText);
    }
    if(!GM_getValue("UserName")) {
        const doc = await getRequest(`/pl_info.php?id=${PlayerId}`);
        GM_setValue("UserName", doc.querySelector("h1").innerText);
    }
}
function parseDate(dateString, isFuture = false) {
    //console.log(dateString)
    if(!dateString) {
        return;
    }
    const dateStrings = dateString.split(" ");

    let hours = 0;
    let minutes = 0;
    let seconds = 0;
    const timePart = dateStrings.find(x => x.includes(":"));
    if(timePart) {
        const time = timePart.split(":");
        hours = parseInt(time[0]);
        minutes = parseInt(time[1]);
        if(time.length > 2) {
            seconds = parseInt(time[2]);
        }
    }

    const now = new Date();
    let year = now.getFullYear();
    let month = now.getMonth();
    let day = now.getDate();
    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) {
            year = isEn ? parseInt(date[0]) : parseInt(date[2]);
            if(year < 1000) {
                year += Math.floor((new Date()).getFullYear() / 1000) * 1000;
            }
        } else {
            if(isFuture && month == 0 && now.getMonth() == 11) {
                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]))}`);
    return new Date(year, month, day, hours, minutes, seconds);
}
function parseBattleResultPanel() {
    if(GM_getValue("ChallengeState") == ChallengeState.Battle && finalResultDiv.innerHTML.length > 10) {
        GM_deleteValue("ChallengeState");
        const bolds = finalResultDiv.querySelectorAll("font b");
        let result = "fail";
        for(const bold of bolds) {
            if(bold.innerHTML == (isEn ? "Victorious:" : "Победившая сторона:")) {
                //console.log(`${bold.parentNode.nextSibling.nextSibling.firstChild.innerText}, UserName: ${GM_getValue("UserName")}`);
                if(bold.parentNode.nextSibling.nextSibling.firstChild.innerText == GM_getValue("UserName")) {
                    result = "win";
                }
                break;
            }
        }
        if(result == "fail") {
            GM_setValue("AmbushSuspendExpireDate", Date.now() + AmbushMinutesInterval * 60 * 1000);
        }
        //console.log(`result: ${result}, AmbushSuspendExpireDate: ${GM_getValue("AmbushSuspendExpireDate")}`);
    }
}