Фильтр заявок в таверне
当前为
// ==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;
}