hwmTavernFilter

Фильтр заявок в таверне

当前为 2023-12-11 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name            hwmTavernFilter
// @author          Tamozhnya1
// @namespace       Tamozhnya1
// @version         2.5
// @encoding        utf-8
// @description     Фильтр заявок в таверне
// @description     В таверне появляется ссылка: "Настрока фильтра".
// @description     Там надо выбрать желаемые районы и остальные параметры, например ставка от 0 до 0.
// @description     Неотмеченные районы не отображаются.
// @description     Заявки, соответствующие фильтру, подсвечиваются зелёным
// @include        *heroeswm.ru/tavern.php*
// @include        *lordswm.com/tavern.php*
// @grant           GM_getValue
// @grant           GM_setValue
// @grant           GM_addStyle
// @license        MIT
// ==/UserScript==

const areas = {
    "Empire Capital": { tower: 50, resources: 150 },
    "Eagle Nest": { tower: 50, resources: 150 },
    "Harbour City": { tower: 50, resources: 150 },
    "East River": { tower: 75, resources: 200 },
    "Portal Ruins": { tower: 75, resources: 200 },
    "Mithril Coast": { tower: 75, resources: 200 },
    "The Wilderness": { tower: 75, resources: 200 },
    "Tiger Lake": { tower: 150, resources: 400 },
    "Dragons' Caves": { tower: 150, resources: 400 },
    "Great Wall": { tower: 150, resources: 400 },
    "Sublime Arbor": { tower: 150, resources: 400 },
    "Rogues' Wood": { tower: 100, resources: 300 },
    "Shining Spring": { tower: 100, resources: 300 },
    "Titans' Valley": { tower: 100, resources: 300 },
    "Wolf Dale": { tower: 100, resources: 300 },
    "Sunny City": { tower: 100, resources: 300 },
    "Fishing Village": { tower: 100, resources: 300 },
    "Peaceful Camp": { tower: 125, resources: 350 },
    "Magma Mines": { tower: 125, resources: 350 },
    "Kingdom Castle": { tower: 125, resources: 350 },
    "Lizard Lowland": { tower: 200, resources: 500 },
    "Bear Mountain": { tower: 200, resources: 500 },
    "Ungovernable Steppe": { tower: 200, resources: 500 },
    "Green Wood": { tower: 100, resources: 300 },
    "Fairy Trees": { tower: 100, resources: 300 },
    "Crystal Garden": { tower: 100, resources: 300 }
};

this.GM_getValue = this.GM_getValue || function(key, def) { return localStorage[key] || def; };
this.GM_setValue = this.GM_setValue || function(key, value) { return localStorage[key] = value; };
this.GM_deleteValue = this.GM_deleteValue || function(key) { return delete localStorage[key]; };
const isEn = document.documentElement.lang == "en";

