您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Меню наборов армии, навыков и оружия. Смена фракции.
当前为
// ==UserScript== // @name hwmSetsMaster // @author Tamozhnya1 // @namespace Tamozhnya1 // @description Меню наборов армии, навыков и оружия. Смена фракции. // @version 10.0 // @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_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM.xmlHttpRequest // @license MIT // ==/UserScript== const playerIdMatch = document.cookie.match(/pl_id=(\d+)/); if(!playerIdMatch) { return; } const PlayerId = playerIdMatch[1]; const windowObject = window.wrappedJSObject || unsafeWindow; const lang = document.documentElement.lang || (location.hostname == "www.lordswm.com" ? "en" : "ru"); const isEn = lang == "en"; 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("Применить"), EnterButtonValue: ustring("ВОЙТИ"), AvailablePoints: "Свободных очков", AvailableTalentPoints: "Свободных очков от навыка", IncreaseManyPointsTooltip: "Введите число от ${minValue} до ${maxValue}. Нажмите Tab." }, "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", EnterButtonValue: "ENTER", AvailablePoints: "Available points", AvailableTalentPoints: "Available talent points", IncreaseManyPointsTooltip: "Enter number from ${minValue} to ${maxValue}. Press Tab." } }; const LocalizedString = Strings[lang]; const isMobileInterface = document.querySelector("div#btnMenuGlobal") ? true : false; const isMobileDevice = mobileCheck(); // Там нет мышки const isNewInterface = document.querySelector("div#hwm_header") ? true : false; const isNewPersonPage = document.querySelector("div#hwm_no_zoom") ? true : false; 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]; }; } let Fraction; getFraction(); const homeArtsPanelSelector = doc => isNewPersonPage ? doc.querySelector("div#inv_doll_stats") : getParent(doc.querySelector("div.arts_info.shop_art_info"), "table"); const homeStatsPanelSelector = doc => isNewPersonPage ? doc.getElementById("home_css_stats_wrap_div") : getParent(doc.querySelector("img[src*='attr_attack']"), "table", 2); const homeArmyPanelSelector = doc => isNewPersonPage ? doc.querySelector("div.home_pers_army") : doc.querySelector("center > div > div.cre_creature72").parentNode; const playerInfoArtsPanelSelector = doc => getParent(doc.querySelector("div[class^='slot']"), "div"); const playerInfoStatsPanelSelector = doc => getParent(doc.querySelector("img[src*='attr_attack']"), "table"); const playerInfoArmyPanelSelector = doc => doc.querySelector("center > div > div.cre_creature72").parentNode; const playerInfoPerksPanelSelector = doc => getParent(doc.querySelector("a[href^='showperkinfo.php']"), "table", 2); const mapHuntButtonsPanelSelector = doc => doc.querySelector("div#neut_right_block div.map_buttons_container"); const mapHuntButtons2PanelSelector = doc => doc.querySelector("div#neut_right_block2 div.map_buttons_container"); const mapMercenaryTaskPanelSelector = doc => getParent(doc.querySelector("div#map_right_block_inside > table.wbwhite.rounded_table.map_table_margin center a[href='mercenary_guild.php']"), "center"); const inventoryStatsPanelSelector = doc => doc.querySelector("div.inventory_stats"); /************************************************************************************************************/ const weaponSetsPreferences = { menuTitle: LocalizedString.Weapon, menuImage: "https://dcdn3.heroeswm.ru/i/mobile_view_ny/icons/_panelInventory.png?v=3.23de65", setReferencePage: "inventory.php", sets: new Array(), menuItems: {}, currentMenuItem: undefined, refreshingPages: "home.php;inventory.php;pl_info.php;map.php", updatePanelHandler: async function() { if(location.pathname == '/home.php') { refreshUpdatePanels([homeArtsPanelSelector, homeStatsPanelSelector], hintProcessor); return true; } if(location.pathname == '/pl_info.php') { if(getUrlParamValue(location.href, "id") == PlayerId) { refreshUpdatePanels([playerInfoArtsPanelSelector, playerInfoStatsPanelSelector], hintProcessor); } return true; } if(location.pathname == '/map.php') { refreshUpdatePanels([mapHuntButtonsPanelSelector, mapHuntButtons2PanelSelector, mapMercenaryTaskPanelSelector], hintProcessor); return true; } return false; }, // refreshingConditions: function() { // if(location.pathname == '/map.php') { // return (document.querySelector("#neut_right_block") || document.querySelector("div#map_right_block_inside > table.wbwhite.rounded_table.map_table_margin center a[href='mercenary_guild.php']")) ? true : false; // } // return false; // }, initSetsApplyAction: function() { this.sets.length = 0; this.sets.push({ number: 0, name: LocalizedString.RemoveAll, method: "GET", url: "inventory.php?all_off=100" }); const weaponSets = JSON.parse(getPlayerValue("WeaponSets", "{}")); for(const setNumber in weaponSets) { this.sets.push({ number: setNumber, name: weaponSets[setNumber], method: "GET", url: `inventory.php?all_on=${setNumber}`, headers: null }); } }, getCurrentSetName: function() { return "WeaponSet"; }, onPageLoad: function() { if(/inventory.php/.test(location.href)) { const undressDiv = document.querySelector("div[id ='undress_all_div']"); addSetChangerListener(undressDiv, this, 0); const setDivs = document.querySelectorAll("div[set_div_id]"); // Если setDivs.length = 0, то ничего не делаем - мы в заявке на бой if(setDivs.length > 0) { const weaponSets = {}; for(const setDiv of setDivs) { const setNumber = setDiv.getAttribute("set_div_id"); if(setDiv.hasAttribute("onclick")) { weaponSets[setNumber] = setDiv.innerText; addSetChangerListener(setDiv, this, setNumber); } } setPlayerValue("WeaponSets", JSON.stringify(weaponSets)); } } 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, menuImage: "https://dcdn.heroeswm.ru/i/perks/2xleadership1.png", setReferencePage: "skillwheel.php", sets: new Array(), menuItems: {}, currentMenuItem: undefined, refreshingPages: "skillwheel.php;pl_info.php;home.php;inventory.php", updatePanelHandler: async function() { if(location.pathname == '/home.php') { refreshUpdatePanels(homeStatsPanelSelector, hintProcessor); getPerksToHomeCore(); return true; } if(location.pathname == '/pl_info.php') { if(getUrlParamValue(location.href, "id") == PlayerId) { refreshUpdatePanels([playerInfoStatsPanelSelector, playerInfoPerksPanelSelector], hintProcessor); } return true; } if(location.pathname == '/inventory.php') { refreshUpdatePanels(inventoryStatsPanelSelector, hintProcessor); return true; } return false; }, onPageLoad: function() { const setRefs = document.querySelectorAll("a[href^='skillwheel.php?setuserperk']"); // skillwheel.php?setuserperk=1&prace=4&buildid=5 // skillwheel.php?rand=1&setstats=1¶m0=20¶m1=8¶m2=0¶m3=2 const pageSets = {}; for(const setRef of setRefs) { pageSets[setRef.innerHTML] = getUrlParamValue(setRef.href, "buildid"); addSetChangerListener(setRef, this, parseInt(getUrlParamValue(setRef.href, "buildid"))); } setPlayerFractionValue("SkillSets", JSON.stringify(pageSets)); }, initSetsApplyAction: function () { const skillSets = JSON.parse(getPlayerFractionValue("SkillSets", "{}")); this.sets = Object.keys(skillSets).map(x => { return { number: parseInt(skillSets[x]), name: x, method: "GET", url: `/skillwheel.php?setuserperk=1&prace=${Fraction}&buildid=${skillSets[x]}` }; }); }, getCurrentSetName: function() { return getFractionKey("SkillSet"); } }; /************************************************************************************************************/ const armySetsPreferences = { menuTitle: LocalizedString.Army, menuImage: "https://dcdn.heroeswm.ru/i/castle_im/btn_recruit.png", setReferencePage: "army.php", sets: new Array(), menuItems: {}, currentMenuItem: undefined, refreshingPages: "home.php;army.php;pl_info.php", updatePanelHandler: async function() { if(location.pathname == '/home.php') { refreshUpdatePanels(homeArmyPanelSelector, hintProcessor); return true; } if(location.pathname == '/pl_info.php') { if(getUrlParamValue(location.href, "id") == PlayerId) { refreshUpdatePanels(playerInfoArmyPanelSelector, hintProcessor); } return true; } return false; }, setsTable: null, getCurrentSetName: function() { return getFractionKey("ArmySet"); }, initSetsApplyAction: function () { const armySetsData = JSON.parse(getPlayerFractionValue("ArmySets", "{}")); const armySets = Object.keys(armySetsData).map(x => { const data = armySetsData[x].split("|"); return { Id: x, Name: data[0], Army: data.slice(1).map(y => Number(y)) } }); this.sets = armySets.map(x => { return { number: parseInt(x.Id), name: x.Name, title: x.Army.join("+"), method: "POST", url: "/army_apply.php", data: x.Army.map((x, i) => `countv${i + 1}=${x}`).join("&"), contentType: "application/x-www-form-urlencoded" }; }); if(/\/army.php/.test(location.href)) { this.drawSetsTable(armySets); } }, drawSetsTable: function(armySets) { const isInit = this.setsTable ? false : true; let container; if(isInit) { const hwm_for_zoom = document.getElementById("hwm_for_zoom"); container = document.body; if(!isMobileInterface) { container = addElement("center", hwm_for_zoom); } const tableStyle = "background-color: #959595; border: 1px solid #f5c137; table-layout: fixed;" + (isMobileInterface ? "margin: 0 0 0 50px;" : ""); this.setsTable = addElement("table", container, { style: tableStyle }); } else { this.setsTable.innerHTML = ""; container = this.setsTable.parentNode; } const cellWidths = [100, 60, 60, 60, 60, 60, 60, 60, 10, 10]; for(const cellWidth of cellWidths) { this.setsTable.innerHTML += `<col style="width: ${cellWidth}px;" />`; } this.drawTableHeader(); for(const armySet of armySets) { this.drawSetRow(armySet); } if(isInit) { const saveButton = addElement("input", container, { type: "button", value: LocalizedString.Save, style: isMobileInterface ? "margin: 0 0 0 50px;" : "" }); saveButton.addEventListener("click", this.saveSets); const addCurrentButton = addElement("input", container, { type: "button", value: LocalizedString.AddCurrent }); addCurrentButton.addEventListener("click", function() { armySetsPreferences.drawSetRow(); }); } }, drawTableHeader: function () { if(!this.setsTable) { return; } let cellStyle = "border: 1px solid #f5c137; overflow: hidden;"; let units = windowObject.obj; let tr = addElement("tr", this.setsTable); addElement("td", tr, { innerHTML: LocalizedString.SetName.replace(/ /g, "<br>").replace(/-/g, "-<br>"), style: "font-weight: bold; font-size: 8pt; text-align: center; border: 1px solid #f5c137; overflow: hidden;" }); // ; overflow: hidden for(let i = 1; i <= 7; i++) { addElement("td", tr, { innerHTML: units[i]['name'].replace(/ /g, "<br>").replace(/-/g, "-<br>"), style: "font-weight: bold; font-size: 8pt; text-align: center; border: 1px solid #f5c137; overflow: hidden;", onClick: `ChangeSlider(event, ${i}, 0);` }); } addElement("td", tr, { style: cellStyle }); addElement("td", tr, { style: cellStyle }); }, drawSetRow: function(armySet) { const isNew = armySet ? false : true; const units = windowObject.obj; //console.log(`armySet: ${armySet}, units: ${units}`); //console.log(units.slice(1)); armySet = armySet || { Id: (new Date()).getTime(), Name: "", Army: [units[1], units[2], units[3], units[4], units[5], units[6], units[7]].map(x => x.nownumberd) }; let cellStyle = "border: 1px solid #f5c137; overflow: hidden;"; if(!this.setsTable) { return; } let tr = addElement("tr", this.setsTable, { setId: armySet.Id }); let td = addElement("td", tr, { style: cellStyle }); let input = addElement("input", td, { value: armySet.Name, onfocus: `this.select();`, style: "width: 97px;" }); //, style: "overflow: hidden;" for(let i = 0; i < armySet.Army.length; i++) { td = addElement("td", tr, { style: cellStyle }); input = addElement("input", td, { value: armySet.Army[i], onfocus: `ChangeSlider(event, ${i + 1}, 0); this.select();`, type: "number", style: "min-width: 47px; width: 98%; text-align: right;" }); } td = addElement("td", tr, { style: cellStyle }); let delButton = addElement("input", td, { type: "button", value: "x", title: LocalizedString.Delete }); delButton.addEventListener("click", this.deleteSet); td = addElement("td", tr, { style: cellStyle }); if(!isNew) { let applyButton = addElement("input", td, { type : "button", value : "v", title : LocalizedString.Apply }); applyButton.addEventListener("click", function() { armySetsPreferences.saveSets(); applySet(null, armySetsPreferences, { number: parseInt(armySet.Id), name: armySet.Name, title: armySet.Army.join("+"), method: "POST", url: "army_apply.php", data: armySet.Army.reduce((x, y, i) => `${x}&countv${i + 1}=${y}`, ""), contentType: "application/x-www-form-urlencoded" }); }); } }, saveSets: function () { const rows = Array.from(armySetsPreferences.setsTable.rows).slice(1); const armySetsData = rows.reduce((t, x) => ({ ...t, [x.getAttribute("setId")]: Array.from(x.cells).slice(0, 8).map(y => y.firstChild.value).join("|") }), {}); setPlayerFractionValue("ArmySets", JSON.stringify(armySetsData)); }, deleteSet: function () { const table = this.parentNode.parentNode.parentNode; const row = this.parentNode.parentNode; table.removeChild(row); } }; /************************************************************************************************************/ const fractionsPreferences = { menuTitle: LocalizedString.Castle, menuImage: "https://dcdn.heroeswm.ru/i/castle_im/btn_fraction.png", setReferencePage: "castle.php", sets: [], menuItems: {}, currentMenuItem: undefined, refreshingPages: "home.php;army.php;pl_info.php;castle.php;inventory.php;skillwheel.php", initSetsApplyAction: function() { const fractions = JSON.parse(getPlayerValue("Fractions", "{}")); this.sets = Object.keys(fractions).map(x => { return { number: fractions[x], name: x, method: "GET", url: `castle.php?change_clr_to=${fractions[x]}&sign=${getPlayerValue("Sign")}` }; }); }, getCurrentSetName: function() { return "Fraction"; }, onPageLoad: async function () { await this.initCastlesList(); this.findSetChangersAndAddListener(); }, initCastlesList: async function () { if(location.pathname == '/castle.php' || !getPlayerValue("Fractions")) { const doc = location.pathname == '/castle.php' ? document : await getRequest("/castle.php"); const fractions = Array.from(doc.querySelectorAll("div.castle_faction_div_inside")).reduce((t, x) => ({...t, [x.getAttribute("hint")]: getUrlParamValue(x.firstChild.href, "show_castle_f") }), {}); setPlayerValue("Fractions", JSON.stringify(fractions)); const changeCastleRef = doc.querySelector("div.castle_yes_no_dialog a[href*='castle.php?change_clr_to']"); if(changeCastleRef) { setPlayerValue("Sign", getUrlParamValue(changeCastleRef.href, "sign")); } } }, findSetChangersAndAddListener: function() { const setRefs = document.querySelectorAll("a[href*='castle.php?change_clr_to']"); for(const setRef of setRefs) { addSetChangerListener(setRef, this, getUrlParamValue(setRef.href, "change_clr_to")); } }, setChanged: function(newSetNumber) { Fraction = newSetNumber; setPlayerValue("Fraction", Fraction); createMenu(); } }; /************************************************************************************************************/ const preferences = [weaponSetsPreferences, skillSetsPreferences, armySetsPreferences, fractionsPreferences]; const isHeartOnPage = document.querySelector("canvas#heart") || document.querySelector("div#heart_js_mobile"); main(); function main() { if(isHeartOnPage && Fraction) { update(); for(const preference of preferences) { if(preference.onPageLoad) { preference.onPageLoad(); } } createMenu(); window.addEventListener("resize", function() { createMenu(true); }); drowSkillChangers(); if(location.pathname == '/home.php' && isNewPersonPage) { observe(document.querySelector("div#home_css_stats_wrap_div"), drowSkillChangers); } } } function update() { const fractionNumbers = [1, 101, 2, 102, 3, 103, 4, 104, 5, 105, 205, 6, 106, 7, 107, 8, 108, 9, 10]; for(const fractionNumber of fractionNumbers) { //deletePlayerFractionValue("SkillSets", fractionNumber); const skillSetsOld = getValue(`SkillSets${PlayerId}Fraction${fractionNumber}`); const skillSets = getPlayerFractionValue("SkillSets", undefined, fractionNumber); // if(fractionNumber == 8) { // console.log(`fractionNumber: ${fractionNumber}, skillSetsOld: ${skillSetsOld}, skillSets: ${skillSets}, CurrentSkillSet: ${getValue(`CurrentSkillSet${PlayerId}Fraction${fractionNumber}`)}`); // } if(skillSetsOld && !skillSets) { setPlayerFractionValue("SkillSets", skillSetsOld, fractionNumber); setPlayerFractionValue("SkillSet", getValue(`CurrentSkillSet${PlayerId}Fraction${fractionNumber}`), fractionNumber); } //deletePlayerFractionValue("ArmySets", fractionNumber); const armySetsOld = getValue(`ArmySets${PlayerId}Fraction${fractionNumber}`); const armySets = getPlayerFractionValue("ArmySets", undefined, fractionNumber); // if(fractionNumber == 8) { // console.log(`fractionNumber: ${fractionNumber}, armySetsOld: ${armySetsOld}, armySets: ${armySets}, ArmySet: ${getValue(`ArmySet${PlayerId}Fraction${fractionNumber}`)}`); // } if(armySetsOld && !armySets) { setPlayerFractionValue("ArmySets", armySetsOld, fractionNumber); setPlayerFractionValue("ArmySet", getValue(`ArmySet${PlayerId}Fraction${fractionNumber}`), fractionNumber); } // if(fractionNumber == 8) { // console.log(`ArmySet: ${getPlayerFractionValue("ArmySet", undefined, fractionNumber)}`); // } } } 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 getOrCreateAndResizeDropdown(baseElement, style) { const dropdownId = `${baseElement.id}Dropdown`; let dropdown = document.getElementById(dropdownId); if(!dropdown) { dropdown = addElement("div", document.body, { id: dropdownId, style: `position: absolute; z-index: ${baseElement.style.zIndex};` + (style || "") }); if(isMobileDevice) { baseElement.addEventListener("click", function() { dropdown.style.display = dropdown.style.display == "none" ? "block" : "none"; if(dropdown.style.display == "block") { const dropdowns = document.querySelectorAll("div[id$=Dropdown]"); for(const dropdown of dropdowns) { if(dropdown.id != dropdownId) { dropdown.style.display = "none"; } } } }); } else { let hideTimer; const dropdownTimeout = 100; baseElement.addEventListener("mouseenter", function() { clearTimeout(hideTimer); if(dropdown.style.display == "none") { setTimeout(function() { dropdown.style.display = "block"; }, dropdownTimeout); } }); baseElement.addEventListener("mouseleave", function() { hideTimer = setTimeout(function() { dropdown.style.display = "none"; }, dropdownTimeout); }); dropdown.addEventListener("mouseenter", function() { clearTimeout(hideTimer); }); dropdown.addEventListener("mouseleave", function() { hideTimer = setTimeout(function() { dropdown.style.display = "none"; }, dropdownTimeout); }); } } const baseElementRect = baseElement.getBoundingClientRect(); dropdown.style.top = `${baseElementRect.bottom + window.scrollY + 1}px`; dropdown.style.left = `${baseElementRect.left}px`; return dropdown; } function createMenu(isResize) { const menuPanel = document.querySelector("div#hwm_header") || document.querySelector("#main_top_table") || document.querySelector("body > table"); const homeRef = menuPanel.querySelector("a[href='home.php']"); const menuAnchor = isNewInterface ? homeRef.parentNode : getParent(homeRef, "td", 3); if(!menuAnchor) { return; } const anchorRect = menuAnchor.getBoundingClientRect(); //console.log(anchorRect); const borderWidth = isNewInterface ? 1 : 2; const menuItemHeight = anchorRect.height - borderWidth * 2; const menuItemLineHeight = menuItemHeight - borderWidth; const menuItemTop = anchorRect.top + window.scrollY; const foreColor = "#f5c137"; const backgroundColor = isNewInterface ? "linear-gradient(to top, #09203f 0%, #537895 100%)" : (document.querySelector("img[src*='i/top_ny']") ? "#003399" : "#6b6b69"); const zIndex = location.pathname == "/photo_pl_photos.php" ? "0" : "100"; let currentMenuItemLeft = anchorRect.left - borderWidth - 1; for(let i = preferences.length - 1; i >= 0; i--) { const currentPreferences = preferences[i]; const mainMenuItemId = `SetsMenuItem${i}`; let mainMenuItem = document.getElementById(mainMenuItemId); if(!mainMenuItem) { const menuHeaderStyle = `min-width: ${menuItemHeight}px; font-size: 9pt; position: absolute; border-radius: 5px; background: ${backgroundColor}; color: ${foreColor}; border: ${borderWidth}px solid ${foreColor}; padding: 0 3px 0 3px; font-weight: bold; text-align: center; z-index: ${zIndex};`; mainMenuItem = addElement("div", document.body, { id: mainMenuItemId, style: menuHeaderStyle }); let itemContent = currentPreferences.menuTitle; let itemTitle = ""; if(currentPreferences.menuImage && isNewInterface) { itemTitle = currentPreferences.menuTitle; itemContent = `<img src="${currentPreferences.menuImage}" alt="${itemTitle}" style="height: 90%; margin-top: 2px; border-radius: 50%;">`; } let itemChild; if(isMobileDevice) { itemChild = addElement("span", mainMenuItem, { innerHTML: itemContent, style: `color: ${foreColor}; text-decoration: none;` }); } else { itemChild = addElement("a", mainMenuItem, { innerHTML: itemContent, href: currentPreferences.setReferencePage, style: `color: ${foreColor}; text-decoration: none;` }); } if(itemTitle != "") { itemChild.title = itemTitle; } } mainMenuItem.style.height = `${menuItemHeight}px`; mainMenuItem.style.lineHeight = `${menuItemLineHeight}px`; mainMenuItem.style.top = `${menuItemTop}px`; const mainMenuItemRect = mainMenuItem.getBoundingClientRect(); currentMenuItemLeft -= mainMenuItemRect.width; mainMenuItem.style.left = `${currentMenuItemLeft}px`; const menuContent = getOrCreateAndResizeDropdown(mainMenuItem, `list-style-position: inside; color: ${foreColor}; padding: 2px 3px 2px 3px; white-space: nowrap; background: ${backgroundColor};`); if(isResize) { continue; } currentPreferences.initSetsApplyAction(); menuContent.style.display = "block"; // Перед заполнением покажем див для правильного определения его размеров (нужно, если он установлен в none) menuContent.innerHTML = ''; const currentSetNumber = getPlayerValue(currentPreferences.getCurrentSetName(), -1); let maxClientWidth = menuContent.clientWidth; for(const currentSet of currentPreferences.sets) { const dropDownMenuItem = addElement("li", menuContent, { type: "disc", style: "text-align: left;" }); const currentSetReference = addElement("b", dropDownMenuItem, { innerHTML: currentSet.name, title: currentSet.title || "", style: `color: ${foreColor}; 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.minWidth = `${(maxClientWidth + 25)}px`; menuContent.style.display = "none"; } } function markCurrent(selectedMenuItem, currentPreferences, currentSetNumber) { setPlayerValue(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); }); } function applySet(selectedMenuItem, currentPreferences, currentSet) { markCurrent(selectedMenuItem, currentPreferences, currentSet.number); const originalText = selectedMenuItem ? selectedMenuItem.innerHTML : ""; if(selectedMenuItem) { selectedMenuItem.innerHTML += " " + getWheelImage(); } const request = new XMLHttpRequest(); request.open(currentSet.method, currentSet.url, true); request.onreadystatechange = async function () { if(request.readyState == 2) { request.abort(); if(selectedMenuItem) { selectedMenuItem.innerHTML = originalText; if(isMobileDevice) { selectedMenuItem.parentNode.parentNode.style.display = "none"; } } 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) { let handled = false; if(currentPreferences.updatePanelHandler) { handled = await currentPreferences.updatePanelHandler(); } if(!handled) { window.location.reload(); } } } } if(currentPreferences.refreshingConditions && currentPreferences.refreshingConditions()) { window.location.reload(); } } }; if(currentSet.contentType) { request.setRequestHeader('Content-type', currentSet.contentType); } //console.log(currentSet.data); request.send(currentSet.data); return false; } function drowSkillChangers() { if(location.pathname=='/home.php' && !document.querySelector(`#increaseattackAmountInput`)) { let skillsCount = 0; let re = new RegExp(isNewPersonPage ? `>${LocalizedString.AvailablePoints}:\\s(\\d+)<` : `<b>${LocalizedString.AvailablePoints}:</b>\\s(\\d+)`); const skillsExec = re.exec(document.body.innerHTML); if(skillsExec) { skillsCount += parseInt(skillsExec[1]); } re = new RegExp(isNewPersonPage ? `>${LocalizedString.AvailableTalentPoints}:\\s(\\d+)<` : `<b>${LocalizedString.AvailableTalentPoints}:</b>\\s(\\d+)`); const perksSkillsExec = re.exec(document.body.innerHTML); if(perksSkillsExec) { skillsCount += parseInt(perksSkillsExec[1]); } //console.log(`skillsCount: ${skillsCount}`); if(skillsCount == 0) { return; } const skillValueContainers = []; if(isNewPersonPage) { const container = document.querySelector("div#home_css_stats_wrap_div"); const inv_stat_dataDivs = container.querySelectorAll("div.inv_stat_data.home_stat_data.show_hint"); for(const inv_stat_dataDiv of inv_stat_dataDivs) { const increaseButton = inv_stat_dataDiv.querySelector("div.home_button2.btn_hover2"); if(!increaseButton) { continue; } const skillValueContainer = inv_stat_dataDiv.querySelector("div.inv_stat_text.home_stat_text"); skillValueContainers.push(skillValueContainer); } } else { const increaseRefs = document.querySelectorAll("a[href^='home.php?increase=']"); //home.php?increase=defence for(const increaseRef of increaseRefs) { const sklilIncreaseCell = getParent(increaseRef, "td"); const skillValueContainer = sklilIncreaseCell.previousSibling; skillValueContainers.push(skillValueContainer); } } const skillNames = ["attack", "defence", "power", "knowledge"]; let i = 0; for(const skillValueContainer of skillValueContainers) { const skillValue = Number((skillValueContainer.querySelector("b") || skillValueContainer).innerText); skillValueContainer.innerHTML = ""; const skill = skillNames[i]; const increaseAmountInput = addElement("input", skillValueContainer, { id: `increase${skill}AmountInput`, name: "increaseAmountInput", value: skillValue, type: "number", min: skillValue, max: skillValue + skillsCount, size: 4, onfocus: "this.select();", title: LocalizedString.IncreaseManyPointsTooltip.replace("${minValue}", skillValue + 1).replace("${maxValue}", skillValue + skillsCount) }); increaseAmountInput.addEventListener("change", function() { const targetValue = Number(increaseAmountInput.value); if(targetValue > skillValue && targetValue <= skillValue + skillsCount) { changeSkill(increaseAmountInput, isNewPersonPage, skill, skillValue, targetValue); } }); i++; } } } async function changeSkill(increaseAmountInput, isNewPersonPage, skill, currentValue, targetValue) { while(currentValue < targetValue) { const url = `/home.php?increase=${skill}` + (isNewPersonPage ? `&info=1&js_output=1&rand=${Math.random() * 1000000}` : ""); const txt = await getRequestText(url, isNewPersonPage ? "text/html; charset=UTF-8" : "text/html; charset=windows-1251"); currentValue++; if(isNewPersonPage) { if (txt.substring(0, 7) != 'HCSS_OK') { window.location = '/home.php?info'; return; } const data = txt.split('@'); const home_css_stats_wrap_div = document.getElementById('home_css_stats_wrap_div'); if(data && data[1] && home_css_stats_wrap_div) { home_css_stats_wrap_div.innerHTML = data[1]; if(data.length > 2 && document.getElementById('home_css_mana_count')) { document.getElementById('home_css_mana_count').innerHTML = parseInt(data[2]); } if(typeof windowObject.hwm_hints_init === 'function') windowObject.hwm_hints_init(); } } else { increaseAmountInput.value = currentValue; } } if(!isNewPersonPage) { location.reload(); } } function hintProcessor(panel) { //Array.from(panel.querySelectorAll(".show_hint[hint]")).forEach(x => x.setAttribute("title", x.getAttribute("hint").replace(/<br>/ig, "\n").replace(/<br \/>/ig, "\n"))); } function getWheelImage() { return '<img border="0" align="absmiddle" height="11" src="https://dcdn.heroeswm.ru/css/loading.gif">'; } function getFraction() { let currentFractionNumber; if(location.pathname == '/home.php') { // for new home page let currentFractionIconContainer = document.querySelector("div.home_css_pl_fract.show_hint"); if(!currentFractionIconContainer) { currentFractionIconContainer = document.querySelector("a[href^='castle.php?change_faction_dialog']"); } if(currentFractionIconContainer) { const currentFractionIconImg = currentFractionIconContainer.querySelector("img"); currentFractionNumber = currentFractionIconImg.src.split("i/f/r")[1].split(".png")[0]; } } else if(location.pathname=='/pl_info.php' && getUrlParamValue(location.href, "id") == PlayerId) { const fractionImage = document.querySelector("img[src*='i/f/r']"); const regExp = new RegExp('\\/i\\/f\\/r(\\d+)\\.png'); const regExpExec = regExp.exec(fractionImage.src); if(regExpExec) { currentFractionNumber = regExpExec[1]; } } else if(location.pathname=='/castle.php') { const selectedFractionImg = document.querySelector("div.castle_faction_div_inside2 img"); const selectedFractionImgName = selectedFractionImg.getAttribute("src"); const selectedFractionNumber = selectedFractionImgName.split("kukla_png/kukla")[1].split(".")[0]; //dcdn.heroeswm.ru/i/kukla_png/kukla5.png const fractionsDiv = document.querySelector("div[id='faction_list']"); if(fractionsDiv.getAttribute("style").includes("display:none;")) { currentFractionNumber = selectedFractionNumber; } } if(currentFractionNumber) { setPlayerValue("Fraction", currentFractionNumber); } Fraction = parseInt(getPlayerValue("Fraction")); } // API function getUrlParamValue(url, paramName) { return (new URLSearchParams(url.split("?")[1])).get(paramName); } 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; } function getRequest(url, overrideMimeType) { return new Promise((resolve, reject) => { GM.xmlHttpRequest({ method: "GET", url: url, overrideMimeType: overrideMimeType || "text/html; charset=windows-1251", onload: function(response) { resolve((new DOMParser).parseFromString(response.responseText, "text/html")); }, onerror: function(error) { reject(error); } }); }); } function getRequestText(url, overrideMimeType) { return new Promise((resolve, reject) => { GM.xmlHttpRequest({ method: "GET", url: url, overrideMimeType: overrideMimeType || "text/html; charset=windows-1251", onload: function(response) { resolve(response.responseText); }, onerror: function(error) { reject(error); } }); }); } function postRequest(url, data) { return new Promise((resolve, reject) => { GM.xmlHttpRequest({ method: "POST", url: url, headers: { "Content-Type": "application/x-www-form-urlencoded" }, data: data, onload: function(response) { resolve(response); }, onerror: function(error) { reject(error); } }); }); } function observe(target, handler, config = { childList: true, subtree: true }) { const ob = new MutationObserver(async function(mut, observer) { //console.log(`Mutation start`); observer.disconnect(); if(handler.constructor.name === 'AsyncFunction') { await handler(); } else { handler(); } observer.observe(target, config); }); ob.observe(target, config); } function gmGetBool(valueName, defaultValue = false) { const value = getValue(valueName); if(value) { if(typeof(value) == "string") { return value == "true"; } if(typeof(value) == "boolean") { return value; } } return defaultValue; } function mobileCheck() { let check = false; (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera); return check; }; function getParent(element, parentType, number = 1) { if(!element) { return; } let result = element; let foundNumber = 0; while(result = result.parentNode) { if(result.nodeName.toLowerCase() == parentType.toLowerCase()) { foundNumber++; if(foundNumber == number) { return result; } } } } 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; } async function refreshUpdatePanels(panelSelectors, postProcessor) { panelSelectors = Array.isArray(panelSelectors) ? panelSelectors : [panelSelectors]; let freshDocument; for(const panelSelector of panelSelectors) { const updatePanel = panelSelector(document); if(updatePanel) { freshDocument = freshDocument || await getRequest(location.href); const freshUpdatePanel = panelSelector(freshDocument); if(!freshUpdatePanel) { console.log(updatePanel) continue; } if(postProcessor) { postProcessor(freshUpdatePanel); } updatePanel.innerHTML = freshUpdatePanel.innerHTML; } } if(typeof windowObject.hwm_hints_init === 'function') windowObject.hwm_hints_init(); } 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 getValue(`${key}${PlayerId}`, defaultValue); }; function setPlayerValue(key, value) { setValue(`${key}${PlayerId}`, value); }; function deletePlayerValue(key) { return deleteValue(`${key}${PlayerId}`); }; 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) { if(typeof(value) == "string") { return value == "true"; } if(typeof(value) == "boolean") { return value; } } return defaultValue; } function getPlayerFractionValue(key, defaultValue, fraction = Fraction) { return getPlayerValue(getFractionKey(key, fraction), defaultValue); }; function setPlayerFractionValue(key, value, fraction = Fraction) { setPlayerValue(getFractionKey(key, fraction), value); }; function deletePlayerFractionValue(key, fraction = Fraction) { return deletePlayerValue(getFractionKey(key, fraction)); }; function getFractionKey(key, fraction = Fraction) { return `${key}${fraction}f`; }