hwmSetsMaster

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

当前为 2023-05-15 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name           hwmSetsMaster
// @author         Tamozhnya1
// @namespace      Tamozhnya1
// @description    Меню наборов армии, навыков и оружия. Смена фракции.
// @version        7.1
// @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_deleteValue
// @grant          GM_getValue
// @grant          GM_listValues
// @grant          GM_setValue
// @license        MIT
// ==/UserScript==
    
const windowObject = window.wrappedJSObject || unsafeWindow;
const elementType = { div: "div", a: "a", li: "li", table: "table", center: "center", input: "input", td: "td" };
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("ВОЙТИ")
        },
        "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"
        }
    };
const LocalizedString = Strings[document.documentElement.lang || "ru"];
let userName;
let currentFaction;
const isMobileInterface = document.querySelector("div#btnMenuGlobal") ? true : false;
const isNewInterface = document.querySelector("#main_top_table") ? false : true;

ensureGmMethods();
CalculateUserNameAndFaction();

/************************************************************************************************************/
const weaponSetsPreferences = {
    menuTitle: LocalizedString.Weapon,
    setReferencePage: "inventory.php",
    sets: new Array(),
    menuItems: {},
    currentMenuItem: undefined,
    refreshingPages: "home.php;inventory.php;pl_info.php",
    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 lastSetNumber = GM_getValue(userName + "LastSetNumber", 0);
        for(let setNumber = 1; setNumber <= lastSetNumber; setNumber++) {
            const setName = GM_getValue(userName + "weaponSet" + setNumber);
            if(setName) {
                this.sets.push({ number: setNumber, name: setName, method: "GET", url: "inventory.php?all_on=" + setNumber, headers: null });
            }
        }
    },
    getCurrentSetName: function() { return userName + "currentWeaponSet"; },
    init: function() {
        if(/inventory.php/.test(location.href)) {
            let undressDiv = document.querySelector("div[id ='undress_all_div']");
            addSetChangerListener(undressDiv, this, 0);
          
            let setDivs = document.querySelectorAll("div[set_div_id]"); // Если setDivs.length = 0, то ничего не делаем - мы в заявке на бой
            if(setDivs.length > 0) {
                let lastSetNumber = 0;
                let i = 0;
                for(const setDiv of setDivs) {
                    let setNumber = setDiv.getAttribute("set_div_id");
                    if(setDiv.hasAttribute("onclick")) {
                        addSetChangerListener(setDiv, this, setNumber);
                        GM_setValue(userName + "weaponSet" + setNumber, setDiv.innerText);
                        lastSetNumber = ++i;
                    } else {
                        GM_deleteValue(userName + "weaponSet" + setNumber);
                    }
                }
                GM_setValue(userName + "LastSetNumber", lastSetNumber);
            }
        }
        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",
 
    initSetsApplyAction: function () {
        const setRefs = document.querySelectorAll("a[href^='skillwheel.php?setuserperk']");
        this.sets.length = 0;
        let i = 0;
        for(const setRef of setRefs) {
            this.sets.push({ number: i, name: setRef.innerHTML, method: "GET", url: setRef.href });
            addSetChangerListener(setRef, this, i);
            i++;
        }
    },
    getCurrentSetName: function() { return userName + currentFaction + "currentSkillSet"; }
};
/************************************************************************************************************/
const armySetsPreferences = {
    menuTitle: LocalizedString.Army,
    setReferencePage: "army.php",
    sets: new Array(),
    savedArmyInfos: new Array(),
    menuItems: {},
    currentMenuItem: undefined,
    savedSetIdsConst: "savedArmySetIds",
    savedSetConst: "savedArmySet",
    refreshingPages: "home.php;army.php;pl_info.php",
    setsTable: null,
 
    initSetsApplyAction: function () {
        this.sets.length = 0;
        let i = 0;
        for(const savedArmyInfo of this.savedArmyInfos) {
            this.sets.push(this.getSet(savedArmyInfo));
        }
    },
    getSet: function(savedArmyInfo) {
            let armySetTooltip = "";
            let postData = "";
            let j = 0;
            for(const armyUnitAmount of savedArmyInfo.army) {
                armySetTooltip += (armyUnitAmount == "" ? "0" : armyUnitAmount) + "+";
                postData = `countv${++j}=${(armyUnitAmount == "" ? "0" : armyUnitAmount)}${(postData == "" ? "" : "&") + postData}`;
            }
            return {
            number: parseInt(savedArmyInfo.setId),
            name: savedArmyInfo.name,
            title: armySetTooltip.substring(0, armySetTooltip.length - 1),
            method: "POST",
            url: "army_apply.php",
            data: postData,
            contentType: "application/x-www-form-urlencoded"
        }
    },
    getCurrentSetName: function() { return userName + currentFaction + "currentArmySet"; },
    init: function() {
        let savedSetIdsStr = GM_getValue(userName + currentFaction + this.savedSetIdsConst);
        let setIds = new Array();
        if(savedSetIdsStr) {
            setIds = savedSetIdsStr.split("|");
        }
        this.savedArmyInfos.length = 0;
        for(const setId of setIds) {
            if(setId == "") {
                continue;
            }
            let setStr = GM_getValue(userName + currentFaction + this.savedSetConst + setId);
            if(!setStr) {
                continue;
            }
            let savedSetParams = setStr.split("|");
            let savedArmyInfo = {
                setId: setId,
                name: savedSetParams[7],
                fraction: savedSetParams[8],
                army: new Array()
            };
            for(let j = 0; j < 7; j++) {
                savedArmyInfo.army[j] = savedSetParams[j];
            }
            this.savedArmyInfos.push(savedArmyInfo);
        }
        if(/\/army.php/.test(location.href)) {
            this.drawSetsTable();
        }
    },
    drawSetsTable: function () {
        let cellWidths = [100, 60, 60, 60, 60, 60, 60, 60, 10, 10];
        let hwm_for_zoom = document.getElementById("hwm_for_zoom");
        let container = document.body;
        if(!isMobileInterface) {
            container = addElement("center", hwm_for_zoom);
        }
        let tableStyle = "background-color: #959595; border: 1px solid #f5c137; table-layout: fixed;" + (isMobileInterface ? "margin: 0 0 0 50px;" : "");
        this.setsTable = addElement(elementType.table, container, { style: tableStyle });
        for(const cellWidth of cellWidths) {
            this.setsTable.innerHTML += `<col style="width: ${cellWidth}px;" />`;
        }
        this.drawTableHeader();
        for(const savedArmyInfo of this.savedArmyInfos) {
            this.drawSetRow(savedArmyInfo);
        }
        let saveButton = addElement(elementType.input, container, { type: "button", value: LocalizedString.Save, style: isMobileInterface ? "margin: 0 0 0 50px;" : "" });
        saveButton.addEventListener("click", this.saveSets);
        let addButton = addElement(elementType.input, container, { type: "button", value: LocalizedString.Add });
        addButton.addEventListener("click", this.addSet);
        let addCurrentButton = addElement(elementType.input, container, { type: "button", value: LocalizedString.AddCurrent });
        addCurrentButton.addEventListener("click", this.addCurrentSet);
    },
    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(elementType.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(elementType.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(elementType.td, tr, { style: cellStyle });
        addElement(elementType.td, tr, { style: cellStyle });
    },
    drawSetRow: function (savedArmyInfo, isNew) {
        isNew = isNew || false;
        let cellStyle = "border: 1px solid #f5c137; overflow: hidden;";
        if(!this.setsTable) {
            return;
        }
        let tr = addElement("tr", this.setsTable, { setId: savedArmyInfo.setId });
        let td = addElement(elementType.td, tr, { style: cellStyle });
        let input = addElement(elementType.input, td, { value: savedArmyInfo.name, onfocus: `this.select();`, style: "width: 97px;" }); //, style: "overflow: hidden;"
        for(let i = 0; i < savedArmyInfo.army.length; i++) {
            td = addElement(elementType.td, tr, { style: cellStyle });
            input = addElement(elementType.input, td, { value: savedArmyInfo.army[i], onfocus: `ChangeSlider(event, ${i + 1}, 0); this.select();`, type: "number", style: "min-width: 47px; width: 98%; text-align: right;" });
        }
        td = addElement(elementType.td, tr, { style: cellStyle });
        let delButton = addElement(elementType.input, td, { type: "button", value: "x", title: LocalizedString.Delete });
        delButton.addEventListener("click", this.deleteSet);
        
        td = addElement(elementType.td, tr, { style: cellStyle });
        if(!isNew) {
            let applyButton = addElement(elementType.input, td, { type : "button", value : "v", title : LocalizedString.Apply });
            applyButton.addEventListener("click", function() { armySetsPreferences.saveSets(); applySet(null, armySetsPreferences, armySetsPreferences.getSet(savedArmyInfo)); }, false);
        }
    },
    saveSets: function () {
        let table = armySetsPreferences.setsTable;
        let setIdsStr = "";
        for(let i = 1; i < table.rows.length; i++) {
            let setStr = "";
            let row = table.rows[i];
            let setId = row.getAttribute("setId");
            setIdsStr = setIdsStr + "|" + setId;
            for(let j = 1; j <= 7; j++) {
                setStr = setStr + "|" + row.cells[j].firstChild.value;
            }
            setStr = setStr + "|" + row.cells[0].firstChild.value + "|";
            setStr = setStr.substr(1);
            GM_setValue(userName + currentFaction + armySetsPreferences.savedSetConst + setId, setStr);
        }
        if(setIdsStr != "") {
            GM_setValue(userName + currentFaction + armySetsPreferences.savedSetIdsConst, setIdsStr.substr(1));
        } else {
            GM_deleteValue(userName + currentFaction + armySetsPreferences.savedSetIdsConst);
            GM_deleteValue(armySetsPreferences.getCurrentSetName());
        }
        let armySetIdRegExp = new RegExp(userName + currentFaction + armySetsPreferences.savedSetConst + '(\\d+)');
        let allStorageKeys = GM_listValues();
        let allStorageKeysCount = allStorageKeys.length;
        for(let i = allStorageKeysCount; i--; ) {
            let armySetId = armySetIdRegExp.exec(allStorageKeys[i]);
            if(armySetId && (setIdsStr == "" || !setIdsStr.match(armySetId[1])) ) {
                GM_deleteValue(allStorageKeys[i]);
            }
        }            
    },
    addSet: function () {
        armySetsPreferences.drawSetRow({
            setId : (new Date()).getTime(),
            name : "",
            army : ["", "", "", "", "", "", ""]
        }, true);
    },
    addCurrentSet: function () {
        let units = windowObject.obj;
        let savedArmyInfo = {
            setId : (new Date()).getTime(),
            name : "",
            army : [units[1]['nownumberd'], units[2]['nownumberd'], units[3]['nownumberd'], units[4]['nownumberd'], units[5]['nownumberd'], units[6]['nownumberd'], units[7]['nownumberd']]
        };
        armySetsPreferences.drawSetRow(savedArmyInfo, true);
    },
    deleteSet: function () {
        let table = this.parentNode.parentNode.parentNode;
        let row = this.parentNode.parentNode;
        table.removeChild(row);
    }
};
/************************************************************************************************************/
const factionsPreferences = {
    menuTitle: LocalizedString.Castle,
    setReferencePage: "castle.php",
    sets: new Array(),
    menuItems: {},
    currentMenuItem: undefined,
    availableCastleNames: "availableCastleNames",
    refreshingPages: "home.php;army.php;pl_info.php;castle.php;inventory.php;skillwheel.php",
    userCastleSign: undefined,
    userCastleSignName: "userCastleSign",
    refreshingConditions: function() {
        return false;
    },
    initSetsApplyAction: function() {
        let serializedCastlesInfo = GM_getValue(userName + this.availableCastleNames);
        if(serializedCastlesInfo) {
            let castles = serializedCastlesInfo.split("&");
            this.sets.length = 0;
            for(let castle of castles) {
                const castleParts = castle.split("=");
                const setInfo = { number: castleParts[1], name: castleParts[0], method: "GET" }; 
                if(this.userCastleSign) {
                    setInfo.url = `castle.php?change_clr_to=${castleParts[1]}&sign=${this.userCastleSign}`;
                }
                this.sets.push(setInfo);
            }
        }
    },
    getCurrentSetName: function() { return userName + "currentCastle"; },
    init: function () {
        this.initCastlesList();
        this.userCastleSign = GM_getValue(userName + this.userCastleSignName);
        this.findSetChangersAndAddListener();
    },
    initCastlesList: function () {
        if(!/castle.php/.test(location.href)) {
            return;
        }
        let castleNamesDivs = document.querySelectorAll("div.castle_faction_div_inside");
        let serializedCastlesInfo = "";
        for(let castleNamesDivIndex = 0; castleNamesDivIndex < castleNamesDivs.length; castleNamesDivIndex++) {
            let castleNameDiv = castleNamesDivs[castleNamesDivIndex];
            let castleName = castleNameDiv.getAttribute("hint");
            let castleSelectRef = castleNameDiv.firstChild.getAttribute("href");
            let castleNumber = castleSelectRef.split("=")[1];
            serializedCastlesInfo = serializedCastlesInfo + (serializedCastlesInfo == "" ? "" : "&") + castleName + "=" + castleNumber;
        }
        GM_setValue(userName + this.availableCastleNames, serializedCastlesInfo);
        let castle_yes_no_dialogDiv = document.querySelector("div.castle_yes_no_dialog");
        if(castle_yes_no_dialogDiv) {
            let changeCastleRef = castle_yes_no_dialogDiv.querySelector("a[href*='castle.php?change_clr_to']");
            if(changeCastleRef) {
                let userCastleSign = changeCastleRef.getAttribute("href").split("?")[1].split("&")[1].split("=")[1];
                GM_setValue(userName + this.userCastleSignName, userCastleSign);
            }
        }
    },
    findSetChangersAndAddListener: function() {
        let setRefs = document.querySelectorAll("a[href*='castle.php?change_clr_to']");
        for(let i = 0; i < setRefs.length; i++) {
            let changeCastleRef = setRefs[i];
            let setNumber = changeCastleRef.getAttribute("href").split("?")[1].split("&")[0].split("=")[1];
            addSetChangerListener(changeCastleRef, this, setNumber);
        }
    },
    setChanged: function(newSetNumber) {
        currentFaction = "r" + newSetNumber + "_";
        GM_setValue(userName + "currentFaction", currentFaction);
        main();
    }
};

/************************************************************************************************************/
const preferences = [weaponSetsPreferences, skillSetsPreferences, armySetsPreferences, factionsPreferences];

main();
function main() {
    //console.log([userName, currentFaction]);
    if(document.querySelector("canvas#heart") && userName && currentFaction) {
        createMenu();
        window.addEventListener("resize", function() { createMenu(true); });
    }
}
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 createMenu(isResize) {
    const menuAnchor = getMenuAnchorElement();
    if(!menuAnchor) {
        return;
    }
    const anchorRect = menuAnchor.getBoundingClientRect();
    //menuAnchor.addEventListener("resize", function() { console.log("menuAnchor resize: " + this.getBoundingClientRect()); }, false);
    //console.log(anchorRect);
    const borderWidth = isNewInterface ? 1 : 2;
    const menuItemHeight = anchorRect.height - borderWidth * 2;
    const menuItemLineHeight = menuItemHeight - borderWidth;
    const menuItemTop = anchorRect.top;
    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];
        if(currentPreferences.init) {
            currentPreferences.init();
        }
        currentPreferences.initSetsApplyAction();
        let mainMenuItem = document.getElementById(`SetsMenuItem${i}`);
        let menuContent = document.getElementById(`SetsMenuItem${i}Content`);
        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: `SetsMenuItem${i}`, style: menuHeaderStyle });
            
            addElement("a", mainMenuItem, { innerHTML: currentPreferences.menuTitle, href: currentPreferences.setReferencePage, style: `color: ${foreColor}; text-decoration: none;` });
            
            const menuContentStyle = `position: absolute; list-style-position: inside; color: ${foreColor}; padding: 2px 3px 2px 3px; white-space: nowrap; background: ${backgroundColor}; z-index: ${zIndex};`;
            menuContent = addElement("div", document.body, { id: `SetsMenuItem${i}Content`, style: menuContentStyle });
            
            let hideTimer;
            mainMenuItem.addEventListener("mouseenter", function() { clearTimeout(hideTimer); if(menuContent.style.display == "none") { setTimeout(function() { menuContent.style.display = "block"; }, 100); } }, false);
            mainMenuItem.addEventListener("mouseleave", function() { hideTimer = setTimeout(function() { menuContent.style.display = "none"; }, 100); }, false);
            menuContent.addEventListener("mouseenter", function() { clearTimeout(hideTimer); }, false);
            menuContent.addEventListener("mouseleave", function() { hideTimer = setTimeout(function() { menuContent.style.display = "none"; }, 100); }, false);
        }
        mainMenuItem.style.height = `${menuItemHeight}px`;
        mainMenuItem.style.lineHeight = `${menuItemLineHeight}px`;
        mainMenuItem.style.top = `${menuItemTop}px`;

        let mainMenuItemRect = mainMenuItem.getBoundingClientRect();
        currentMenuItemLeft -= mainMenuItemRect.width;
        mainMenuItem.style.left = `${currentMenuItemLeft}px`;
        
        menuContent.style.top = `${mainMenuItemRect.bottom + 1}px`;
        menuContent.style.left = `${currentMenuItemLeft}px`;

        if(isResize) {
            continue;
        }
        menuContent.style.display = "block"; // Перед заполнением покажем див для правильного определения его размеров (нужно, если он установлен в none)
        menuContent.innerHTML = '';
        let 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.width = `${(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); }, false);
}   
function applySet(selectedMenuItem, currentPreferences, currentSet) {
    markCurrent(selectedMenuItem, currentPreferences, currentSet.number);
    let originalText = selectedMenuItem ? selectedMenuItem.innerHTML : "";
    if(selectedMenuItem) { selectedMenuItem.innerHTML += " " + getLoadGif(); }
    let objXMLHttpReqSM = new XMLHttpRequest();
    objXMLHttpReqSM.open(currentSet.method, currentSet.url, true);
    objXMLHttpReqSM.onreadystatechange = function () {
        if(objXMLHttpReqSM.readyState == 2) {
            objXMLHttpReqSM.abort();
            if(selectedMenuItem) { selectedMenuItem.innerHTML = originalText; }
            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) {
                        console.log(page);
                        window.location.reload(); //window.location.href = window.location.href;
                    }
                }
            }
            if(currentPreferences.refreshingConditions && currentPreferences.refreshingConditions()) {
                window.location.reload(); // window.location.href = window.location.href;
            }
        }
    };
    if(currentSet.contentType) {
        objXMLHttpReqSM.setRequestHeader('Content-type', currentSet.contentType);
    }
    objXMLHttpReqSM.send(currentSet.data);
    return false;
}
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,' +
    'R0lGODlhEAAQAMQAAP///+7u7t3d3bu7u6qqqpmZmYiIiHd3d2ZmZlVVVURERDMzMyIiIhEREQAR' +
    'AAAAAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05F' +
    'VFNDQVBFMi4wAwEAAAAh+QQFBwAQACwAAAAAEAAQAAAFdyAkQgGJJOWoQgIjBM8jkKsoPEzgyMGs' +
    'CjPDw7ADpkQBxRDmSCRetpRA6Rj4kFBkgLC4IlUGhbNQIwXOYYWCXDufzYPDMaoKGBoKb886OjAK' +
    'dgZAAgQkfCwzAgsDBAUCgl8jAQkHEAVkAoA1AgczlyIDczUDA2UhACH5BAUHABAALAAAAAAPABAA' +
    'AAVjICSO0IGIATkqIiMKDaGKC8Q49jPMYsE0hQdrlABCGgvT45FKiRKQhWA0mPKGPAgBcTjsspBC' +
    'AoH4gl+FmXNEUEBVAYHToJAVZK/XWoQQDAgBZioHaX8igigFKYYQVlkCjiMhACH5BAUHABAALAAA' +
    'AAAQAA8AAAVgICSOUGGQqIiIChMESyo6CdQGdRqUENESI8FAdFgAFwqDISYwPB4CVSMnEhSej+Fo' +
    'gNhtHyfRQFmIol5owmEta/fcKITB6y4choMBmk7yGgSAEAJ8JAVDgQFmKUCCZnwhACH5BAUHABAA' +
    'LAAAAAAQABAAAAViICSOYkGe4hFAiSImAwotB+si6Co2QxvjAYHIgBAqDoWCK2Bq6A40iA4yYMgg' +
    'NZKwGFgVCAQZotFwwJIF4QnxaC9IsZNgLtAJDKbraJCGzPVSIgEDXVNXA0JdgH6ChoCKKCEAIfkE' +
    'BQcAEAAsAAAAABAADgAABUkgJI7QcZComIjPw6bs2kINLB5uW9Bo0gyQx8LkKgVHiccKVdyRlqjF' +
    'SAApOKOtR810StVeU9RAmLqOxi0qRG3LptikAVQEh4UAACH5BAUHABAALAAAAAAQABAAAAVxICSO' +
    '0DCQKBQQonGIh5AGB2sYkMHIqYAIN0EDRxoQZIaC6bAoMRSiwMAwCIwCggRkwRMJWKSAomBVCc5l' +
    'UiGRUBjO6FSBwWggwijBooDCdiFfIlBRAlYBZQ0PWRANaSkED1oQYHgjDA8nM3kPfCmejiEAIfkE' +
    'BQcAEAAsAAAAABAAEAAABWAgJI6QIJCoOIhFwabsSbiFAotGMEMKgZoB3cBUQIgURpFgmEI0EqjA' +
    'CYXwiYJBGAGBgGIDWsVicbiNEgSsGbKCIMCwA4IBCRgXt8bDACkvYQF6U1OADg8mDlaACQtwJCEA' +
    'IfkEBQcAEAAsAAABABAADwAABV4gJEKCOAwiMa4Q2qIDwq4wiriBmItCCREHUsIwCgh2q8MiyEKO' +
    'DK7ZbHCoqqSjWGKI1d2kRp+RAWGyHg+DQUEmKliGx4HBKECIMwG61AgssAQPKA19EAxRKz4QCVIh' +
    'ACH5BAUHABAALAAAAAAQABAAAAVjICSOUBCQqHhCgiAOKyqcLVvEZOC2geGiK5NpQBAZCilgAYFM' +
    'ogo/J0lgqEpHgoO2+GIMUL6p4vFojhQNg8rxWLgYBQJCASkwEKLC17hYFJtRIwwBfRAJDk4Obwsi' +
    'dEkrWkkhACH5BAUHABAALAAAAQAQAA8AAAVcICSOUGAGAqmKpjis6vmuqSrUxQyPhDEEtpUOgmgY' +
    'ETCCcrB4OBWwQsGHEhQatVFhB/mNAojFVsQgBhgKpSHRTRxEhGwhoRg0CCXYAkKHHPZCZRAKUERZ' +
    'MAYGMCEAIfkEBQcAEAAsAAABABAADwAABV0gJI4kFJToGAilwKLCST6PUcrB8A70844CXenwILRk' +
    'IoYyBRk4BQlHo3FIOQmvAEGBMpYSop/IgPBCFpCqIuEsIESHgkgoJxwQAjSzwb1DClwwgQhgAVVM' +
    'IgVyKCEAIfkECQcAEAAsAAAAABAAEAAABWQgJI5kSQ6NYK7Dw6xr8hCw+ELC85hCIAq3Am0U6JUK' +
    'jkHJNzIsFAqDqShQHRhY6bKqgvgGCZOSFDhAUiWCYQwJSxGHKqGAE/5EqIHBjOgyRQELCBB7EAQH' +
    '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 CalculateUserNameAndFaction() {
    let enterButton = document.querySelector("input[src$='" + LocalizedString.EnterJpg + "']") || document.querySelector("input[value$='" + LocalizedString.SignInTitle + "']");
    //console.log(enterButton);
    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 {
        userName = GM_getValue("UserName");
        if(/home.php/.test(location.href)) {
            let userNameFromHomePage;
            let 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) {
                    userNameFromHomePage = playersInfo.querySelector("b").innerText + "_";
                }
            }
            if(!userNameFromHomePage) {
                console.log("UserName on home page not found");
            }
            if(userName && userName != userNameFromHomePage) {
                console.log("Saved UserName not equal UserName on home page");
            }
            if(!userName) {
                userName = userNameFromHomePage;
                GM_setValue("UserName", userNameFromHomePage);
            }
        }
        if(!userName) {
            return;
        }
        userName = encodeURIComponent(userName);
        let currentFactionNumber = undefined;
        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) {
                let currentFactionIconImg = currentFactionIconContainer.querySelector("img");
                currentFactionNumber = currentFactionIconImg.src.split("i/f/r")[1].split(".png")[0];
            }
        } else if(location.pathname=='/pl_info.php') {
            let temp_nick = userName;
            let temp_regexp = new RegExp(temp_nick.slice(0, -1)+'.\{30,150\}\\/i\\/f\\/(r\\d+)\\.png');
            let frakPng = temp_regexp.exec( document.querySelector("body").innerHTML );
            if(frakPng) {
                currentFactionNumber = frakPng[1].substring(1);
            }
        } else if(location.pathname=='/castle.php') {
            let selectedFactionImg = document.querySelector("div.castle_faction_div_inside2 img");
            let selectedFactionImgName = selectedFactionImg.getAttribute("src");
            let selectedFactionNumber = selectedFactionImgName.split("kukla_png/kukla")[1].split(".")[0]; //dcdn.heroeswm.ru/i/kukla_png/kukla5.png
            
            let faction_listDiv = document.querySelector("div[id='faction_list']");
            if(faction_listDiv.getAttribute("style").includes("display:none;")) {
                currentFactionNumber = selectedFactionNumber;
            }
        }
        if(currentFactionNumber) {
            GM_setValue(userName + "currentCastle", currentFactionNumber);
            GM_setValue(userName + "currentFaction", "r" + currentFactionNumber + "_");
        }
        currentFaction = GM_getValue(userName + "currentFaction");
    }
}
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;
}