hwmSetsMaster

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

当前为 2023-04-18 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴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        5.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
// @grant          GM_addStyle
// @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 isPhotosPage = location.href.match('photo_pl_photos');
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("Применить")
        },
        "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"
        }
    };
const LocalizedString = Strings[document.documentElement.lang];
var userName;
var currentFaction;

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)) {
            let bolds = document.querySelectorAll("b");
            for(const bold of bolds) {
                if(bold.innerText.includes(LocalizedString.Task)) {
                    return true;
                }
            }
            let neut_right_block = document.querySelector("div[id='neut_right_block']");
            if(neut_right_block) {
                return true;
            }
        }
        return false;
    },
    getSets: function() {
        this.sets[0] = { number: 0, name: LocalizedString.RemoveAll, method: "GET", url: "inventory.php?all_off=100" };
        let lastSetNumber = GM_getValue(userName + "LastSetNumber", 0);
        for (let setNumber = 1; setNumber <= lastSetNumber; setNumber++) {
            let setName = GM_getValue(userName + "weaponSet" + setNumber);
            if (setName) {
                this.sets[setNumber] = { 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",
 
    getSets: 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,
 
    getSets: 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 div = addElement(elementType.center, document.querySelector("body"));
        addElement("br", div);
        this.setsTable = addElement(elementType.table, div, { bgcolor: "#959595", bordercolor: "#f5c137", border: "1px" });
        this.drawTableHeader();
        for(const savedArmyInfo of this.savedArmyInfos) {
            this.drawSetRow(savedArmyInfo);
        }
        let saveButton = addElement(elementType.input, div, { type: "button", value: LocalizedString.Save });
        saveButton.addEventListener("click", this.saveSets);
        let addButton = addElement(elementType.input, div, { type: "button", value: LocalizedString.Add });
        addButton.addEventListener("click", this.addSet);
        let addCurrentButton = addElement(elementType.input, div, { type: "button", value: LocalizedString.AddCurrent });
        addCurrentButton.addEventListener("click", this.addCurrentSet);
    },
    drawTableHeader: function () {
        if(!this.setsTable) {
            return;
        }
        let units = windowObject.obj;
        let tr = addElement("tr", this.setsTable);
        addElement(elementType.td, tr, { innerHTML: LocalizedString.SetName.replace(/ /g, "<br>"), style: "font-weight: bold; font-size: 8pt; text-align: center;" });
        for(let i = 1; i <= 7; i++) {
            addElement(elementType.td, tr, { innerHTML: units[i]['name'].replace(/ /g, "<br>"), style: "font-weight: bold; font-size: 8pt; text-align: center;" });
        }
        addElement(elementType.td, tr);
        addElement(elementType.td, tr);
    },
    drawSetRow: function (savedArmyInfo, isNew) {
        isNew = isNew || false;
        if(!this.setsTable) {
            return;
        }
        let tr = addElement("tr", this.setsTable, { setId: savedArmyInfo.setId });
        let td = addElement(elementType.td, tr);
        let input = addElement(elementType.input, td, { value: savedArmyInfo.name, size: 22 });
        for(let i = 0; i < savedArmyInfo.army.length; i++) {
            td = addElement(elementType.td, tr);
            input = addElement(elementType.input, td, { value: savedArmyInfo.army[i], size: 5 });
        }
        td = addElement(elementType.td, tr);
        let delButton = addElement(elementType.input, td, { type: "button", value: "x", title: LocalizedString.Delete });
        delButton.addEventListener("click", this.deleteSet);
        
        td = addElement(elementType.td, tr);
        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;
    },

    getSets: function() {
        let serializedCastlesInfo = GM_getValue(userName + this.availableCastleNames);
        if(serializedCastlesInfo) {
            let castles = serializedCastlesInfo.split("&");
            for(let i = 0; i < castles.length; i++) {
                let castleName = castles[i].split("=")[0];
                let castleNumber = castles[i].split("=")[1];
                this.sets[i] = { number: castleNumber, name: castleName, method: "GET" };
                if(this.userCastleSign) {
                    this.sets[i].url = "castle.php?change_clr_to=" + castleNumber + "&sign=" + this.userCastleSign;
                }
            }
        }
    },
    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];
var timer;
const menuId = "menuSetsTable";
const isNewInterface = document.querySelector("div.mm_item") ? true : false;

main();

function main() {
    console.log([userName, currentFaction]);
    if(document.querySelector("body") && userName && currentFaction) {
        createMenu();
    }
}
function getMenuContainer() {
    if(isNewInterface) {
        return document.querySelector("div.sh_MenuPanel");
    } else {
        let logobEngChild = document.querySelector("img[src*='logob_eng']") || document.querySelector("img[src*='logob_0eng_']") || document.querySelector("img[src*='23f_05']");
        if(logobEngChild) {
            return logobEngChild.parentNode;
        }
    }
}
function getMenuHeaderStyle(menuStyle, offSet) {
    let topOffSet = isNewInterface ? -28 : 2;
    let menuHeaderStyle = {
        "font-size": "9pt",
        position: "absolute",
        "border-radius": "3px",
        margin: `${topOffSet}px 0px 0px ${offSet}px`,
        background: menuStyle.background,
        color: menuStyle.color,
        border: "1px solid " + menuStyle.borderColor,
        "font-weight": "bold",
        padding: "2px 6px 4px 5px",
        "z-index": menuStyle["z-index"]
    };
    if(isNewInterface) {
        menuHeaderStyle.height = "20px";
        menuHeaderStyle.width = "50px";
    }
    return menuHeaderStyle;
}
function getMenuContainerOffset() { return isNewInterface ? -193 : -80; }
function getMenuContentContainer(mainMenuItem, menuStyle) {
    if(isNewInterface) {
        return addElement(elementType.a, mainMenuItem, { innerHTML: "", href: "javascript:void(0)", style: `color: ${menuStyle.color}; text-decoration: none; vertical-align: middle;` });
    }
    return mainMenuItem;
}
function getMenuContentMouseEnterEventName() { return isNewInterface ? "mouseenter" : "mouseover"; }
function getMenuContentMouseLeaveEventName() { return isNewInterface ? "mouseleave" : "mouseout"; }
function getMenuStyle() {
    let menuStyle = { borderColor : "#f5c137", background : document.querySelector("img[src*='i/top_ny']") ? "#003399" : "#6b6b69", color : "#f5c137", "z-index": (isPhotosPage ? "0" : "100") };
    if(isNewInterface) {
        menuStyle.background = document.querySelector("img[src*='i/top_ny']") ? "#003399" : "#4f76a7";
    }
    return menuStyle;
}
function getMenuContentStyle(menuStyle) {
    if(isNewInterface) {
        return `position: relative; margin-top: 10px;background: ${menuStyle.background}; padding: 6px 3px 2px 3px; white-space: nowrap; z-index: ${menuStyle["z-index"]};`;
    }
    return "position: relative; padding: 6px 3px 2px 3px; white-space: nowrap;";
}
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() {
    let menuContainer = getMenuContainer();
    let menuStyle = getMenuStyle();
    let offSet = getMenuContainerOffset();
    let previousMainMenuItem = null;
    let i = 0;
    for(const currentPreferences of preferences) {
        if(currentPreferences.init) {
            currentPreferences.init();
        }
        if(!menuContainer) {
            continue;
        }
        currentPreferences.getSets();
        if(previousMainMenuItem) {
            offSet += previousMainMenuItem.clientWidth;
        }
        let menuHeaderStyle = getMenuHeaderStyle(menuStyle, offSet);
        let mainMenuItem = document.getElementById(menuId + i + "Header");
        let menuContent = document.getElementById(menuId + i);
        if(!mainMenuItem) {
            mainMenuItem = addElement(elementType.div, menuContainer, { id: menuId + i + "Header" }, menuHeaderStyle);
            addElement(elementType.a, mainMenuItem, { innerHTML: currentPreferences.menuTitle, href: currentPreferences.setReferencePage, style: `color: ${menuStyle.color}; text-decoration: none;` });
            let menuContentContainer = getMenuContentContainer(mainMenuItem, menuStyle);
            menuContent = addElement(elementType.div, menuContentContainer, { id: menuId + i, style: getMenuContentStyle(menuStyle) });
            mainMenuItem.addEventListener(getMenuContentMouseEnterEventName(), function() { timer = setTimeout(function () { menuContent.style.display = "block"; }, 100); }, false);
            mainMenuItem.addEventListener(getMenuContentMouseLeaveEventName(), function() { clearTimeout(timer); menuContent.style.display = "none"; }, false);
            menuContent.addEventListener(getMenuContentMouseEnterEventName(), function() { menuContent.style.display = "block"; }, false);
            menuContent.addEventListener(getMenuContentMouseLeaveEventName(), function() { clearTimeout(timer); menuContent.style.display = "none"; }, false);
        } else {
            menuContent.innerHTML = '';
        }
        previousMainMenuItem = mainMenuItem;

        menuContent.style.display = "block"; // Перед заполнением покажем див для правильного определения его размеров (нужно, если он установлен в none)
        let currentSetNumber = GM_getValue(currentPreferences.getCurrentSetName(), -1);
        let maxClientWidth = menuContent.clientWidth;
        for(const currentSet of currentPreferences.sets) {
            if(!currentSet) {
                continue;
            }
            let dropDownMenuItem = addElement(isPhotosPage ? elementType.div : elementType.li, menuContent, { type: "disc", style: "text-align: left;" });
            let currentSetReference = addElement("b", dropDownMenuItem, { innerHTML: currentSet.name, title: currentSet.title || "", style: `color: ${menuStyle.color}; 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";
        i++;
    }
}
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, style) {
    let el = createElement(type, data, style);
    if(parent) {
        parent.appendChild(el);
    }
    return el;
}
function createElement(type, data, style) {
    let el = document.createElement(type);
    if(data) {
        for(const key in data) {
            if(key == "innerHTML") {
                el.innerHTML = data[key];
            } else {
                el.setAttribute(key, data[key]);
            }
        }
    }
    if(style && el.id) {
        let styleStr = "";
        if(typeof(style) == "string") {
            styleStr = style;
        } else {
            for (let key in style) {
                styleStr += key + ": " + style[key] + "; ";
            }
        }
        GM_addStyle("#" + el.id + "{" + styleStr + "}");
    }
    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_addStyle) {
        this.GM_addStyle = function(key) {
            let style = document.createElement('style');
            style.type = "text/css";
            style.textContent = key;
            document.querySelector("head").appendChild(style);
        }
    }
    if(!this.GM_listValues) {
        this.GM_listValues = function() {
            let values = [];
            for (let i = 0; i < localStorage.length; i++) {
                values.push(localStorage.key(i));
            }
            return values;
        }
    }
}
function CalculateUserNameAndFaction() {
    let enterButton = document.querySelector("input[src$='" + LocalizedString.EnterJpg + "']");
    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(!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;
}