hwmSetsMaster

Меню наборов армии, навыков и оружия. Смена фракции.

目前為 2023-11-29 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name           hwmSetsMaster
// @author         Tamozhnya1
// @namespace      Tamozhnya1
// @description    Меню наборов армии, навыков и оружия. Смена фракции.
// @version        8.6
// @encoding        utf-8
// @include        *heroeswm.ru/*
// @include        *lordswm.com/*
// @exclude        */rightcol.php*
// @exclude        */ch_box.php*
// @exclude        */chat*
// @exclude        */ticker.html*
// @exclude        */frames*
// @exclude        */brd.php*
// @grant          GM_getValue
// @grant          GM_setValue
// @grant          GM_deleteValue
// @grant 		   GM.xmlHttpRequest
// @license        MIT
// ==/UserScript==

const playerIdMatch = document.cookie.match(/pl_id=(\d+)/);
if(playerIdMatch) {
    var PlayerId = playerIdMatch[1];
}
let Fraction;
const windowObject = window.wrappedJSObject || unsafeWindow;
const isEn = document.documentElement.lang == "en";
const Strings = {
        "ru": {
            Army: ustring("Армия"),
            Save: ustring("Сохранить"),
            Add: ustring("Добавить"),
            AddCurrent: ustring("Добавить текущий"),
            SetName: ustring("Наименование набора"),
            Delete: ustring("Удалить"),
            Talents: ustring("Навыки"),
            Weapon: ustring("Оружие"),
            RemoveAll: ustring("Снять все"),
            EnterJpg: "enter0.jpg",
            SignInTitle: "Войти",
            Castle: "Замок",
            Task: ustring("Задание"),
            Apply: ustring("Применить"),
            EnterButtonValue: ustring("ВОЙТИ"),
            AvailablePoints: "Свободных очков",
            AvailableTalentPoints: "Свободных очков от навыка",
            IncreaseManyPointsTooltip: "Введите число от ${minValue} до ${maxValue}. Нажмите Tab."
        },
        "en": {
            Army: "Army",
            Save: "Save",
            Add: "Add",
            AddCurrent: "Add current",
            SetName: "Set name",
            Delete: "Delete",
            Talents: "Talents",
            Weapon: "Weapon",
            RemoveAll: "Un-equip all",
            EnterJpg: "enter0_eng.jpg",
            SignInTitle: "Sign in",
            Castle: "Castle",
            Task: "Task",
            Apply: "Apply",
            EnterButtonValue: "ENTER",
            AvailablePoints: "Available points",
            AvailableTalentPoints: "Available talent points",
            IncreaseManyPointsTooltip: "Enter number from ${minValue} to ${maxValue}. Press Tab."
        }
    };
const LocalizedString = Strings[document.documentElement.lang || "ru"];
let userName;
const isMobileInterface = document.querySelector("div#btnMenuGlobal") ? true : false;
const isMobileDevice = mobileCheck(); // Там нет мышки
const isNewInterface = document.querySelector("#main_top_table") ? false : true;
const isNewPersonPage = document.querySelector("div#hwm_no_zoom") ? true : false;

ensureGmMethods();
getUserName();
getFraction();

