hwmTavernFilter

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

当前为 2024-03-15 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴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.7
// @description     Фильтр заявок в таверне
// @include        *heroeswm.ru/tavern.php*
// @include        *lordswm.com/tavern.php*
// @grant           GM_getValue
// @grant           GM_setValue
// @grant           GM_addStyle
// @license        MIT
// ==/UserScript==

const playerIdMatch = document.cookie.match(/pl_id=(\d+)/);
if(!playerIdMatch) {
    return;
}
const PlayerId = playerIdMatch[1];
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 }
};
const isEn = document.documentElement.lang == "en";
const locations = {
    "Empire Capital": "Столица Империи",
    "East River": "Восточная Река",
    "Tiger Lake": "Тигриное Озеро",
    "Rogues' Wood": "Лес Разбойников",
    "Wolf Dale": "Долина Волков",
    "Peaceful Camp": "Мирный Лагерь",
    "Lizard Lowland": "Равнина Ящеров",
    "Green Wood": "Зеленый Лес",
    "Eagle Nest": "Орлиное Гнездо",
    "Portal Ruins": "Руины Портала",
    "Dragons' Caves": "Пещеры Драконов",
    "Shining Spring": "Сияющий Родник",
    "Sunny City": "Солнечный Город",
    "Magma Mines": "Магма Шахты",
    "Bear Mountain": "Медвежья Гора",
    "Fairy Trees": "Магический Лес",
    "Harbour City": "Портовый Город",
    "Mithril Coast": "Мифриловый Берег",
    "Great Wall": "Великая Стена",
    "Titans' Valley": "Равнина Титанов",
    "Fishing Village": "Рыбачье село",
    "Kingdom Castle": "Замок Королевства",
    "Ungovernable Steppe": "Непокорная Степь",
    "Crystal Garden": "Кристальный Сад",
    "East Island": "Восточный Остров",
    "The Wilderness": "Дикие земли",
    "Sublime Arbor": "Великое Древо"
};

