hwmTavernFilter

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name            hwmTavernFilter
// @author          Tamozhnya1
// @namespace       Tamozhnya1
// @version         2.3
// @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([]);
    
    // Уровень противника
    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}`) ? "" : "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) {
    const value = GM_getValue(valueName);
    if(value) {
        if(typeof(value) == "string") {
            return value == "true";
        }
        if(typeof(value) == "boolean") {
            return value;
        }
    }
    return false;
}