/************************************************************************************************************/
const weaponSetsPreferences = {
    menuTitle: LocalizedString.Weapon,
    setReferencePage: "inventory.php",
    sets: new Array(),
    menuItems: {},
    currentMenuItem: undefined,
    refreshingPages: "home.php;inventory.php;pl_info.php",
    updatePanelHandler: async function() {
        if(location.pathname == '/home.php') {
            let updatePanel, newUpdatePanel;
            const doc = await getRequest(`/home.php`);
            if(isNewPersonPage) {
                updatePanel = document.querySelector("div#inv_doll_stats");
                newUpdatePanel = doc.querySelector("div#inv_doll_stats");
            } else {
                updatePanel = getParent(document.querySelector("div.arts_info.shop_art_info"), "table");
                newUpdatePanel = getParent(doc.querySelector("div.arts_info.shop_art_info"), "table");
            }
            Array.from(newUpdatePanel.querySelectorAll("img.show_hint")).forEach(x => x.setAttribute("title", x.getAttribute("hint").replace(/<br \/>/g, "\n")));
            updatePanel.innerHTML = newUpdatePanel.innerHTML;
            return true;
        }
        if(location.pathname == '/pl_info.php') {
            if(getUrlParamValue(location.href, "id") == PlayerId) {
                const doc = await getRequest(`/pl_info.php?id=${PlayerId}`);
                const updatePanel = getParent(document.querySelector("div[class^='slot']"), "div");
                const newUpdatePanel = getParent(doc.querySelector("div[class^='slot']"), "div");
                Array.from(newUpdatePanel.querySelectorAll("img.show_hint")).forEach(x => x.setAttribute("title", x.getAttribute("hint").replace(/<br \/>/g, "\n")));
                updatePanel.innerHTML = newUpdatePanel.innerHTML;
            }
            return true;
        }
        return false;
    },
    refreshingConditions: function() {
        if(/map.php/.test(location.href)) {
            const bolds = document.querySelectorAll("b");
            for(const bold of bolds) {
                if(bold.innerText.includes(LocalizedString.Task)) {
                    return true;
                }
            }
            const neut_right_block = document.querySelector("#neut_right_block");
            if(neut_right_block) {
                return true;
            }
        }
        return false;
    },
    initSetsApplyAction: function() {
        this.sets.length = 0;
        this.sets.push({ number: 0, name: LocalizedString.RemoveAll, method: "GET", url: "inventory.php?all_off=100" });
        const weaponSets = JSON.parse(GM_getValue(`WeaponSets${PlayerId}`, "{}"));
        for(const setNumber of Object.keys(weaponSets)) {
            this.sets.push({ number: setNumber, name: weaponSets[setNumber], method: "GET", url: `inventory.php?all_on=${setNumber}`, headers: null });
        }
    },
    getCurrentSetName: function() { return `WeaponSet${PlayerId}`; },
    onPageLoad: function() {
        if(/inventory.php/.test(location.href)) {
            const undressDiv = document.querySelector("div[id ='undress_all_div']");
            addSetChangerListener(undressDiv, this, 0);

            const setDivs = document.querySelectorAll("div[set_div_id]"); // Если setDivs.length = 0, то ничего не делаем - мы в заявке на бой
            if(setDivs.length > 0) {
                const weaponSets = {};
                for(const setDiv of setDivs) {
                    const setNumber = setDiv.getAttribute("set_div_id");
                    if(setDiv.hasAttribute("onclick")) {
                        weaponSets[setNumber] = setDiv.innerText;
                        addSetChangerListener(setDiv, this, setNumber);
                    }
                }
                GM_setValue(`WeaponSets${PlayerId}`, JSON.stringify(weaponSets));
            }
        }
        this.findSetChangersAndAddListener();
    },
    findSetChangersAndAddListener: function() {
        let setRefs = document.querySelectorAll("a[href^='inventory.php?all_off=100']");
        for(const setRef of setRefs) {
            addSetChangerListener(setRef, this, 0);
        }
        setRefs = document.querySelectorAll("a[href*='inventory.php?all_on=']");
        for(const weaponSetReference of setRefs) {
            let setNumber = weaponSetReference.getAttribute("href").split("all_on=")[1];
            addSetChangerListener(weaponSetReference, this, setNumber);
        }
    }
};
/***********************************************************************************************************/
const skillSetsPreferences = {
    menuTitle: LocalizedString.Talents,
    setReferencePage: "skillwheel.php",
    sets: new Array(),
    menuItems: {},
    currentMenuItem: undefined,
    refreshingPages: "skillwheel.php;pl_info.php;home.php",
    updatePanelHandler: async function() {
        if(location.pathname == '/home.php') {
            const doc = await getRequest(`/home.php`);
            const statsUpdatePanel = isNewPersonPage ? document.getElementById("home_css_stats_wrap_div") : getParent(document.querySelector("img[src*='attr_attack']"), "table", 2);
            const newStatsUpdatePanel = isNewPersonPage ? doc.getElementById("home_css_stats_wrap_div") : getParent(doc.querySelector("img[src*='attr_attack']"), "table", 2);
            statsUpdatePanel.innerHTML = newStatsUpdatePanel.innerHTML;
            getPerksToHomeCore();
            return true;
        }
        if(location.pathname == '/pl_info.php') {
            if(getUrlParamValue(location.href, "id") == PlayerId) {
                const doc = await getRequest(`/pl_info.php?id=${PlayerId}`);
                const statsUpdatePanel = getParent(document.querySelector("img[src*='attr_attack']"), "table");
                const newStatsUpdatePanel = getParent(doc.querySelector("img[src*='attr_attack']"), "table");
                statsUpdatePanel.innerHTML = newStatsUpdatePanel.innerHTML;

                const perksUpdatePanel = getParent(document.querySelector("a[href^='showperkinfo.php']"), "table", 2);
                const newPerksUpdatePanel = getParent(doc.querySelector("a[href^='showperkinfo.php']"), "table", 2);
                Array.from(newPerksUpdatePanel.querySelectorAll("img.show_hint")).forEach(x => x.setAttribute("title", x.getAttribute("hint").replace(/<br \/>/g, "\n")));
                perksUpdatePanel.innerHTML = newPerksUpdatePanel.innerHTML;
            }
            return true;
        }
        return false;
    },

    onPageLoad: function() {
        const setRefs = document.querySelectorAll("a[href^='skillwheel.php?setuserperk']"); // skillwheel.php?setuserperk=1&prace=4&buildid=5 // skillwheel.php?rand=1&setstats=1&param0=20&param1=8&param2=0&param3=2
        const pageSets = {};
        for(const setRef of setRefs) {
            pageSets[setRef.innerHTML] = getUrlParamValue(setRef.href, "buildid");
            addSetChangerListener(setRef, this, parseInt(getUrlParamValue(setRef.href, "buildid")));
        }
        GM_setValue(`SkillSets${PlayerId}Fraction${Fraction}`, JSON.stringify(pageSets));
    },
    initSetsApplyAction: function () {
        //console.log(GM_getValue(`SkillSets${PlayerId}Fraction${Fraction}`));
        const skillSets = JSON.parse(GM_getValue(`SkillSets${PlayerId}Fraction${Fraction}`, "{}"));
        this.sets = Object.keys(skillSets).map(x => { return { number: parseInt(skillSets[x]), name: x, method: "GET", url: `/skillwheel.php?setuserperk=1&prace=${Fraction}&buildid=${skillSets[x]}` }; });
    },
    getCurrentSetName: function() { return `CurrentSkillSet${PlayerId}Fraction${Fraction}`; }
};
/************************************************************************************************************/
const armySetsPreferences = {
    menuTitle: LocalizedString.Army,
    setReferencePage: "army.php",
    sets: new Array(),
    menuItems: {},
    currentMenuItem: undefined,
    refreshingPages: "home.php;army.php;pl_info.php",
    updatePanelHandler: async function() {
        if(location.pathname == '/home.php') {
            let updatePanel, newUpdatePanel;
            const doc = await getRequest(`/home.php`);
            if(isNewPersonPage) {
                updatePanel = document.querySelector("div.home_pers_army");
                newUpdatePanel = doc.querySelector("div.home_pers_army");
                Array.from(newUpdatePanel.querySelectorAll("div.castle_creature54.show_hint")).forEach(x => x.setAttribute("title", x.getAttribute("hint")));
            } else {
                updatePanel = document.querySelector("center > div > div.cre_creature72").parentNode;
                newUpdatePanel = doc.querySelector("center > div > div.cre_creature72").parentNode;
                Array.from(newUpdatePanel.querySelectorAll("div.cre_creature72 img")).forEach(x => x.setAttribute("title", x.getAttribute("hint")));
            }
            updatePanel.innerHTML = newUpdatePanel.innerHTML;
            return true;
        }
        if(location.pathname == '/pl_info.php') {
            if(getUrlParamValue(location.href, "id") == PlayerId) {
                const doc = await getRequest(`/pl_info.php?id=${PlayerId}`);
                const newUpdatePanel = doc.querySelector("center > div > div.cre_creature72").parentNode;
                Array.from(newUpdatePanel.querySelectorAll("div.cre_creature72 img")).forEach(x => x.setAttribute("title", x.getAttribute("hint")));

                const updatePanel = document.querySelector("center > div > div.cre_creature72").parentNode;
                updatePanel.innerHTML = newUpdatePanel.innerHTML;
            }
            return true;
        }
        // Скрипты ломаются
        // if(location.pathname == '/army.php') {
            // const doc = await getRequest(`/army.php`);
            // const newUpdatePanel = doc.querySelector("div#army_info_div");
            // const updatePanel = document.querySelector("div#army_info_div");
            // updatePanel.innerHTML = newUpdatePanel.innerHTML;
            // return true;
        // }
        return false;
    },
    setsTable: null,

    getCurrentSetName: function() { return `ArmySet${PlayerId}Fraction${Fraction}`; },
    initSetsApplyAction: function () {
        //GM_deleteValue(`ArmySets${PlayerId}Fraction${Fraction}`);
        if(!GM_getValue(`ArmySets${PlayerId}Fraction${Fraction}`)) {
            let savedSetIdsStr = GM_getValue(`${userName}r${Fraction}_savedArmySetIds`);
            let setIds = new Array();
            if(savedSetIdsStr) {
                setIds = savedSetIdsStr.split("|");
            }
            const armySetsData = {};
            for(const setId of setIds) {
                if(setId == "") {
                    continue;
                }
                const setStr = GM_getValue(`${userName}r${Fraction}_savedArmySet${setId}`);
                if(!setStr) {
                    continue;
                }
                let setArr = setStr.split("|");
                armySetsData[setId] = [setArr[7]].concat(setArr.slice(0, 7)).join("|");
            }
            GM_setValue(`ArmySets${PlayerId}Fraction${Fraction}`, JSON.stringify(armySetsData));
        }
        //console.log(GM_getValue(`ArmySets${PlayerId}Fraction${Fraction}`, "{}"));
        const armySetsData = JSON.parse(GM_getValue(`ArmySets${PlayerId}Fraction${Fraction}`, "{}"));
        const armySets = Object.keys(armySetsData).map(x => { const data = armySetsData[x].split("|"); return { Id: x, Name: data[0], Army: data.slice(1).map(y => Number(y)) } });
        this.sets = armySets.map(x => { return { number: parseInt(x.Id), name: x.Name, title: x.Army.join("+"), method: "POST", url: "/army_apply.php", data: x.Army.map((x, i) => `countv${i + 1}=${x}`).join("&"), contentType: "application/x-www-form-urlencoded" }; });
        if(/\/army.php/.test(location.href)) {
            this.drawSetsTable(armySets);
        }
    },
    drawSetsTable: function(armySets) {
        const isInit = this.setsTable ? false : true;
        let container;
        if(isInit) {
            const hwm_for_zoom = document.getElementById("hwm_for_zoom");
            container = document.body;
            if(!isMobileInterface) {
                container = addElement("center", hwm_for_zoom);
            }
            const tableStyle = "background-color: #959595; border: 1px solid #f5c137; table-layout: fixed;" + (isMobileInterface ? "margin: 0 0 0 50px;" : "");
            this.setsTable = addElement("table", container, { style: tableStyle });
        } else {
            this.setsTable.innerHTML = "";
            container = this.setsTable.parentNode;
        }

        const cellWidths = [100, 60, 60, 60, 60, 60, 60, 60, 10, 10];
        for(const cellWidth of cellWidths) {
            this.setsTable.innerHTML += `<col style="width: ${cellWidth}px;" />`;
        }
        this.drawTableHeader();
        for(const armySet of armySets) {
            this.drawSetRow(armySet);
        }
        if(isInit) {
            const saveButton = addElement("input", container, { type: "button", value: LocalizedString.Save, style: isMobileInterface ? "margin: 0 0 0 50px;" : "" });
            saveButton.addEventListener("click", this.saveSets);
            const addCurrentButton = addElement("input", container, { type: "button", value: LocalizedString.AddCurrent });
            addCurrentButton.addEventListener("click", function() { armySetsPreferences.drawSetRow(); });
        }
    },
    drawTableHeader: function () {
        if(!this.setsTable) {
            return;
        }
        let cellStyle = "border: 1px solid #f5c137; overflow: hidden;";
        let units = windowObject.obj;
        let tr = addElement("tr", this.setsTable);
        addElement("td", tr, { innerHTML: LocalizedString.SetName.replace(/ /g, "<br>").replace(/-/g, "-<br>"), style: "font-weight: bold; font-size: 8pt; text-align: center; border: 1px solid #f5c137; overflow: hidden;" }); // ; overflow: hidden
        for(let i = 1; i <= 7; i++) {
            addElement("td", tr, { innerHTML: units[i]['name'].replace(/ /g, "<br>").replace(/-/g, "-<br>"), style: "font-weight: bold; font-size: 8pt; text-align: center; border: 1px solid #f5c137; overflow: hidden;", onClick: `ChangeSlider(event, ${i}, 0);` });
        }
        addElement("td", tr, { style: cellStyle });
        addElement("td", tr, { style: cellStyle });
    },
    drawSetRow: function(armySet) {
        const isNew = armySet ? false : true;
        const units = windowObject.obj;
        //console.log(`armySet: ${armySet}, units: ${units}`);
        //console.log(units.slice(1));
        armySet = armySet || { Id: (new Date()).getTime(), Name: "", Army: [units[1], units[2], units[3], units[4], units[5], units[6], units[7]].map(x => x.nownumberd) };
        let cellStyle = "border: 1px solid #f5c137; overflow: hidden;";
        if(!this.setsTable) {
            return;
        }
        let tr = addElement("tr", this.setsTable, { setId: armySet.Id });
        let td = addElement("td", tr, { style: cellStyle });
        let input = addElement("input", td, { value: armySet.Name, onfocus: `this.select();`, style: "width: 97px;" }); //, style: "overflow: hidden;"
        for(let i = 0; i < armySet.Army.length; i++) {
            td = addElement("td", tr, { style: cellStyle });
            input = addElement("input", td, { value: armySet.Army[i], onfocus: `ChangeSlider(event, ${i + 1}, 0); this.select();`, type: "number", style: "min-width: 47px; width: 98%; text-align: right;" });
        }
        td = addElement("td", tr, { style: cellStyle });
        let delButton = addElement("input", td, { type: "button", value: "x", title: LocalizedString.Delete });
        delButton.addEventListener("click", this.deleteSet);

        td = addElement("td", tr, { style: cellStyle });
        if(!isNew) {
            let applyButton = addElement("input", td, { type : "button", value : "v", title : LocalizedString.Apply });
            applyButton.addEventListener("click", function() { armySetsPreferences.saveSets(); applySet(null, armySetsPreferences, { number: parseInt(armySet.Id), name: armySet.Name, title: armySet.Army.join("+"), method: "POST", url: "army_apply.php", data: armySet.Army.reduce((x, y, i) => `${x}&countv${i + 1}=${y}`, ""), contentType: "application/x-www-form-urlencoded" }); });
        }
    },
    saveSets: function () {
        const rows = Array.from(armySetsPreferences.setsTable.rows).slice(1);
        const armySetsData = rows.reduce((t, x) => ({ ...t, [x.getAttribute("setId")]: Array.from(x.cells).slice(0, 8).map(y => y.firstChild.value).join("|") }), {});
        GM_setValue(`ArmySets${PlayerId}Fraction${Fraction}`, JSON.stringify(armySetsData));
    },
    deleteSet: function () {
        const table = this.parentNode.parentNode.parentNode;
        const row = this.parentNode.parentNode;
        table.removeChild(row);
    }
};
/************************************************************************************************************/
const factionsPreferences = {
    menuTitle: LocalizedString.Castle,
    setReferencePage: "castle.php",
    sets: new Array(),
    menuItems: {},
    currentMenuItem: undefined,
    refreshingPages: "home.php;army.php;pl_info.php;castle.php;inventory.php;skillwheel.php",
    initSetsApplyAction: function() {
        const fractions = JSON.parse(GM_getValue(`Fractions${PlayerId}`, "{}"));
        this.sets.length = 0;
        for(const fractionName of Object.keys(fractions)) {
            const set = { number: fractions[fractionName], name: fractionName, method: "GET" };
            const sign = GM_getValue(`Sign${PlayerId}`);
            if(sign) {
                set.url = `castle.php?change_clr_to=${fractions[fractionName]}&sign=${sign}`;
            }
            this.sets.push(set);
        }
    },
    getCurrentSetName: function() { return `Fraction${PlayerId}`; },
    onPageLoad: async function () {
        await this.initCastlesList();
        this.findSetChangersAndAddListener();
    },
    initCastlesList: async function () {
        let doc = document;
        if(!/castle.php/.test(location.href)) {
            if(GM_getValue(`Sign${PlayerId}`)) {
                return;
            }
            doc = await getRequest("/castle.php");
        }
        const castleNamesDivs = doc.querySelectorAll("div.castle_faction_div_inside");
        const fractions = {};
        for(const castleNameDiv of castleNamesDivs) {
            const castleName = castleNameDiv.getAttribute("hint");
            fractions[castleName] = getUrlParamValue(castleNameDiv.firstChild.href, "show_castle_f");
        }
        GM_setValue(`Fractions${PlayerId}`, JSON.stringify(fractions));
        const castle_yes_no_dialogDiv = doc.querySelector("div.castle_yes_no_dialog");
        if(castle_yes_no_dialogDiv) {
            const changeCastleRef = castle_yes_no_dialogDiv.querySelector("a[href*='castle.php?change_clr_to']");
            if(changeCastleRef) {
                GM_setValue(`Sign${PlayerId}`, getUrlParamValue(changeCastleRef.href, "sign"));
            }
        }
    },
    findSetChangersAndAddListener: function() {
        const setRefs = document.querySelectorAll("a[href*='castle.php?change_clr_to']");
        for(const setRef of setRefs) {
            addSetChangerListener(setRef, this, getUrlParamValue(setRef.href, "change_clr_to"));
        }
    },
    setChanged: function(newSetNumber) {
        Fraction = newSetNumber;
        GM_setValue(`Fraction${PlayerId}`, Fraction);
        createMenu();
    }
};