main();
function main() {
    const tavernRef = document.querySelector("a[href='/tavern.php']");
    if(tavernRef) {
        tavernRef.parentNode.appendChild(document.createTextNode(" / "));
        const showOptionsRef = addElement("a", { href: "javascript:void(0)", innerHTML: isEn ? "Filter settings" : "Настрока фильтра" }, tavernRef.parentNode);
        showOptionsRef.addEventListener("click", showOptions);
    }
    applyFilter();
}
function showOptions() {
    if(showPupupPanel(GM_info.script.name)) {
       return;
    }
    const fieldsMap = [];
    fieldsMap.push([addElement("b", { innerText: "Выберите районы" })]);
    let i = 0;
    let fieldsRow = [];
    for(const area in areas) {
        i++;
        const areaName = isEn ? area : locations[area];
        const areaLabel = addElement("label", { for: `areaCheckbox${i}`, innerHTML: `${areaName} (${areas[area].tower}/${areas[area].resources})` });
        const areaCheckbox = addElement("input", { id: `areaCheckbox${i}`, type: "checkbox" });
        areaCheckbox.checked = getPlayerBool(`show${area}`, true);
        areaCheckbox.addEventListener("click", function() { setPlayerValue(`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 = addElement("b", { innerText: isEn ? "Partner level from" : "Уровень противника от" });
    const minLevelSelect = addElement("select");
    minLevelSelect.addEventListener("change", function() { setPlayerValue("minLevel", this.value); });

    const levelToCaption = addElement("b", { innerText: isEn ? "to" : "до" });
    const maxLevelSelect = addElement("select");
    maxLevelSelect.addEventListener("change", function() { setPlayerValue("maxLevel", this.value); });
    const opponentLevels = {};
    opponentLevels[-1] = isEn ? "Any" : "Любой";
    for(let i = 0; i <= 20; i++) {
        opponentLevels[i] = i.toString();
    }
    for(const opponentLevel in opponentLevels) {
        let option = addElement("option", { value: opponentLevel, innerHTML: opponentLevels[opponentLevel] }, minLevelSelect);
        if(opponentLevel == getPlayerValue("minLevel", "-1")) {
            option.setAttribute("selected", "selected");
        }
        option = addElement("option", { value: opponentLevel, innerHTML: opponentLevels[opponentLevel] }, maxLevelSelect);
        if(opponentLevel == getPlayerValue("maxLevel", "-1")) {
            option.setAttribute("selected", "selected");
        }
    }
    fieldsMap.push([levelFromCaption, minLevelSelect, levelToCaption, maxLevelSelect]);

    // Тип игры
    const gameTypeCaption = addElement("b", { innerText: isEn ? "Game type" : "Тип игры" });
    const gameTypeSelect = addElement("select");
    gameTypeSelect.addEventListener("change", function() { setPlayerValue("gameType", this.value); });
    const gameTypes = {"-1": isEn ? "Any" : "Любой", "1": isEn ? "One desk" : "Одна колода", "8": isEn ? "Infinite desk" : "Бесконечная колода"};
    for(const gameType in gameTypes) {
        const option = addElement("option", { value: gameType, innerHTML: gameTypes[gameType] }, gameTypeSelect);
        if(gameType == getPlayerValue("gameType", "-1")) {
            option.setAttribute("selected", "selected");
        }
    }
    fieldsMap.push([gameTypeCaption, gameTypeSelect]);

    // Время на ход
    const moveTimeFromCaption = addElement("b", { innerText: isEn ? "Turn time from" : "Время на ход от"});
    const minTimeSelect = addElement("select");
    minTimeSelect.addEventListener("change", function() { setPlayerValue("minTime", this.value); });

    const moveTimeToCaption = addElement("b", { innerText: isEn ? "to" : "до" });
    const maxTimeSelect = addElement("select");
    maxTimeSelect.addEventListener("change", function() { setPlayerValue("maxTime", this.value); });
    const moveTimes = {"-1": isEn ? "Any" : "Любая", "15": isEn ? "15 sec" :"15 сек.", "30": isEn ? "30 sec" : "30 сек.", "40": isEn ? "40 sec" : "40 сек."};
    for(const moveTime in moveTimes) {
        let option = addElement("option", { value: moveTime, innerHTML: moveTimes[moveTime] }, minTimeSelect);
        if(moveTime == getPlayerValue("minTime", "-1")) {
            option.setAttribute("selected", "selected");
        }
        option = addElement("option", { value: moveTime, innerHTML: moveTimes[moveTime] }, maxTimeSelect);
        if(moveTime == getPlayerValue("maxTime", "-1")) {
            option.setAttribute("selected", "selected");
        }
    }
    fieldsMap.push([moveTimeFromCaption, minTimeSelect, moveTimeToCaption, maxTimeSelect]);

    // Величина ставки
    const betValueFromCaption = addElement("b", { innerText: isEn ? "Bet value from" : "Величина ставки от" });
    const minBetSelect = addElement("select");
    minBetSelect.addEventListener("change", function() { setPlayerValue("minBet", this.value); });

    const betValueToCaption = addElement("b", { innerText: isEn ? "to" : "до" });
    const maxBetSelect = addElement("select");
    maxBetSelect.addEventListener("change", function() { setPlayerValue("maxBet", this.value); });
    const betValues = { "-1": isEn ? "Any" : "Любая", "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", { value: betValue, innerHTML: betValues[betValue] }, minBetSelect);
        if(betValue == getPlayerValue("minBet", "-1")) {
            option.setAttribute("selected", "selected");
        }
        option = addElement("option", { value: betValue, innerHTML: betValues[betValue] }, maxBetSelect);
        if(betValue == getPlayerValue("maxBet", "-1")) {
            option.setAttribute("selected", "selected");
        }
    }
    fieldsMap.push([betValueFromCaption, minBetSelect, betValueToCaption, maxBetSelect]);

    createPupupPanel(GM_info.script.name, getScriptReferenceHtml() + " " + getSendErrorMailReferenceHtml(), fieldsMap, onScriptOptionToggle);
}
function onScriptOptionToggle(isShown) {
    if(isShown) {
        setTimeout("clearTimeout(Timer)", 0); // Вкл/выкл таймер обновления страницы (взаимодействие со скриптом на странице)
    } else {
        setTimeout("Refresh()", 0);
        applyFilter();
    }
}
function applyFilter() {
    const options = { minBet: parseInt(getPlayerValue("minBet", "-1")), maxBet: parseInt(getPlayerValue("maxBet", "-1")), gameType: parseInt(getPlayerValue("gameType", -1)), minLevel: parseInt(getPlayerValue("minLevel", -1)), maxLevel: parseInt(getPlayerValue("maxLevel", -1)), minTime: parseInt(getPlayerValue("minTime", -1)), maxTime: parseInt(getPlayerValue("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 => {
        if(x.cells.length == 6) {
            if(!x.cells[0].hasAttribute("location")) {
                x.cells[0].setAttribute("location", x.cells[0].innerHTML);
            }
            currentTavern = x.cells[0].getAttribute("location");
            const locationName = isEn ? currentTavern : locations[currentTavern];
            x.cells[0].innerHTML = `${locationName}<br><span title="${isEn ? "Tower height" : "Высота башни"}">${areas[currentTavern].tower}</span> / <span title="${isEn ? "Resources" : "Ресурсов"}">${areas[currentTavern].resources}</span>`;
        }
        const bet = {
            tavern: 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 = getPlayerBool(`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;
    });
}
// API
function createPupupPanel(panelName, panelTitle, fieldsMap, panelToggleHandler) {
    const backgroundPopupPanel = addElement("div", { id: panelName, style: "position: fixed; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgb(0,0,0); background-color: rgba(0,0,0,0.4); z-index: 200;" }, document.body);
    backgroundPopupPanel.addEventListener("click", function(e) { if(e.target == this) { hidePupupPanel(panelName, panelToggleHandler); }});
    const contentDiv = addElement("div", { style: `top: 50%; transform: translateY(-50%); padding: 5px; display: flex; flex-wrap: wrap; position: relative; margin: auto; padding: 0; width: fit-content; background-image: linear-gradient(to right, #eea2a2 0%, #bbc1bf 19%, #57c6e1 42%, #b49fda 79%, #7ac5d8 100%); border: 1mm ridge rgb(211, 220, 50);` }, backgroundPopupPanel);
    if(panelTitle) {
        addElement("b", { innerHTML: panelTitle, style: "text-align: center; margin: auto; width: 90%; display: block;" }, contentDiv);
    }
    const divClose = addElement("span", { id: panelName + "close", title: isEn ? "Close" : "Закрыть", innerHTML: "&times;", style: "cursor: pointer; font-size: 20px; font-weight: bold;" }, contentDiv);
    divClose.addEventListener("click", function() { hidePupupPanel(panelName, panelToggleHandler); });

    addElement("div", { style: "flex-basis: 100%; height: 0;"}, contentDiv);

    if(fieldsMap) {
        let contentTable = addElement("table", { style: "flex-basis: 100%; width: min-content;"}, contentDiv);
        for(const rowData of fieldsMap) {
            if(rowData.length == 0) { // Спомощью передачи пустой стороки-массива, указываем, что надо начать новую таблицу после брейка
                addElement("div", { style: "flex-basis: 100%; height: 0;"}, contentDiv);
                contentTable = addElement("table", undefined, contentDiv);
                continue;
            }
            const row = addElement("tr", undefined, contentTable);
            for(const cellData of rowData) {
                const cell = addElement("td", undefined, row);
                if(cellData) {
                    if(typeof(cellData) == "string") {
                        cell.innerText = cellData;
                    } else {
                        cell.appendChild(cellData);
                    }
                }
            }
        }
    }
    if(panelToggleHandler) {
        panelToggleHandler(true);
    }
    return contentDiv;
}
function showPupupPanel(panelName, panelToggleHandler) {
    const backgroundPopupPanel = document.getElementById(panelName);
    if(backgroundPopupPanel) {
        backgroundPopupPanel.style.display = '';
        if(panelToggleHandler) {
            panelToggleHandler(true);
        }
        return true;
    }
    return false;
}
function hidePupupPanel(panelName, panelToggleHandler) {
    const backgroundPopupPanel = document.getElementById(panelName);
    backgroundPopupPanel.style.display = 'none';
    if(panelToggleHandler) {
        panelToggleHandler(false);
    }
}
function getValue(key, defaultValue) { return GM_getValue(key, defaultValue); };
function setValue(key, value) { GM_setValue(key, value); };
function deleteValue(key) { return GM_deleteValue(key); };
function getPlayerValue(key, defaultValue) { return GM_getValue(`${key}${PlayerId}`, defaultValue); };
function setPlayerValue(key, value) { GM_setValue(`${key}${PlayerId}`, value); };
function deletePlayerValue(key) { return GM_deleteValue(`${key}${PlayerId}`); };
function listValues() { return GM_listValues(); }
function getPlayerBool(valueName, defaultValue = false) { return getBool(valueName + PlayerId, defaultValue); }
function getBool(valueName, defaultValue = false) {
    const value = getValue(valueName);
    //console.log(`valueName: ${valueName}, value: ${value}, ${typeof(value)}`)
    if(value != undefined) {
        if(typeof(value) == "string") {
            return value == "true";
        }
        if(typeof(value) == "boolean") {
            return value;
        }
    }
    return defaultValue;
}
function GM_addStyle(css) { addElement("style", { type: "text/css", innerHTML: css }, document.head); }
function addElement(type, data = {}, parent = undefined, insertPosition = "beforeend") {
    const el = document.createElement(type);
    for(const key in data) {
        if(key == "innerText" || key == "innerHTML") {
            el[key] = data[key];
        } else {
            el.setAttribute(key, data[key]);
        }
    }
    if(parent) {
        parent.insertAdjacentElement(insertPosition, el);
    }
    return el;
}
function getScriptLastAuthor() {
    let authors = GM_info.script.author;
    if(!authors) {
        const authorsMatch = GM_info.scriptMetaStr.match(/@author(.+)\n/);
        authors = authorsMatch ? authorsMatch[1] : "";
    }
    const authorsArr = authors.split(",").map(x => x.trim()).filter(x => x);
    return authorsArr[authorsArr.length - 1];
}
function getDownloadUrl() {
    let result = GM_info.script.downloadURL;
    if(!result) {
        const downloadURLMatch = GM_info.scriptMetaStr.match(/@downloadURL(.+)\n/);
        result = downloadURLMatch ? downloadURLMatch[1] : "";
        result = result.trim();
    }
    return result;
}
function getScriptReferenceHtml() { return `<a href="${getDownloadUrl()}" title="${isEn ? "Check for update" : "Проверить обновление скрипта"}" target=_blanc>${GM_info.script.name} ${GM_info.script.version}</a>`; }
function getSendErrorMailReferenceHtml() { return `<a href="sms-create.php?mailto=${getScriptLastAuthor()}&subject=${isEn ? "Error in" : "Ошибка в"} ${GM_info.script.name} ${GM_info.script.version} (${GM_info.scriptHandler} ${GM_info.version})" target=_blanc>${isEn ? "Bug report" : "Сообщить об ошибке"}</a>`; }