main();
function main() {
    const tavernRef = document.querySelector("a[href='/tavern.php']");
    if(tavernRef) {
        tavernRef.parentNode.appendChild(document.createTextNode(" / "));
        const showOptionsRef = addElement("a", tavernRef.parentNode, { href: "javascript:void(0)", innerHTML: ustring("Настрока фильтра") });
        showOptionsRef.addEventListener("click", showOptions);
    }
    applyFilter();
}
function showOptions() {
    if(showPupupPanel(GM_info.script.name)) {
       return; 
    }
    const fieldsMap = [];
    fieldsMap.push([createElement("b", { innerText: "Выберите районы" })]);
    let i = 0;
    let fieldsRow = [];
    for(const area in areas) {
        i++;
        const areaLabel = createElement("label", { for: `areaCheckbox${i}`, innerText: `${area} (${areas[area].tower}/${areas[area].resources})` });
        const areaCheckbox = createElement("input", { id: `areaCheckbox${i}`, type: "checkbox" });
        areaCheckbox.checked = gmGetBool(`show${area}`);
        areaCheckbox.addEventListener("click", function() { GM_setValue(`show${area}`, this.checked); });
        
        fieldsRow.push(areaLabel);
        fieldsRow.push(areaCheckbox);
        if(i % 4 == 0) {
            fieldsMap.push(fieldsRow);
            fieldsRow = [];
        }
    }
    fieldsMap.push(fieldsRow);
    fieldsMap.push([]);
    
    // Уровень противника
    const levelFromCaption = createElement("b", { innerText: ustring("Уровень противника от:") });
    const minLevelSelect = createElement("select");
    minLevelSelect.addEventListener("change", function() { GM_setValue("minLevel", this.value); });
 
    const levelToCaption = createElement("b", { innerText: ustring("до:") });
    const maxLevelSelect = createElement("select");
    maxLevelSelect.addEventListener("change", function() { GM_setValue("maxLevel", this.value); });
    const opponentLevels = {};
    opponentLevels[-1] = ustring("Любой");
    for(let i = 0; i <= 20; i++) {
        opponentLevels[i] = i.toString();
    }
    for(const opponentLevel in opponentLevels) {
        let option = addElement("option", minLevelSelect, { value: opponentLevel, innerHTML: opponentLevels[opponentLevel] });
        if(opponentLevel == GM_getValue("minLevel", "-1")) {
            option.setAttribute("selected", "selected");
        }
        option = addElement("option", maxLevelSelect, { value: opponentLevel, innerHTML: opponentLevels[opponentLevel] });
        if(opponentLevel == GM_getValue("maxLevel", "-1")) {
            option.setAttribute("selected", "selected");
        }
    }
    fieldsMap.push([levelFromCaption, minLevelSelect, levelToCaption, maxLevelSelect]);
    
    // Тип игры
    const gameTypeCaption = createElement("b", { innerText: ustring("Тип игры:") });
    const gameTypeSelect = createElement("select");
    gameTypeSelect.addEventListener("change", function() { GM_setValue("gameType", this.value); });
    const gameTypes = {"-1": ustring("Любой"), "1": ustring("Игра с одной колодой"), "8": ustring("Игра с бесконечной колодой")};
    for(const gameType in gameTypes) {
        const option = addElement("option", gameTypeSelect, { value: gameType, innerHTML: gameTypes[gameType] });
        if(gameType == GM_getValue("gameType", "-1")) {
            option.setAttribute("selected", "selected");
        }
    }
    fieldsMap.push([gameTypeCaption, gameTypeSelect]);
    
    // Время на ход
    const moveTimeFromCaption = createElement("b", { innerText: ustring("Время на ход от:")});
    const minTimeSelect = createElement("select");
    minTimeSelect.addEventListener("change", function() { GM_setValue("minTime", this.value); });
 
    const moveTimeToCaption = createElement("b", { innerText: ustring("до:") });
    const maxTimeSelect = createElement("select");
    maxTimeSelect.addEventListener("change", function() { GM_setValue("maxTime", this.value); });
    const moveTimes = {"-1": "Любая", "15": "15 сек.", "30": "30 сек.", "40": "40 сек."};
    for(const moveTime in moveTimes) {
        let option = addElement("option", minTimeSelect, { value: moveTime, innerHTML: ustring(moveTimes[moveTime]) });
        if(moveTime == GM_getValue("minTime", "-1")) {
            option.setAttribute("selected", "selected");
        }
        option = addElement("option", maxTimeSelect, { value: moveTime, innerHTML: ustring(moveTimes[moveTime]) });
        if(moveTime == GM_getValue("maxTime", "-1")) {
            option.setAttribute("selected", "selected");
        }
    }
    fieldsMap.push([moveTimeFromCaption, minTimeSelect, moveTimeToCaption, maxTimeSelect]);
    
    // Величина ставки
    const betValueFromCaption = createElement("b", { innerText: ustring("Величина ставки от:") });
    const minBetSelect = createElement("select");
    minBetSelect.addEventListener("change", function() { GM_setValue("minBet", this.value); });
 
    const betValueToCaption = createElement("b", { innerText: ustring("до:") });
    const maxBetSelect = createElement("select");
    maxBetSelect.addEventListener("change", function() { GM_setValue("maxBet", this.value); });
    const betValues = { "-1": "Любая", "0": "0 золота", "40": "40 золота", "100": "100 золота", "300": "300 золота", "600": "600 золота", "1000": "1000 золота",
        "2000": "2000 золота", "3000": "3000 золота", "4000": "4000 золота", "5000": "5000 золота", "6000": "6000 золота", "7000": "7000 золота",
        "10000": "10000 золота", "11000": "11000 золота", "12000": "12000 золота", "20000": "20000 золота", "25000": "25000 золота", "30000": "30000 золота",
        "35000": "35000 золота", "40000": "40000 золота", "50000": "50000 золота" };
    for(const betValue in betValues) {
        let option = addElement("option", minBetSelect, { value: betValue, innerHTML: ustring(betValues[betValue]) });
        if(betValue == GM_getValue("minBet", "-1")) {
            option.setAttribute("selected", "selected");
        }
        option = addElement("option", maxBetSelect, { value: betValue, innerHTML: ustring(betValues[betValue]) });
        if(betValue == GM_getValue("maxBet", "-1")) {
            option.setAttribute("selected", "selected");
        }
    }
    fieldsMap.push([betValueFromCaption, minBetSelect, betValueToCaption, maxBetSelect]);
    
    createPupupPanel(GM_info.script.name, "Настройки фильтра", fieldsMap, onScriptOptionToggle);
}
function onScriptOptionToggle(isShown) {
    if(isShown) {
        setTimeout("clearTimeout(Timer)", 0); // Вкл/выкл таймер обновления страницы (взаимодействие со скриптом на странице)
    } else {
        setTimeout("Refresh()", 0);
        applyFilter();
    }
}
function applyFilter() {
    const options = { minBet: parseInt(GM_getValue("minBet", "-1")), maxBet: parseInt(GM_getValue("maxBet", "-1")), gameType: parseInt(GM_getValue("gameType", -1)), minLevel: parseInt(GM_getValue("minLevel", -1)), maxLevel: parseInt(GM_getValue("maxLevel", -1)), minTime: parseInt(GM_getValue("minTime", -1)), maxTime: parseInt(GM_getValue("maxTime", -1)) };
    //console.log(options);
    let currentTavern;
    const bets = Array.from(document.querySelectorAll("table[class='wb'] > tbody > tr")).filter(x => x.querySelector("img[src*='gold.png']")).map(x => {
        const bet = {
            tavern: (currentTavern = x.cells.length == 6 ? x.cells[0].innerHTML : currentTavern),
            level: parseInt(x.querySelector("a[href^='pl_info.php']").parentNode.querySelector("i").innerText.replace("(", "").replace(")", "")),
            gameType: x.querySelector("img[src*='1koloda']") ? 1 : 8,
            time: parseInt((new RegExp(`(\\d+) ${isEn ? "sec" : "сек"}.`)).exec(x.innerHTML)[1]),
            betValue: parseInt(x.querySelector("img[src*='gold.png']").parentNode.nextElementSibling.innerText.replace(",", "")),
            mayEnter: x.querySelector("a[href^='join_to_card_game.php']") ? true : false
        };
        bet.enabled = bet.mayEnter
            && (options.gameType == -1 || options.gameType == bet.gameType)
            && (options.minLevel == -1 || options.minLevel <= bet.level)
            && (options.maxLevel == -1 || options.maxLevel >= bet.level)
            && (options.minTime == -1 || options.minTime <= bet.time)
            && (options.maxTime == -1 || options.maxTime >= bet.time)
            && (options.minBet == -1 || options.minBet <= bet.betValue)
            && (options.maxBet == -1 || options.maxBet >= bet.betValue);
        x.style.display = gmGetBool(`show${bet.tavern}`, true) ? "" : "none";
        x.style.backgroundColor = bet.enabled ? "green" : "gray";
        if(bet.mayEnter) {
            x.querySelector("a[href^='join_to_card_game.php']").style.pointerEvents = bet.enabled ? "" : "none";
        }
        //console.log(bet);
        return bet;
    });
}
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);
    var result = "";
    for (var i = 0; i < s.length; i++)
        result += uchar(s[i]);
    return result;
}
function createPupupPanel(panelName, panelTitle, fieldsMap, panelToggleHandler) {
    let backgroundPopupPanel = addElement("div", document.body, { id: panelName + "1", style: "position: absolute; left: 0pt; width: 100%; background: none repeat scroll 0% 0% gray; opacity: 0.5; top: 0px; height: 100%; display: block; z-index: 200;" });
    backgroundPopupPanel.addEventListener("click", function() { hidePupupPanel(panelName, panelToggleHandler); });
 
    let popupPanel = addElement("div", document.body, { id: panelName + "2", style: `position: absolute; width: 650px; background: none repeat scroll 0% 0%; background-image: linear-gradient(to right, #eea2a2 0%, #bbc1bf 19%, #57c6e1 42%, #b49fda 79%, #7ac5d8 100%); left: ${((document.body.offsetWidth - 650) / 2)}px; top: 150px; display: block; z-index: 200; border: 4mm ridge rgba(211, 220, 50, .6);` });
    let contentDiv = addElement("div", popupPanel, { id: panelName + "3", style: "border: 1px solid #abc; padding: 5px; margin: 2px; display: flex; flex-wrap: wrap;" });
    
    if(panelTitle) {
        addElement("b", contentDiv, { innerText: panelTitle, style: "text-align: center; width: 84%; display: block;" });
    }
    let divClose = addElement("div", contentDiv, {id: panelName + "close", title: "Close", innerText: "x", style: "border: 1px solid #abc; width: 15px; height: 15px; text-align: center; cursor: pointer;" });
    divClose.addEventListener("click", function() { hidePupupPanel(panelName, panelToggleHandler); });
    
    addElement("div", contentDiv, { style: "flex-basis: 100%; height: 0;"});
    
    if(fieldsMap) {
        let contentTable = addElement("table", contentDiv);
        for(const rowData of fieldsMap) {
            if(rowData.length == 0) { // Спомощью передачи пустой стороки-массива, указываем, что надо начать новую таблицу после брейка
                addElement("div", contentDiv, { style: "flex-basis: 100%; height: 0;"});
                contentTable = addElement("table", contentDiv);
                continue;
            }
            const row = addElement("tr", contentTable);
            for(const cellData of rowData) {
                const cell = addElement("td", row);
                if(cellData) {
                    if(typeof(cellData) == "string") {
                        cell.innerText = cellData;
                    } else {
                        cell.appendChild(cellData);    
                    }
                }
            }
        }
    }
    if(panelToggleHandler) {
        panelToggleHandler(true);
    }
    return contentDiv;
}
function showPupupPanel(panelName, panelToggleHandler) {
    let backgroundPopupPanel = document.getElementById(panelName + "1");
    let popupPanel = document.getElementById(panelName + "2");
    if(backgroundPopupPanel) {
        if(panelToggleHandler) {
            panelToggleHandler(true);
        }
        backgroundPopupPanel.style.display = popupPanel.style.display = 'block';
        return true;
    }
    return false;
}
function hidePupupPanel(panelName, panelToggleHandler) {
    let backgroundPopupPanel = document.getElementById(panelName + "1");
    let popupPanel = document.getElementById(panelName + "2");
    backgroundPopupPanel.style.display = popupPanel.style.display = 'none';
    if(panelToggleHandler) {
        panelToggleHandler(false);
    }
}
function 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 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;
}