/************************************************************************************************************/
const preferences = [weaponSetsPreferences, skillSetsPreferences, armySetsPreferences, factionsPreferences];
const isHeartOnPage = document.querySelector("canvas#heart") || document.querySelector("div#heart_js_mobile");
main();
function mobileCheck() {
  let check = false;
  (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
  return check;
};
function main() {
    getPerksToHome();
    if(isHeartOnPage && PlayerId && Fraction) {
        for(const preference of preferences) {
            if(preference.onPageLoad) {
                preference.onPageLoad();
            }
        }
        createMenu();
        window.addEventListener("resize", function() { createMenu(true); });
        drowSkillChangers();
        const container = document.querySelector("div#home_css_stats_wrap_div");
        observe(container, drowSkillChangers);
    }
}
function getPerksToHome() {
    if(location.pathname == '/home.php') {
        let hwmSetsMasterPerksContainer = document.getElementById("hwmSetsMasterPerksContainer");
        if(!hwmSetsMasterPerksContainer) {
            let homePagePerksContainer;
            if(isNewPersonPage) {
                homePagePerksContainer = document.querySelector("div.home_friends_block");
            } else {
                homePagePerksContainer = 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", homePagePerksContainer);
            const showPerksTitleSpan = addElement("span", homePagePerksContainer, { innerHTML: `&nbsp;&raquo;&nbsp;<b>${isEn ? "Perks" : "Навыки"}:`, title: getShowPerksTitleSpanTitle() });
            showPerksTitleSpan.addEventListener("click", function() { GM_setValue("ShowPerks", !gmGetBool("ShowPerks")); this.title = getShowPerksTitleSpanTitle(); }, false);
            addElement("br", homePagePerksContainer);
            hwmSetsMasterPerksContainer = addElement("div", homePagePerksContainer, { id: "hwmSetsMasterPerksContainer" });
        }
        getPerksToHomeCore();
    }
}
async function getPerksToHomeCore() {
    if(location.pathname == '/home.php' && gmGetBool("ShowPerks")) {
        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.setAttribute("title", x.getAttribute("hint")); x.style.width = `48px`; x.style.height = "auto"; });
            document.getElementById("hwmSetsMasterPerksContainer").innerHTML = perksTable.outerHTML;
        }
    }
}
function getShowPerksTitleSpanTitle() { return isEn ? `Click for ${gmGetBool("ShowPerks") ? "disable" : "enable"} perks loading` : `Нажмите для ${gmGetBool("ShowPerks") ? "выключения" : "включения"} загрузки навыков`; }
function getMenuAnchorElement() {
    // const homeRefs = document.querySelectorAll("a[href='home.php']");
    // console.log(`homeRefs: ${homeRefs.length}`);
    const menuPanel = document.querySelector("div.sh_MenuPanel") || document.querySelector("#main_top_table") || document;
    if(menuPanel) {
        const homeRef = menuPanel.querySelector("a[href='home.php']");
        if(isNewInterface) {
            //homeRef.parentNode.addEventListener("resize", function() { createMenu(true); });
            return homeRef.parentNode;
        } else {
            const result = homeRef.parentNode?.parentNode?.parentNode?.parentNode?.parentNode?.parentNode?.parentNode?.parentNode?.parentNode?.parentNode?.parentNode?.parentNode?.parentNode?.parentNode?.parentNode?.parentNode?.parentNode;
            if(!result) {
                result = homeRef.parentNode;
            }
            return result;
        }
    }
}
function getTextWidth(text, font) {
    const canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas")); // re-use canvas object for better performance
    const context = canvas.getContext("2d");
    context.font = font;
    const metrics = context.measureText(text);
    return metrics.width;
}
function getCssStyle(element, prop) { return window.getComputedStyle(element, null).getPropertyValue(prop); }
function getCanvasFont(el = document.body) {
    const fontWeight = getCssStyle(el, 'font-weight') || 'normal';
    const fontSize = getCssStyle(el, 'font-size') || '16px';
    const fontFamily = getCssStyle(el, 'font-family') || 'Times New Roman';
    return `${fontWeight} ${fontSize} ${fontFamily}`;
}
function getOrCreateAndResizeDropdown(baseElement, style) {
    const dropdownId = `${baseElement.id}Dropdown`;
    let dropdown = document.getElementById(dropdownId);
    if(!dropdown) {
        dropdown = addElement("div", document.body, { id: dropdownId, style: `position: absolute; z-index: ${baseElement.style.zIndex};` + (style || "") });
        if(isMobileDevice) {
            baseElement.addEventListener("click", function() {
                dropdown.style.display = dropdown.style.display == "none" ? "block" : "none";
                if(dropdown.style.display == "block") {
                    const dropdowns = document.querySelectorAll("div[id$=Dropdown]");
                    for(const dropdown of dropdowns) {
                        if(dropdown.id != dropdownId) {
                            dropdown.style.display = "none";
                        }
                    }
                }
            });
        } else {
            let hideTimer;
            const dropdownTimeout = 100;
            baseElement.addEventListener("mouseenter", function() { clearTimeout(hideTimer); if(dropdown.style.display == "none") { setTimeout(function() { dropdown.style.display = "block"; }, dropdownTimeout); } });
            baseElement.addEventListener("mouseleave", function() { hideTimer = setTimeout(function() { dropdown.style.display = "none"; }, dropdownTimeout); });
            dropdown.addEventListener("mouseenter", function() { clearTimeout(hideTimer); });
            dropdown.addEventListener("mouseleave", function() { hideTimer = setTimeout(function() { dropdown.style.display = "none"; }, dropdownTimeout); });
        }
    }
    const baseElementRect = baseElement.getBoundingClientRect();
    dropdown.style.top = `${baseElementRect.bottom + window.scrollY + 1}px`;
    dropdown.style.left = `${baseElementRect.left}px`;
    return dropdown;
}
function createMenu(isResize) {
    const menuAnchor = getMenuAnchorElement();
    if(!menuAnchor) {
        return;
    }
    const anchorRect = menuAnchor.getBoundingClientRect();
    //console.log(anchorRect);
    const borderWidth = isNewInterface ? 1 : 2;
    const menuItemHeight = anchorRect.height - borderWidth * 2;
    const menuItemLineHeight = menuItemHeight - borderWidth;
    const menuItemTop = anchorRect.top + window.scrollY;
    const foreColor = "#f5c137";
    const backgroundColor = isNewInterface ? "linear-gradient(to top, #09203f 0%, #537895 100%)" : (document.querySelector("img[src*='i/top_ny']") ? "#003399" : "#6b6b69");
    const zIndex = location.pathname == "/photo_pl_photos.php" ? "0" : "100";
    let currentMenuItemLeft = anchorRect.left - borderWidth - 1;
    for(let i = preferences.length - 1; i >= 0; i--) {
        const currentPreferences = preferences[i];
        const mainMenuItemId = `SetsMenuItem${i}`;
        let mainMenuItem = document.getElementById(mainMenuItemId);
        if(!mainMenuItem) {
            const menuHeaderStyle = `font-size: 9pt; position: absolute; border-radius: 5px; background: ${backgroundColor}; color: ${foreColor}; border: ${borderWidth}px solid ${foreColor}; padding: 0 3px 0 3px; font-weight: bold; text-align: center; z-index: ${zIndex};`;
            mainMenuItem = addElement("div", document.body, { id: mainMenuItemId, style: menuHeaderStyle });
            if(isMobileDevice) {
                addElement("span", mainMenuItem, { innerHTML: currentPreferences.menuTitle, style: `color: ${foreColor}; text-decoration: none;` });
            } else {
                addElement("a", mainMenuItem, { innerHTML: currentPreferences.menuTitle, href: currentPreferences.setReferencePage, style: `color: ${foreColor}; text-decoration: none;` });
            }
        }
        mainMenuItem.style.height = `${menuItemHeight}px`;
        mainMenuItem.style.lineHeight = `${menuItemLineHeight}px`;
        mainMenuItem.style.top = `${menuItemTop}px`;

        const mainMenuItemRect = mainMenuItem.getBoundingClientRect();
        currentMenuItemLeft -= mainMenuItemRect.width;
        mainMenuItem.style.left = `${currentMenuItemLeft}px`;

        const menuContent = getOrCreateAndResizeDropdown(mainMenuItem, `list-style-position: inside; color: ${foreColor}; padding: 2px 3px 2px 3px; white-space: nowrap; background: ${backgroundColor};`);
        if(isResize) {
            continue;
        }
        currentPreferences.initSetsApplyAction();
        menuContent.style.display = "block"; // Перед заполнением покажем див для правильного определения его размеров (нужно, если он установлен в none)
        menuContent.innerHTML = '';
        const currentSetNumber = GM_getValue(currentPreferences.getCurrentSetName(), -1);
        let maxClientWidth = menuContent.clientWidth;
        for(const currentSet of currentPreferences.sets) {
            const dropDownMenuItem = addElement("li", menuContent, { type: "disc", style: "text-align: left;" });
            const currentSetReference = addElement("b", dropDownMenuItem, { innerHTML: currentSet.name, title: currentSet.title || "", style: `color: ${foreColor}; cursor: pointer;` });
            if(currentSet.url) {
                currentSetReference.addEventListener("click", function() { applySet(currentSetReference, currentPreferences, currentSet); }, false);
            }
            if(currentSet.number == currentSetNumber) {
                markCurrent(currentSetReference, currentPreferences, currentSet.number);
            }
            currentPreferences.menuItems[currentSet.number] = currentSetReference;

            let currentWidth = getTextWidth(currentSet.name, getCanvasFont(currentSetReference));
            if(maxClientWidth < currentWidth) {
                maxClientWidth = currentWidth;
            }
        }
        menuContent.style.minWidth = `${(maxClientWidth + 25)}px`;
        menuContent.style.display = "none";
    }
}
function markCurrent(selectedMenuItem, currentPreferences, currentSetNumber) {
    GM_setValue(currentPreferences.getCurrentSetName(), currentSetNumber);
    if(selectedMenuItem) {
        selectedMenuItem.style.color = '#0f0';
        if (currentPreferences.currentMenuItem && currentPreferences.currentMenuItem != selectedMenuItem) {
            currentPreferences.currentMenuItem.style.color = "#f5c137";
        }
        currentPreferences.currentMenuItem = selectedMenuItem;
    }
}
function addSetChangerListener(htmlElement, currentPreferences, setNumber) {
    htmlElement.addEventListener("click", function() { markCurrent(currentPreferences.menuItems[setNumber], currentPreferences, setNumber); });
}
function applySet(selectedMenuItem, currentPreferences, currentSet) {
    markCurrent(selectedMenuItem, currentPreferences, currentSet.number);
    const originalText = selectedMenuItem ? selectedMenuItem.innerHTML : "";
    if(selectedMenuItem) {
        selectedMenuItem.innerHTML += " " + getLoadGif();
    }
    const request = new XMLHttpRequest();
    request.open(currentSet.method, currentSet.url, true);
    request.onreadystatechange = async function () {
        if(request.readyState == 2) {
            request.abort();
            if(selectedMenuItem) {
                selectedMenuItem.innerHTML = originalText;
                if(isMobileDevice) {
                    selectedMenuItem.parentNode.parentNode.style.display = "none";
                }
            }
            if(typeof(currentPreferences.setChanged) == "function") {
                currentPreferences.setChanged(currentSet.number);
            }
            if(currentPreferences.refreshingPages) {
                let pages = currentPreferences.refreshingPages.split(';');
                for(const page of pages) {
                    if(location.href.indexOf(page) > -1) {
                        let handled = false;
                        if(currentPreferences.updatePanelHandler) {
                            handled = await currentPreferences.updatePanelHandler();
                        }
                        console.log(`handled: ${handled}`)
                        if(!handled) {
                            window.location.reload();
                        }
                    }
                }
            }
            if(currentPreferences.refreshingConditions && currentPreferences.refreshingConditions()) {
                window.location.reload();
            }
        }
    };
    if(currentSet.contentType) {
        request.setRequestHeader('Content-type', currentSet.contentType);
    }
    //console.log(currentSet.data);
    request.send(currentSet.data);
    return false;
}
function drowSkillChangers() {
    if(location.pathname=='/home.php' && !document.querySelector(`#increaseattackAmountInput`)) {
        const isNewPersonPage = document.querySelector("div#home_css_stats_wrap_div") ? true : false;
        let skillsCount = 0;
        let re = new RegExp(isNewPersonPage ? `>${LocalizedString.AvailablePoints}:\\s(\\d+)<` : `<b>${LocalizedString.AvailablePoints}:</b>\\s(\\d+)`);
        const skillsExec = re.exec(document.body.innerHTML);
        if(skillsExec) {
            skillsCount += parseInt(skillsExec[1]);
        }
        re = new RegExp(isNewPersonPage ? `>${LocalizedString.AvailableTalentPoints}:\\s(\\d+)<` : `<b>${LocalizedString.AvailableTalentPoints}:</b>\\s(\\d+)`);
        const perksSkillsExec = re.exec(document.body.innerHTML);
        if(perksSkillsExec) {
            skillsCount += parseInt(perksSkillsExec[1]);
        }
        //console.log(`skillsCount: ${skillsCount}`);
        if(skillsCount == 0) {
            return;
        }
        const skillValueContainers = [];
        if(isNewPersonPage) {
            const container = document.querySelector("div#home_css_stats_wrap_div");
            const inv_stat_dataDivs = container.querySelectorAll("div.inv_stat_data.home_stat_data.show_hint");
            for(const inv_stat_dataDiv of inv_stat_dataDivs) {
                const increaseButton = inv_stat_dataDiv.querySelector("div.home_button2.btn_hover2");
                if(!increaseButton) {
                    continue;
                }
                const skillValueContainer = inv_stat_dataDiv.querySelector("div.inv_stat_text.home_stat_text");
                skillValueContainers.push(skillValueContainer);
            }
        } else {
            const increaseRefs = document.querySelectorAll("a[href^='home.php?increase=']"); //home.php?increase=defence
            for(const increaseRef of increaseRefs) {
                const sklilIncreaseCell = getParent(increaseRef, "td");
                const skillValueContainer = sklilIncreaseCell.previousSibling;
                skillValueContainers.push(skillValueContainer);
            }
        }
        const skillNames = ["attack", "defence", "power", "knowledge"];
        let i = 0;
        for(const skillValueContainer of skillValueContainers) {
            const skillValue = Number((skillValueContainer.querySelector("b") || skillValueContainer).innerText);
            skillValueContainer.innerHTML = "";
            const skill = skillNames[i];
            const increaseAmountInput = addElement("input", skillValueContainer, { id: `increase${skill}AmountInput`, name: "increaseAmountInput", value: skillValue, type: "number", min: skillValue, max: skillValue + skillsCount, size: 4, onfocus: "this.select();", title: LocalizedString.IncreaseManyPointsTooltip.replace("${minValue}", skillValue + 1).replace("${maxValue}", skillValue + skillsCount) });
            increaseAmountInput.addEventListener("change", function() { const targetValue = Number(increaseAmountInput.value); if(targetValue > skillValue && targetValue <= skillValue + skillsCount) { changeSkill(increaseAmountInput, isNewPersonPage, skill, skillValue, targetValue); } });
            i++;
        }
    }
}
async function changeSkill(increaseAmountInput, isNewPersonPage, skill, currentValue, targetValue) {
    while(currentValue < targetValue) {
        const url = `/home.php?increase=${skill}` + (isNewPersonPage ? `&info=1&js_output=1&rand=${Math.random() * 1000000}` : "");
        const txt = await getRequestText(url, isNewPersonPage ? "text/html; charset=UTF-8" : "text/html; charset=windows-1251");
        currentValue++;
        if(isNewPersonPage) {
            if (txt.substring(0, 7) != 'HCSS_OK') {
                window.location = '/home.php?info';
                return;
            }
            const data = txt.split('@');
            const home_css_stats_wrap_div = document.getElementById('home_css_stats_wrap_div');
            if(data && data[1] && home_css_stats_wrap_div) {
                home_css_stats_wrap_div.innerHTML = data[1];
                if(data.length > 2 && document.getElementById('home_css_mana_count')) {
                    document.getElementById('home_css_mana_count').innerHTML = parseInt(data[2]);
                }
                if(typeof windowObject.hwm_hints_init === 'function') windowObject.hwm_hints_init();
            }
        } else {
            increaseAmountInput.value = currentValue;
        }
    }
    if(!isNewPersonPage) {
        location.reload();
    }
}
function getParent(element, parentType, number = 1) {
    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 getLoadGif() {
    return '<img border="0" align="absmiddle" height="11" src="data:image/gif;base64,' +
    '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' +
    'fySDhGYQdDWGQyUhADs=">';
}
function ensureGmMethods() {
    if(!this.GM_getValue) {
        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]; };
    }
    if(!this.GM_listValues) {
        this.GM_listValues = function() {
            const values = [];
            for(let key in localStorage) {
                values.push(localStorage[key]);
            }
            return values;
        }
    }
}
function getUserName() {
    let enterButton = document.querySelector("input[src$='" + LocalizedString.EnterJpg + "']") || document.querySelector("input[value$='" + LocalizedString.SignInTitle + "']");
    if(/login.php$/.test(location.href)) {
        enterButton = document.querySelector("input[value='" + LocalizedString.SignInTitle + "']");
    }
    let loginTextBox = document.querySelector("input[name='login']");
    if(enterButton && loginTextBox) {
        enterButton.addEventListener("click", function() { GM_setValue("UserName", loginTextBox.value + "_"); });
    } else {
        if(/home.php/.test(location.href)) {
            const playersInfos = document.querySelectorAll("a.pi");
            for(const playersInfo of playersInfos) {
                if(playersInfo.nextElementSibling && playersInfo.nextElementSibling.tagName == "A" && playersInfo.nextElementSibling.href.indexOf("castle.php?change_faction_dialog") > -1) {
                    GM_setValue("UserName", playersInfo.querySelector("b").innerText + "_");
                }
            }
        }
        userName = GM_getValue("UserName");
        if(userName) {
            userName = encodeURIComponent(userName);
        }
    }
}
function getFraction() {
    let currentFactionNumber;
    if(location.pathname == '/home.php') {
        // for new home page
        let currentFactionIconContainer = document.querySelector("div.home_css_pl_fract.show_hint");
        if(!currentFactionIconContainer) {
            currentFactionIconContainer = document.querySelector("a[href^='castle.php?change_faction_dialog']");
        }
        if(currentFactionIconContainer) {
            const currentFactionIconImg = currentFactionIconContainer.querySelector("img");
            currentFactionNumber = currentFactionIconImg.src.split("i/f/r")[1].split(".png")[0];
        }
    } else if(location.pathname=='/pl_info.php' && getUrlParamValue(location.href, "id") == PlayerId) {
        const fractionImage = document.querySelector("img[src*='i/f/r']");
        const regExp = new RegExp('\\/i\\/f\\/r(\\d+)\\.png');
        const regExpExec = regExp.exec(fractionImage.src);
        if(regExpExec) {
            currentFactionNumber = regExpExec[1];
        }
    } else if(location.pathname=='/castle.php') {
        const selectedFactionImg = document.querySelector("div.castle_faction_div_inside2 img");
        const selectedFactionImgName = selectedFactionImg.getAttribute("src");
        const selectedFactionNumber = selectedFactionImgName.split("kukla_png/kukla")[1].split(".")[0]; //dcdn.heroeswm.ru/i/kukla_png/kukla5.png

        const faction_listDiv = document.querySelector("div[id='faction_list']");
        if(faction_listDiv.getAttribute("style").includes("display:none;")) {
            currentFactionNumber = selectedFactionNumber;
        }
    }
    if(currentFactionNumber) {
        GM_setValue(`Fraction${PlayerId}`, currentFactionNumber);
    }
    Fraction = parseInt(GM_getValue(`Fraction${PlayerId}`));
}
function getUrlParamValue(url, paramName) { return (new URLSearchParams(url.split("?")[1])).get(paramName); }
function uchar(s) { switch (s[0]) {case "А": return "\u0410"; case "Б": return "\u0411"; case "В": return "\u0412"; case "Г": return "\u0413"; case "Д": return "\u0414"; case "Е": return "\u0415"; case "Ж": return "\u0416"; case "З": return "\u0417"; case "И": return "\u0418"; case "Й": return "\u0419"; case "К": return "\u041a"; case "Л": return "\u041b"; case "М": return "\u041c"; case "Н": return "\u041d"; case "О": return "\u041e"; case "П": return "\u041f"; case "Р": return "\u0420"; case "С": return "\u0421"; case "Т": return "\u0422"; case "У": return "\u0423"; case "Ф": return "\u0424"; case "Х": return "\u0425"; case "Ц": return "\u0426"; case "Ч": return "\u0427"; case "Ш": return "\u0428"; case "Щ": return "\u0429"; case "Ъ": return "\u042a"; case "Ы": return "\u042b"; case "Ь": return "\u042c"; case "Э": return "\u042d"; case "Ю": return "\u042e"; case "Я": return "\u042f"; case "а": return "\u0430"; case "б": return "\u0431"; case "в": return "\u0432"; case "г": return "\u0433"; case "д": return "\u0434"; case "е": return "\u0435"; case "ж": return "\u0436"; case "з": return "\u0437"; case "и": return "\u0438"; case "й": return "\u0439"; case "к": return "\u043a"; case "л": return "\u043b"; case "м": return "\u043c"; case "н": return "\u043d"; case "о": return "\u043e"; case "п": return "\u043f"; case "р": return "\u0440"; case "с": return "\u0441"; case "т": return "\u0442"; case "у": return "\u0443"; case "ф": return "\u0444"; case "х": return "\u0445"; case "ц": return "\u0446"; case "ч": return "\u0447"; case "ш": return "\u0448"; case "щ": return "\u0449"; case "ъ": return "\u044a"; case "ы": return "\u044b"; case "ь": return "\u044c"; case "э": return "\u044d"; case "ю": return "\u044e"; case "я": return "\u044f"; case "Ё": return "\u0401"; case "ё": return "\u0451"; default: return s[0]; } }
function ustring(s) {
    s = String(s);
    let result = "";
    for(let i = 0; i < s.length; i++) {
        result += uchar(s[i]);
    }
    return result;
}
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 getRequestText(url, overrideMimeType) {
    return new Promise((resolve, reject) => {
        GM.xmlHttpRequest({ method: "GET", url: url, overrideMimeType: overrideMimeType || "text/html; charset=windows-1251",
            onload: function(response) { resolve(response.responseText); },
            onerror: function(error) { reject(error); }
        });
    });
}
function postRequest(url, data) {
    return new Promise((resolve, reject) => {
        GM.xmlHttpRequest({ method: "POST", url: url, headers: { "Content-Type": "application/x-www-form-urlencoded" }, data: data,
            onload: function(response) { resolve(response); },
            onerror: function(error) { reject(error); }
        });
    });
}
function observe(target, handler, config = { childList: true, subtree: true }) {
    const ob = new MutationObserver(async function(mut, observer) {
        //console.log(`Mutation start`);
        observer.disconnect();
        if(handler.constructor.name === 'AsyncFunction') {
            await handler();
        } else {
            handler();
        }
        observer.observe(target, config);
    });
    ob.observe(target, config);
}
function gmGetBool(valueName, defaultValue = false) {
    const value = GM_getValue(valueName);
    if(value) {
        if(typeof(value) == "string") {
            return value == "true";
        }
        if(typeof(value) == "boolean") {
            return value;
        }
    }
    return defaultValue;
}