您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Добавляет в инфу персов и на домашнюю: ХП армии, очки и загрузку навыков, баланс рулетки и таверны, сумму умений, перекач, день рождения персонажа. Спойлеры. Статистика клана.
当前为
// ==UserScript== // @name hwmAdvancedPlayerInfo // @author alex_kocharin 2008-2012, Demin 2013-2015, Tamozhnya1 2024 // @namespace Tamozhnya1 // @version 19.2 // @description Добавляет в инфу персов и на домашнюю: ХП армии, очки и загрузку навыков, баланс рулетки и таверны, сумму умений, перекач, день рождения персонажа. Спойлеры. Статистика клана. // @include /^https{0,1}:\/\/(www|my)\.(heroeswm|lordswm)\.(ru|com)\/(home|pl_info|clan_info)\.php/ // @grant GM_deleteValue // @grant GM_getValue // @grant GM_setValue // @grant GM.xmlHttpRequest // @require https://update.greasyfork.org/scripts/490927/1360667/Tamozhnya1Lib.js // @license MIT // ==/UserScript== // Включить/выключить загрузку навыков на домашней странице можно щелчком по надписи "Навыки". День рождения загружается щелчком по надписи. Стоимость боя показывается скриптом hwmOptimalRepairAtMarket. Туда же перенесены расчет ОА и крафта. // Оригинальный скрипт https://userscripts-mirror.org/scripts/show/178809 (скрипт демина с greasyfork почему-то удален, как и таймеры) if(!PlayerId) { return; } const unitsHealth = { peasant: [1, 4], conscript: [1, 6], archer: [1, 7], marksman: [1, 10], footman: [1, 16], squire: [1, 26], griffon: [1, 30], impergriffin: [1, 35], priest: [1, 54], inquisitor: [1, 80], cavalier: [1, 90], paladin: [1, 100], angel: [1, 180], archangel: [1, 220], brute: [101, 8], crossman: [101, 8], vindicator: [101, 23], battlegriffon: [101, 52], zealot: [101, 80], champion: [101, 100], seraph2: [101, 220], skeleton: [2, 4], skeletonarcher: [2, 4], zombie: [2, 17], plaguezombie: [2, 17], ghost: [2, 8], spectre: [2, 19], vampire: [2, 30], vampirelord: [2, 35], lich: [2, 50], archlich: [2, 55], wight: [2, 95], wraith: [2, 100], bonedragon: [2, 150], spectraldragon: [2, 160], sceletonwar: [102, 5], rotzombie: [102, 23], poltergeist: [102, 20], vampireprince: [102, 40], masterlich: [102, 55], banshee: [102, 110], ghostdragon: [102, 150], gremlin: [3, 5], mastergremlin: [3, 6], stone_gargoyle: [3, 15], obsgargoyle: [3, 20], iron_golem: [3, 18], steelgolem: [3, 24], mage: [3, 18], archmage: [3, 30], djinn: [3, 40], djinn_sultan: [3, 45], rakshasa_rani: [3, 120], rakshasa_raja: [3, 140], colossus: [3, 175], titan: [3, 190], saboteurgremlin: [103, 6], elgargoly: [103, 16], magneticgolem: [103, 28], battlemage: [103, 29], djinn_vizier: [103, 50], rakshasa_kshatra: [103, 135], stormtitan: [103, 190], pixel: [4, 5], sprite: [4, 6], dancer: [4, 12], wardancer: [4, 12], elf: [4, 10], masterhunter: [4, 14], druid: [4, 34], druideld: [4, 38], unicorn: [4, 57], silverunicorn: [4, 77], treant: [4, 175], ancienent: [4, 181], greendragon: [4, 200], emeralddragon: [4, 200], dryad: [104, 6], wdancer: [104, 14], arcaneelf: [104, 12], ddhigh: [104, 34], pristineunicorn: [104, 80], savageent: [104, 175], crystaldragon: [104, 200], goblin: [5, 3], hobgoblin: [5, 4], wolfrider: [5, 10], wolfraider: [5, 12], orc: [5, 12], orcchief: [5, 18], ogre: [5, 50], ogremagi: [5, 65], rocbird: [5, 55], thunderbird: [5, 65], cyclop: [5, 85], cyclopking: [5, 95], behemoth: [5, 210], ancientbehemoth: [5, 250], goblinarcher: [105, 3], boarrider: [105, 14], orcrubak: [105, 20], ogrebrutal: [105, 70], firebird: [105, 65], cyclopod: [105, 100], dbehemoth: [105, 280], goblinmag: [205, 3], orcshaman: [205, 13], darkbird: [205, 60], hyenarider: [205, 13], ogreshaman: [205, 55], shamancyclop: [205, 105], cursedbehemoth: [205, 250], scout: [6, 10], assassin: [6, 14], stalker: [6, 15], maiden: [6, 16], fury: [6, 16], bloodsister: [6, 24], minotaur: [6, 31], minotaurguard: [6, 35], taskmaster: [6, 40], darkrider: [6, 40], grimrider: [6, 50], briskrider: [6, 50], hydra: [6, 80], deephydra: [6, 125], foulhydra: [6, 125], shadow_witch: [6, 80], matriarch: [6, 90], mistress: [6, 100], shadowdragon: [6, 200], blackdragon: [6, 240], reddragon: [6, 235], imp: [7, 4], familiar: [7, 6], horneddemon: [7, 13], hornedoverseer: [7, 13], hellhound: [7, 15], cerberus: [7, 15], succubus: [7, 20], succubusmis: [7, 30], hellcharger: [7, 50], nightmare: [7, 66], pitfiend: [7, 110], pitlord: [7, 120], devil: [7, 166], archdevil: [7, 199], vermin: [107, 6], jdemon: [107, 13], hotdog: [107, 15], seducer: [107, 26], hellkon: [107, 66], pity: [107, 140], archdemon: [107, 211], defender: [8, 7], shieldguard: [8, 12], spearwielder: [8, 10], skirmesher: [8, 12], bearrider: [8, 25], blackbearrider: [8, 30], brawler: [8, 20], berserker: [8, 25], runepriest: [8, 60], runepatriarch: [8, 70], thane: [8, 100], thunderlord: [8, 120], firedragon: [8, 230], magmadragon: [8, 280], mountaingr: [108, 12], harpooner: [108, 10], whitebearrider: [108, 30], battlerager: [108, 30], runekeeper: [108, 65], flamelord: [108, 120], lavadragon: [108, 275], goblinus: [9, 3], trapper: [9, 4], fcentaur: [9, 6], ncentaur: [9, 9], warrior: [9, 12], mauler: [9, 12], shamaness: [9, 30], sdaughter: [9, 35], slayer: [9, 34], executioner: [9, 40], wyvern: [9, 90], foulwyvern: [9, 105], cyclopus: [9, 220], untamedcyc: [9, 225], goblinshaman: [109, 5], mcentaur: [109, 10], warmong: [109, 20], eadaughter: [109, 35], chieftain: [109, 48], poukai: [109, 120], bloodeyecyc: [109, 235], scorp: [10, 4], scorpup: [10, 5], duneraider: [10, 12], duneraiderup: [10, 12], shakal: [10, 24], shakalup: [10, 30], dromad: [10, 40], dromadup: [10, 45], priestmoon: [10, 50], priestsun: [10, 55], slon: [10, 100], slonup: [10, 110], anubis: [10, 160], anubisup: [10, 200] }; const perkBranchCosts = { 1: { knight_mark: 5, attack: 9, defense: 8, luck: 10, leadership: 7, dark: 8, light: 7 }, 101: { benediction: 7, defense: 10, leadership: 10, enlightenment: 8, light: 6, summon: 10, sorcery: 7 }, 2: { necr_soul: 5, defense: 11, enlightenment: 9, dark: 7, summon: 8, sorcery: 8 }, 102: { powerraise: 6, attack: 9, luck: 10, enlightenment: 8, summon: 6, sorcery: 7 }, 3: { magic_mirror: 7, enlightenment: 9, light: 10, summon: 8, destructive: 10, sorcery: 7 }, 103: { nomagicdamage: 7, attack: 8, luck: 10, leadership: 9, enlightenment: 8, destructive: 9, sorcery: 8 }, 4: { elf_shot: 7, attack: 10, defense: 9, luck: 7, leadership: 10, enlightenment: 10, light: 7, summon: 9 }, 104: { zakarrow: 4, attack: 9, defense: 8, luck: 10, leadership: 8, enlightenment: 12 }, 5: { barb_skill: 7, attack: 7, defense: 9, luck: 9, leadership: 10 }, 105: { save_rage: 6, attack: 7, defense: 8, luck: 7, leadership: 9 }, 205: { dark_blood: 5, defense: 9, luck: 10, leadership: 10, enlightenment: 8, dark: 6, sorcery: 7 }, 6: { dark_power: 7, attack: 8, luck: 9, leadership: 10, enlightenment: 10, dark: 8, destructive: 9, sorcery: 7 }, 106: { cre_master: 5, attack: 8, defense: 11, leadership: 8, luck: 10, enlightenment: 8, dark: 8 }, 7: { hellfire: 6, attack: 7, defense: 9, luck: 10, dark: 8, destructive: 10, sorcery: 8 }, 107: { consumecorpse: 5, defense: 9, leadership: 9, enlightenment: 9, dark: 6, sorcery: 7 }, 8: { runeadv: 7, defense: 9, destructive: 11, light: 7, leadership: 9, luck: 10 }, 108: { firelord: 5, attack: 7, defense: 10, leadership: 8, luck: 8, destructive: 6, }, 9: { memoryblood: 6, attack: 7, enlightenment: 9, leadership: 9, luck: 10, defense: 9 }, 10: { dayandnight: 7, attack: 8, defense: 10, leadership: 10, light: 6, dark: 6, sorcery: 9, enlightenment: 9 } }; addStyle(` .bar_wrap { width: 120px; /*margin: 3px 0 3px 9px;*/ border: 1px solid #1C1C1C; background-color: #8C7526; box-shadow: 0 0 1px #666, inset 0 1px 1px #222; background-image: linear-gradient(#65541B, #8C7526 50%, #65541B); display: inline-block; } .bar { height: 5px; background-color: #f9e37e; border-right: 1px solid #282828; box-shadow: inset 0 0 1px #ddd; background-image: linear-gradient(#e7ae6b, #be8d55 50%, #a57b4b 51%, #ae804c); transition: all 1s ease; max-width: 150px; } .bar:hover { animation: animate-stripes 3s linear infinite; } @keyframes animate-stripes { 0% {background-position: 0 0;} 100% {background-position: 0 22px;} } .htooltip, .htooltip: visited, .tooltip: active { color: #0077AA; text-decoration: none; } .htooltip:hover { color: #0099CC; } .htooltip > span { background-color: rgba(0,0,0, 0.8); border-radius: 5px 5px 0px 0px; box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.5); color: #fff; margin-left: -1px; margin-top: -24px; opacity: 0; padding: 2px 5px; position: absolute; text-decoration: none; visibility: hidden; z-index: 10; transition: opacity 0.4s ease-in-out, visibility 0.4s ease-in-out; } .htooltip:hover > span { position: absolute; opacity: 1; visibility: visible; } .htooltip1 > span:first-child { background-color: rgba(0,0,0, 0.8); border-radius: 5px 5px 0px 0px; box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.5); color: #fff; margin-left: -1px; margin-top: -24px; opacity: 0; padding: 2px 5px; position: absolute; text-decoration: none; visibility: hidden; z-index: 10; transition: opacity 0.4s ease-in-out, visibility 0.4s ease-in-out; } .htooltip1:hover > span:first-child { position: absolute; opacity: 1; visibility: visible; } `); var lang_en = { 'Knight' : 'Knight', 'Necromancer' : 'Necromancer', 'Wizard' : 'Wizard', 'Elf' : 'Elf', 'Barbarian' : 'Barbarian', 'Dark elf' : 'Dark elf', 'Demon' : 'Demon', 'Dwarf' : 'Dwarf', 'Steepe barbarian' : 'Steepe barbarian', 'Pharaoh' : 'Pharaoh', 'Combat level' : 'Combat level', 'Hunters\' guild' : 'Hunters\' guild', 'Laborers\' guild' : 'Laborers\' guild', 'Gamblers\' guild' : 'Gamblers\' guild', 'Thieves\' guild' : 'Thieves\' guild', 'Rangers\' guild' : 'Rangers\' guild', 'Mercenaries\' guild' : 'Mercenaries\' guild', 'Commanders\' guild' : 'Commanders\' guild', 'Watchers\' guild' : 'Watchers\' guild', 'Adventurers\' guild' : 'Adventurers\' guild', 'Leaders\' Guild' : 'Leaders\' Guild', 'Smiths\' guild' : 'Smiths\' guild', 'Enchanters\' guild' : 'Enchanters\' guild', 'Enchanters' : 'Enchanters' }; var lang_ru = { 'Knight' : 'Рыцарь', 'Necromancer' : 'Некромант', 'Wizard' : 'Маг', 'Elf' : 'Эльф', 'Barbarian' : 'Варвар', 'Dark elf' : 'Темный эльф', 'Demon' : 'Демон', 'Dwarf' : 'Гном', 'Steepe barbarian' : 'Степной варвар', 'Pharaoh' : 'Фараон', 'Combat level' : 'Боевой уровень', 'Hunters\' guild' : 'Гильдия Охотников', 'Laborers\' guild' : 'Гильдия Рабочих', 'Gamblers\' guild' : 'Гильдия Картежников', 'Thieves\' guild' : 'Гильдия Воров', 'Rangers\' guild' : 'Гильдия Рейнджеров', 'Mercenaries\' guild' : 'Гильдия Наемников', 'Commanders\' guild' : 'Гильдия Тактиков', 'Watchers\' guild' : 'Гильдия Стражей', 'Adventurers\' guild' : 'Гильдия Искателей', 'Leaders\' Guild' : 'Гильдия Лидеров', 'Smiths\' guild' : 'Гильдия Кузнецов', 'Enchanters\' guild' : 'Гильдия Оружейников', 'Enchanters' : 'Оружейников' }; const text = isEn ? lang_en : lang_ru; const fractions = isEn ? ["Knight", "Necromancer", "Wizard", "Elf", "Barbarian", "Dark elf", "Demon", "Dwarf", "Tribal", "Pharaoh"] : ["Рыцарь", "Некромант", "Маг", "Эльф", "Варвар", "Темный эльф", "Демон", "Гном", "Степной варвар", "Фараон", "Кавалер", "Зомби-призыватель", "Волшебник", "Лесной", "Дикарь", "Зловещая тень", "Адский хулиган", "Карлик", "Кочевник", "Кот-фараон"]; main(); async function main() { tavernAndRouletteBalances(); birthday(); await getTalentsToHome(); if(location.pathname == "/pl_info.php") { talentsStatistics(); } calcArmyHealth(); // После загрузки навыков, если она есть, чтоб обработать навык "vitality" showExpBar(); setTimeout(function() { const talentsChanger = document.getElementById("hwmSetsMasterSkillSetSelectedValue"); const armyChanger = document.getElementById("hwmSetsMasterArmySetSelectedValue"); if(talentsChanger) { if(location.pathname == "/pl_info.php" && getUrlParamValue(location.href, "id") == PlayerId) { observe([talentsChanger], talentsStatistics); } if(location.pathname == "/home.php" || location.pathname == "/pl_info.php" && getUrlParamValue(location.href, "id") == PlayerId) { const panels = [armyChanger]; if(location.pathname == "/pl_info.php" && getUrlParamValue(location.href, "id") == PlayerId) { panels.push(talentsChanger); } observe(panels, calcArmyHealth); } } }, 1500); // Здесь ждем загрузки hwmSetsMaster, чтоб подписаться на элемент hwmSetsMasterSkillSetSelectedValue и hwmSetsMasterArmySetSelectedValue addPlayerInfoSpoilers(); clanStatistics(); } async function getTalentsToHome() { if(location.pathname == '/home.php') { const playerLevel = getViewingPlayerLevel(); if(playerLevel < 5) { return; } let hwmAdvancedPlayerInfoTalentsContainer = document.getElementById("hwmAdvancedPlayerInfoTalentsContainer"); if(!hwmAdvancedPlayerInfoTalentsContainer) { let homePageTalentsContainer; if(isNewPersonPage) { homePageTalentsContainer = document.querySelector("div.home_friends_block"); } else { homePageTalentsContainer = document.querySelector("body > center > table:nth-child(2) > tbody > tr:nth-child(1) > td:nth-child(1) > table > tbody > tr:nth-child(2) > td:nth-child(1) > table > tbody > tr > td > table > tbody > tr > td"); } addElement("br", {}, homePageTalentsContainer); const ShowTalentsTitleSpan = addElement("span", { id: "hwmAdvancedPlayerInfoTalentsCaptionContainer", innerHTML: ` » <b>${isEn ? "Talents" : "Навыки"}:</b><b id="hwmAdvancedPlayerInfoTalentsPointsContainer"></b>`, title: getShowTalentsTitleSpanTitle() }, homePageTalentsContainer); ShowTalentsTitleSpan.addEventListener("click", function() { setValue("ShowTalents", !getBool("ShowTalents")); this.title = getShowTalentsTitleSpanTitle(); getTalentsToHomeCore(); }, false); addElement("br", {}, homePageTalentsContainer); hwmAdvancedPlayerInfoTalentsContainer = addElement("div", { id: "hwmAdvancedPlayerInfoTalentsContainer" }, homePageTalentsContainer); } await getTalentsToHomeCore(); const talentsChanger = document.getElementById("hwmSetsMasterSkillSetSelectedValue"); if(talentsChanger) { observe([talentsChanger], getTalentsToHomeCore); //setTimeout(function() { observe([talentsChanger], getTalentsToHomeCore); }, 3000); } } } async function getTalentsToHomeCore() { if(location.pathname == '/home.php' && getBool("ShowTalents")) { const doc = await getRequest(`/pl_info.php?id=${PlayerId}`); const perksTable = getParent(doc.querySelector("a[href^='showperkinfo.php']"), "table", 2); if(perksTable) { Array.from(perksTable.querySelectorAll("a[href^='showperkinfo.php'] > img")).forEach(x => { x.style.width = `48px`; x.style.height = "auto"; }); //Array.from(perksTable.querySelectorAll("a[href^='showperkinfo.php'] > img")).forEach(x => { x.setAttribute("title", x.getAttribute("hint")); x.style.width = `48px`; x.style.height = "auto"; }); document.getElementById("hwmAdvancedPlayerInfoTalentsContainer").innerHTML = perksTable.outerHTML; if(typeof win.hwm_hints_init === 'function') win.hwm_hints_init(); talentsStatistics(); calcArmyHealth(); } } } function getShowTalentsTitleSpanTitle() { return isEn ? `Click for ${getBool("ShowTalents") ? "disable" : "enable"} talents loading` : `Нажмите для ${getBool("ShowTalents") ? "выключения" : "включения"} загрузки навыков`; } function talentsStatistics() { const playerLevel = getViewingPlayerLevel(); if(playerLevel < 5) { return; } let talentsContainer; let talentsCaptionContainer; let talentsPointsContainer; if(location.pathname == "/home.php") { talentsContainer = document.getElementById("hwmAdvancedPlayerInfoTalentsContainer"); talentsCaptionContainer = document.getElementById("hwmAdvancedPlayerInfoTalentsCaptionContainer"); talentsPointsContainer = document.getElementById("hwmAdvancedPlayerInfoTalentsPointsContainer"); } if(location.pathname == "/pl_info.php") { talentsContainer = getParent(document.querySelector("a[href^='showperkinfo.php?name=']"), "td", 3); const layerTable = getParent(talentsContainer, "table"); if(layerTable) { talentsCaptionContainer = Array.from(layerTable.rows[0].cells).find(x => x.innerHTML.includes(isEn ? "Talents" : "Навыки")).querySelector("b"); } talentsPointsContainer = document.getElementById("hwmAdvancedPlayerInfoTalentsPointsContainer") || addElement("span", { id: "hwmAdvancedPlayerInfoTalentsPointsContainer" }, talentsCaptionContainer); } if(!talentsContainer || !talentsCaptionContainer) { return; } const talentBranchRows = talentsContainer.querySelectorAll(":scope > table > tbody > tr"); const playerTalentBranches = Array.from(talentBranchRows).map(x => Array.from(x.querySelectorAll("a[href^='showperkinfo.php?name=']")).map(y => getUrlParamValue(y.href, "name"))); //console.log(playerTalentBranches); let talentPoints = 0; const playerFraction = getPlayerFraction(); const playerPerkBranchCosts = perkBranchCosts[playerFraction]; //console.log(playerPerkBranchCosts); for(const playerPerkBranche of playerTalentBranches) { let branchName = playerPerkBranche[0]; let firstPerkPromout = 1; if(["1", "2", "3"].includes(branchName.slice(-1))) { firstPerkPromout = parseInt(branchName.slice(-1)); branchName = branchName.slice(0, -1); } //console.log(`branchName: ${branchName}, branchCost: ${playerPerkBranchCosts[branchName]}, branchePerks: ${playerPerkBranche.length}, firstPerkPromout: ${firstPerkPromout}`); talentPoints += playerPerkBranchCosts[branchName] * (playerPerkBranche.length + firstPerkPromout - 1); } talentsPointsContainer.innerText = ` (${isEn ? "points" : "очки"} ${talentPoints} ${isEn ? "from" : "из"} ${10 + 5 * (playerLevel - 5)})`; } function calcArmyHealth() { let armyContainer; if(location.pathname == "/pl_info.php") { armyContainer = getParent(document.querySelector(".cre_creature72"), "center"); } if(location.pathname == "/home.php") { if(isNewPersonPage) { armyContainer = document.querySelector("div.home_css_creature_list"); } else { armyContainer = getParent(document.querySelector(".cre_creature72"), "center"); } } if(!armyContainer) { return; } const creatures = Array.from(document.querySelectorAll(`div.${isNewPersonPage ? "castle_creature54" : "cre_creature72"}`)).filter(x => x.querySelector("div#add_now_count")).map(x => ({ Name: getUrlParamValue(x.querySelector("a[href^='army_info.php?name=']").href, "name"), Amount: parseInt(x.querySelector("div#add_now_count").innerText) })); const hasVitality = document.querySelector("a[href='showperkinfo.php?name=vitality']") ? true : false; const sum = creatures.reduce((t, x) => { const army = unitsHealth[x.Name]; if(army) { t += x.Amount * (army[1] + (hasVitality ? 2 : 0)); } return t; }, 0); const unknownCreatures = creatures.filter(x => !unitsHealth[x.Name]); let unknownCreaturesMessage = ""; if(unknownCreatures.length > 0) { unknownCreaturesMessage = isEn ? `Creatures not found: ${unknownCreatures.map(x => x.Name).join(', ')}. Please, contact developer.` : `Существа не найдены: ${unknownCreatures.map(x => x.Name).join(', ')}. Пожалуйста, сообщите разработчику.`; } let hwmAdvancedPlayerInfoArmyHealthContainer = document.getElementById("hwmAdvancedPlayerInfoArmyHealthContainer"); if(!hwmAdvancedPlayerInfoArmyHealthContainer) { armyContainer.insertAdjacentHTML("afterend", ` » <b>${isEn ? "Total HP" : "Общее HP"}: </b><span id=hwmAdvancedPlayerInfoArmyHealthContainer>${sum}</span> <a id=hwmAdvancedPlayerInfouUknownCreaturesMessageContainer href="javascript:alert('${unknownCreaturesMessage}');" title="${unknownCreaturesMessage}"> (?)</a>`); hwmAdvancedPlayerInfoArmyHealthContainer = document.getElementById("hwmAdvancedPlayerInfoArmyHealthContainer"); } hwmAdvancedPlayerInfoArmyHealthContainer.innerText = sum; hwmAdvancedPlayerInfoArmyHealthContainer.style.color = hasVitality ? "#ff0000" : ""; const hwmAdvancedPlayerInfouUknownCreaturesMessageContainer = document.getElementById("hwmAdvancedPlayerInfouUknownCreaturesMessageContainer"); hwmAdvancedPlayerInfouUknownCreaturesMessageContainer.style.display = unknownCreaturesMessage ? "" : "none"; hwmAdvancedPlayerInfouUknownCreaturesMessageContainer.title = unknownCreaturesMessage; hwmAdvancedPlayerInfouUknownCreaturesMessageContainer.href = `javascript:alert('${unknownCreaturesMessage}');`; } function tavernAndRouletteBalances() { if(location.pathname != "/pl_info.php") { return; } // Баланс рулетки const rouletteDebitText = findChildrenTextContainsValue("td", isEn ? "Roulette bets total" : "Поставлено в рулетке"); const rouletteCreditText = findChildrenTextContainsValue("td", isEn ? "Roulette winnings total" : "Выиграно в рулетке"); if(rouletteDebitText.length == 1 && rouletteCreditText.length == 1 && rouletteDebitText[0].nextSibling.tagName.toLowerCase() == "b" && rouletteCreditText[0].nextSibling.tagName.toLowerCase() == "b") { const rouletteBalance = rouletteCreditText[0].nextSibling.innerText.replace(/,/g, "") - rouletteDebitText[0].nextSibling.innerText.replace(/,/g, ""); rouletteCreditText[0].nextSibling.insertAdjacentHTML("afterend", `<br> ${isEn ? 'Balance' : 'Баланс'}: <b>${rouletteBalance.toLocaleString()}</b>`); } // Баланс таверны var statisticsSecondCell = getParent(document.querySelector("td.wb > a[href^='pl_transfers.php?id']"), "td").nextSibling; var tavern_parent = statisticsSecondCell.querySelector("tr").parentNode.childNodes[0].childNodes[1].firstChild.firstChild.childNodes; const winsRow = tavern_parent[1]; const failsRow = tavern_parent[2]; tavern_parent[0].childNodes[1].setAttribute('style', 'white-space: nowrap;'); winsRow.childNodes[1].setAttribute('style', 'white-space: nowrap;'); //console.log(winsRow) failsRow.childNodes[1].setAttribute('style', 'white-space: nowrap;'); var tavern_0bal = winsRow.querySelector("tr"); var tavern_1bal = failsRow.querySelector("tr"); if(!tavern_0bal && !tavern_1bal) return; let wins = 0; let fails = 0; if(tavern_0bal) { wins = parseInt(winsRow.cells[1].querySelector("b").innerText.replace(/,/g, "")); tavern_0bal.childNodes[1].setAttribute('style', 'text-align: right; padding-right: 5px;'); tavern_0bal = tavern_0bal.childNodes[1].innerHTML.replace(/,/g, ""); winsRow.childNodes[3].firstChild.width = "100%"; var totalRow = winsRow.cloneNode(true); } else { tavern_0bal = 0; } if(tavern_1bal) { fails = parseInt(failsRow.cells[1].querySelector("b").innerText.replace(/,/g, "")); tavern_1bal.childNodes[1].setAttribute('style', 'text-align: right; padding-right: 5px;'); tavern_1bal = tavern_1bal.childNodes[1].innerHTML.replace(/,/g, ""); failsRow.childNodes[3].firstChild.width = "100%"; var totalRow = totalRow || failsRow.cloneNode(true); } else { tavern_1bal = 0; } var tavern_bal = tavern_0bal - tavern_1bal; totalRow.firstChild.innerHTML = ` ${isEn ? 'Balance:' : 'Баланс:'}`; totalRow.childNodes[1].innerHTML = `<b>${(wins - fails).toLocaleString()}</b>`; totalRow.childNodes[2].innerHTML = " "; totalRow.childNodes[3].innerHTML = ` <table border="0" cellspacing="0" cellpadding="0" width="100%"> <tbody> <tr> <td> <img class="rs" width="24" height="24" src="https://dcdn2.heroeswm.ru/i/r/48/gold.png?v=3.23de65" border="0" title="${isEn ? "Gold" : "Золото"}" alt=""> </td> <td style="text-align: right; padding-right: 5px;"> ${tavern_bal.toLocaleString()} </td> </tr> </tbody> </table>`; failsRow.insertAdjacentElement("afterend", totalRow); } function birthday() { if(location.pathname == "/pl_info.php") { const playerId = getUrlParamValue(location.href, "id"); let bifthday = GM_getValue(`PlayerBifthday${playerId}`, ""); const districtBold = Array.from(document.querySelectorAll("b")).find(x => x.innerHTML.includes(isEn ? "Location" : "Район")); if(districtBold) { districtBold.nextElementSibling.nextElementSibling.insertAdjacentHTML("afterend", ` » <b id=hwmAdvancedPlayerInfoBirthdayCaption title="${isEn ? "Click to download birthday" : "Нажмите для загрузки дня рождения"}">${isEn ? "Birthday" : "День рождения"}: </b><span id=hwmAdvancedPlayerInfoBirthday>${bifthday}</span>`); document.getElementById("hwmAdvancedPlayerInfoBirthdayCaption").addEventListener("click", loadBirthday); } } } async function loadBirthday() { const playerId = getUrlParamValue(location.href, "id"); const firstProtocolPage = await getRequest(`/pl_transfers.php?id=${playerId}&page=50000`); const lines = firstProtocolPage.querySelector(`div#set_mobile_max_width > div > div`).innerHTML.split("<br>").filter(x => x != ""); bifthday = lines[lines.length - 2]; bifthday = bifthday.replace(/ /g, ""); GM_setValue(`PlayerBifthday${playerId}`, bifthday); document.getElementById("hwmAdvancedPlayerInfoBirthday").innerHTML = bifthday; } function showExpBar() { if(location.pathname != '/home.php' && location.pathname != '/pl_info.php') { return; } const player = { SkillLevel: [], SkillNumber: []}; let skillInfoCell; if(isNewPersonPage) { const levelInfoCell = Array.from(document.querySelectorAll("div.home_pers_info")).find(x => x.innerHTML.includes(text['Combat level'])); player.Level = parseInt(levelInfoCell.querySelector("div[id=bartext] > span").innerText); player.Expirience = parseInt(levelInfoCell.querySelector("div.home_text_exp").firstChild.textContent.replace(/,/g, "")); const homeContainerBlocks = Array.from(document.querySelectorAll("div#set_mobile_max_width > div > div.home_container_block")); //console.log(homeContainerBlocks) skillInfoCell = homeContainerBlocks.find(x => x.innerHTML.includes(text['Knight']) || x.innerHTML.includes('Кавалер')); Array.from(skillInfoCell.querySelectorAll("div[id=row]")).forEach((x, i) => { player.SkillLevel[i] = parseInt(x.querySelector("div#bartext span").innerText); player.SkillNumber[i] = parseFloat(x.querySelector("div.home_text_exp").firstChild.textContent); }); const guildsDiv = homeContainerBlocks.find(x => x.innerHTML.includes(text['Enchanters'])); Array.from(guildsDiv.querySelectorAll("div[id=row]")).forEach(x => { const key = findKey(text, y => text[y].includes(x.querySelector("span.home_guild_text").innerText)); if(key) { player[key] = parseInt(x.querySelector("div#bartext span").innerText); } }); } else { const levelInfoBold = Array.from(document.querySelectorAll("td > b")).find(x => x.innerHTML.includes(text['Combat level'])); const levelRegex = new RegExp(`${text['Combat level']}: (\\d{1,2})`); player.Level = parseInt(levelRegex.exec(levelInfoBold.innerHTML)[1]); const expirienceRegex = /\(([\d\.\,]+)\)/g; const expirienceRegexExec = expirienceRegex.exec(levelInfoBold.parentNode.innerHTML); if(expirienceRegexExec) { player.Expirience = parseInt(expirienceRegexExec[1].replace(/,/g, "")); } skillInfoCell = Array.from(document.querySelectorAll("td")).find(x => (x.innerHTML.includes(text['Knight']) || x.innerHTML.includes('Кавалер')) && x.innerHTML.includes(text['Enchanters\' guild']) && !x.innerHTML.includes("<td")); const regex = /\(([\d\.\,]+)\)/g; for(const fraction of fractions) { const skillRegex = new RegExp(`${fraction}: (\\d{1,2})`); const skillsData = skillRegex.exec(skillInfoCell.innerHTML); if(!skillsData) { continue; } player.SkillLevel.push(parseInt(skillsData[1])); const skillsNumberData = regex.exec(skillInfoCell.innerHTML); let skillNumber = 0; if(skillsNumberData) { skillNumber = parseFloat(skillsNumberData[1]); } player.SkillNumber.push(skillNumber); } for(const key of Object.keys(text).filter(x => x.includes("guild") || x.includes("Guild"))) { const guildName = text[key]; let guildRegex = new RegExp(` ${guildName}: (\\d{1,2}) \\(`, "g"); if(key == 'Hunters\' guild') { guildRegex = new RegExp(` ${guildName}: .+>(\\d{1,2})<`, "g"); } player[key] = parseInt(guildRegex.exec(skillInfoCell.innerHTML)[1]); } } player.GuildStatsNumber = getGuildStatsNumber(player); player.MainSkillStatsNumber = getMainSkillStatsNumber(player); player.SkillSum = Math.floor(player.SkillLevel.reduce((t, x) => t + x, 0) * 0.25); player.TotalPoints = player.GuildStatsNumber + player.MainSkillStatsNumber + player.SkillSum; player.TotalSkills = round00(player.SkillNumber.reduce((t, x) => t + x, 0)); player.Ratio = player.TotalSkills > 0 ? Math.round(player.Expirience / player.TotalSkills) : 0; console.log(player); if(player.Level > 2) { //console.log(`isNewPersonPage: ${isNewPersonPage}`) const playerPersents = getPlayerPercents(player); console.log(playerPersents); let resumeText = "В норме!"; let resumeTitle = ""; const prevEdgeSpan = getSpanHtml(playerPersents.prevEdge, playerPersents.prevEdgeClarification); const totalPointsSpan = getSpanHtml(player.TotalPoints, isEn ? "Player points" : "Очков игрока"); const guildStatsNumberSpan = getSpanHtml(player.GuildStatsNumber, isEn ? "total guilds parameters" : "сумма параметров от всех гильдий"); const skillSumSpan = getSpanHtml(player.SkillSum, isEn ? "total factions skill levels*0.25" : "сумма уровней умений фракций*0.25"); const mainSkillStatsNumberSpan = getSpanHtml(player.MainSkillStatsNumber, isEn ? "max faction skill level parameters (with possible faction potion)" : "сумма параметров от максимального умения фракции(с учётом возможного применения \"зелья фракции\")"); const nextEdgeSpan = getSpanHtml(playerPersents.nextEdge, playerPersents.nextEdgeClarification); const progressText = `${isEn ? "Main progress" : "Основной прогресс"}: ${playerPersents.normalPercent}%. ${prevEdgeSpan}->${totalPointsSpan}=(${guildStatsNumberSpan}+${skillSumSpan}+${mainSkillStatsNumberSpan})->${nextEdgeSpan}`; if(playerPersents.advacedPersent > 0){ resumeText = `Перекач! ${isEn ? "Exp" : "Опыт"}: +${playerPersents.advacedPersent}%`; //resumeTitle = `${isEn ? "More experience" : "Опыта больше на"}: ${playerPersents.advacedPersent}%`; } if(playerPersents.advacedPersent < 0) { resumeText = `Недокач!`; resumeTitle = `${isEn ? "more skill points will be awarded in proportion to the missing points" : "будет начисляться больше очков умений в соотношении к недостающим очкам"}`; } const resumeSpan = getSpanHtml(resumeText, resumeTitle); if(isNewPersonPage) { const ratioSpan = getSpanHtml(player.Ratio.toLocaleString(), isEn ? "Expirience points to one skill point" : "Очков опыта на одно очко умения"); skillInfoCell.querySelector("div.home_inside_margins").insertAdjacentHTML("beforeend", ` <div class="home_scroll_content" id="row" onclick="show_all_hwm_exp();"> <span class="home_guild_text">${isEn ? "Total skills" : "Сумма умений"}</span> <div class="home_text_exp" style="display: block;">${player.TotalSkills.toLocaleString()} (${ratioSpan})</div> </div> <div class="home_scroll_content htooltip1" id="row" onclick="show_all_hwm_exp();"> <span>${progressText}</span> <span class="home_guild_text">${isEn ? "Progress" : "Прогресс"} <div id="bar" class="home_bar_exp" style="opacity: 1;"><div id="barprogress" style="width: ${playerPersents.normalPercent}%;"></div></div> <div class="home_text_exp" style="display: block;">${playerPersents.normalPercent}% ${resumeSpan}</div> `); } else { const levelInfoBold = getParent(Array.from(document.querySelectorAll("td > b")).find(x => x.innerHTML.includes(isEn ? "Combat level:" : "Боевой уровень:")), "td").querySelector("br"); //levelInfoBold.insertAdjacentHTML("afterend", `<meter id="playerPointsMeter" min="0" max="147" low="${playerPersents.beginNormalPoint}" high="${playerPersents.endNormalPoint}" optimum="${playerPersents.averagePoint}" value="${player.TotalPoints}"></meter>`); levelInfoBold.insertAdjacentHTML("afterend", ` <span id=hwmAdvancedPlayerInfoTotalSkillsSpan> » <b>${isEn ? "Skills count" : "Сумма умений"}: </b>${player.TotalSkills.toLocaleString()}, ${isEn ? "ratio" : "соотношение"}: <span title="${isEn ? "Expirience points to one skill point" : "Очков опыта на одно очко умения"}">${ player.Ratio.toLocaleString() }</span> </span> <br> » <b>${isEn ? "Progress" : "Прогресс"}:</b> <div class="bar_wrap htooltip"> <div class="bar" style="width: ${playerPersents.normalPercent}%"></div> <span>${progressText}</span> </div> <div style='font-size: 8px; font-weight: bold; display: inline-block;'>${playerPersents.normalPercent}% ${resumeSpan}</div>`); } } } function getSpanHtml(value, title) { return `<span title="${title}">${value}</span>`; } function getGuildStatsNumber(player) { const mercStats = [0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11]; const commandersStats = [0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; const watchersStats = [0, 1, 2, 3, 4, 5, 6, 7, 7.5, 8.5, 9.5]; const leadersStats = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5, 0.5, 0.5, 0.5, 0.5, 1]; const hunters = player['Hunters\' guild']; const laborers = Math.floor(player['Laborers\' guild'] / 2); const thieves = Math.max(player['Thieves\' guild'], player['Rangers\' guild']) / 2; const mercenaries = mercStats[player['Mercenaries\' guild']]; const commanders = commandersStats[player['Commanders\' guild']]; const watchers = watchersStats[player['Watchers\' guild']]; const adventurers = player['Adventurers\' guild']; const leaders = leadersStats[player['Leaders\' Guild']]; //console.log(`Hunters: ${hunters}, Laborers: ${laborers}, Thieves/Rangers: ${thieves}, Mercenaries: ${mercenaries}, Commanders: ${commanders}, Watchers: ${watchers}, Adventurers: ${adventurers}, Leaders: ${leaders}`); return hunters + laborers + thieves + mercenaries + commanders + watchers + adventurers + leaders; } function getMainSkillStatsNumber(player) { let skillLevel = player.SkillLevel.reduce((t, x) => Math.max(t, x), 0); const averageSkill = [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 10, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14]; skillLevel = Math.max(skillLevel, averageSkill[player.Level]); const skillStats = [0, 1, 2, 2.5, 4, 5.5, 6.5, 9, 11.5, 16, 21, 27, 33, 35, 36.5]; return skillStats[skillLevel]; } function getPlayerPercents(player) { //player.Level++; //для тестов const averagePoints = [0, 0, 0, 3, 5, 7, 10, 13, 17, 20, 25, 29, 35, 41, 48, 58, 68, 77, 84, 90, 96, 101, 108, 114, 125, 136, 147, 158, 169]; const penaltyProcents = [0, 25, 500, 1000]; // Ищем перекач // 101, 108, 114, 125 let advacedPersent = 0; const nextLevels = averagePoints.slice(player.Level + 1, player.Level + 5); const prevLevels = averagePoints.slice(player.Level - 4, player.Level).reverse(); //console.log(prevLevels) const averagePoint = averagePoints[player.Level]; let beginNormalPoint = prevLevels[0]; let endNormalPoint = nextLevels[0] + 2; //console.log(`beginNormalPoint: ${beginNormalPoint}, endNormalPoint: ${endNormalPoint}, player.TotalPoints: ${player.TotalPoints}, player.Level: ${player.Level}`) let prevEdge = beginNormalPoint; let nextEdge = endNormalPoint; let prevEdgeClarification = isEn ? `Average points on ${player.Level - 1} level` : `Средние очки на ${player.Level - 1} уровне`; let nextEdgeClarification = isEn ? `Average points + 2 on ${player.Level + 1} level` : `Средние очки + 2 на ${player.Level + 1} уровне`; if(player.TotalPoints <= endNormalPoint) { if(player.TotalPoints < beginNormalPoint) { // Недокач - будет начисляться больше очков умений в соотношении к недостающим очкам } if(player.TotalPoints < beginNormalPoint) { prevLevels.forEach((x, i) => { const add = i == 0 ? 0 : 0; if(player.TotalPoints < (x - add) && player.TotalPoints >= prevLevels[i + 1]) { const beginPoint = x - add; const endPoint = prevLevels[i + 1]; const beginProcent = -penaltyProcents[i] - 1; const endProcent = penaltyProcents[i + 1]; const advacedPoints = beginPoint - player.TotalPoints; const percentStep = Math.round((endProcent - beginProcent) / (endPoint - beginPoint)); advacedPersent = beginProcent + percentStep * advacedPoints; //console.log(`excessLevel: ${i}, player.TotalPoints: ${player.TotalPoints}, levelAveragePoints: ${x}, add: ${add}, beginPoint: ${beginPoint}, endPoint: ${endPoint}, beginProcent: ${beginProcent}, endProcent: ${endProcent}, advacedPoints: ${advacedPoints}, percentStep: ${percentStep}, advacedPersent: ${advacedPersent}`); prevEdge = endPoint; nextEdge = beginPoint; prevEdgeClarification = isEn ? `Average points on ${player.Level - (i + 2)} level` : `Средние очки на ${player.Level - (i + 2)} уровне`; nextEdgeClarification = isEn ? `Average points on ${player.Level - (i + 1)} level` : `Средние очки на ${player.Level - (i + 1)} уровне`; } if(i == prevLevels.length - 1 && player.TotalPoints < prevLevels[i + 1]) { advacedPersent = penaltyProcents[i + 1]; //console.log(`excessLevel: ${i}, player.TotalPoints: ${player.TotalPoints}, levelAveragePoints: ${x}, add: ${add}, advacedPersent: ${advacedPersent}`); } }); } } else { nextLevels.forEach((x, i) => { const add = i == 0 ? 2 : 0; if(player.TotalPoints > (x + add) && player.TotalPoints <= nextLevels[i + 1]) { const beginPoint = x + add; const endPoint = nextLevels[i + 1]; const beginProcent = penaltyProcents[i] + 1; const endProcent = penaltyProcents[i + 1]; const advacedPoints = player.TotalPoints - beginPoint; const percentStep = Math.round((endProcent - beginProcent) / (endPoint - beginPoint)); advacedPersent = beginProcent + percentStep * advacedPoints; //console.log(`excessLevel: ${i}, player.TotalPoints: ${player.TotalPoints}, levelAveragePoints: ${x}, add: ${add}, beginPoint: ${beginPoint}, endPoint: ${endPoint}, beginProcent: ${beginProcent}, endProcent: ${endProcent}, advacedPoints: ${advacedPoints}, percentStep: ${percentStep}, advacedPersent: ${advacedPersent}`); prevEdge = x + add; nextEdge = endPoint; prevEdgeClarification = isEn ? `Average points${add > 0 ? ` + ${add}` : ""} on ${player.Level + 1 + i} level` : `Средние очки${add > 0 ? ` + ${add}` : ""} на ${player.Level + 1 + i} уровне`; nextEdgeClarification = isEn ? `Average points on ${player.Level + 1 + i + 1} level` : `Средние очки на ${player.Level + 1 + i + 1} уровне`; } if(i == nextLevels.length - 1 && player.TotalPoints > nextLevels[i + 1]) { advacedPersent = penaltyProcents[i + 1]; //console.log(`excessLevel: ${i}, player.TotalPoints: ${player.TotalPoints}, levelAveragePoints: ${x}, add: ${add}, advacedPersent: ${advacedPersent}`); } }); } return { averagePoint: averagePoint, beginNormalPoint: beginNormalPoint, endNormalPoint: endNormalPoint, normalPercent: Math.max(Math.min(Math.round((player.TotalPoints - beginNormalPoint) * 100 / (endNormalPoint - beginNormalPoint)), 100), 0), advacedPersent: advacedPersent, prevEdge: prevEdge, nextEdge: nextEdge, prevEdgeClarification: prevEdgeClarification, nextEdgeClarification: nextEdgeClarification }; } function addPlayerInfoSpoilers() { if(location.pathname == "/pl_info.php") { const panelNames = isEn ? ["Statistics", "Clans", "Resources", "Best stacks in the Leaders' Guild", "Achievements", "Personal info"] : ["Статистика", "Кланы", "Ресурсы", "Лучшие отряды Гильдии Лидеров", "Достижения", "Личная информация"]; const bolds = Array.from(document.querySelectorAll("td > b")); for(const panelName of panelNames) { const panelTitleBold = bolds.find(x => x.innerText == panelName); if(panelTitleBold) { const panelTitle = panelTitleBold.closest("td"); const spoiler = addElement("div", { id: `${panelName.replace(/\s/g, "").replace(/'/g, "")}Spoiler`, style: "display: inline-block; cursor: pointer;", innerHTML: `<img id="pl_info_parts_open_img" src="https://dcdn.heroeswm.ru/i/inv_im/btn_expand.svg" style="vertical-align: middle;">` }, panelTitle); spoiler.addEventListener("click", function() { setPlayerValue(this.id, !getPlayerBool(this.id)); bindPlayerInfoSpolers(); }); if(panelName == (isEn ? "Statistics" : "Статистика")) { addElement("a", { innerHTML: ` <b>${isEn ? "Battles" : "Бои"}</b>`, href: `/pl_warlog.php?id=${getUrlParamValue(location.href, "id")}` }, panelTitle); addElement("a", { innerHTML: ` <b>${isEn ? "Transfers" : "Передачи"}</b>`, href: `/pl_transfers.php?id=${getUrlParamValue(location.href, "id")}` }, panelTitle); } if(panelName == (isEn ? "Clans" : "Кланы")) { const clanRef = panelTitle.closest("tr").nextElementSibling.querySelector("a[href^='clan_info.php']"); if(clanRef) { const clone = clanRef.cloneNode(true); panelTitle.insertAdjacentElement("beforeend", clone); } } } } bindPlayerInfoSpolers(); } } function bindPlayerInfoSpolers() { const panelNames = isEn ? ["Statistics", "Clans", "Resources", "Best stacks in the Leaders' Guild", "Achievements", "Personal info"] : ["Статистика", "Кланы", "Ресурсы", "Лучшие отряды Гильдии Лидеров", "Достижения", "Личная информация"]; for(const panelName of panelNames) { const spoilerId = `${panelName.replace(/\s/g, "").replace(/'/g, "")}Spoiler`; const spoiler = document.getElementById(spoilerId); if(spoiler) { const spoiled = getPlayerBool(spoilerId); spoiler.querySelector("img").style.transform = spoiled ? 'rotate(0deg)' : 'rotate(90deg)'; spoiler.closest("tr").nextElementSibling.style.display = spoiled ? "none" : ""; } } } function clanStatistics() { if(location.pathname == "/clan_info.php") { const clanActivity = document.querySelector("img[src$='clans/online.gif']") || document.querySelector("img[src$='clans/offline.gif']"); if(!clanActivity) { return; } const clanHeroesTable = clanActivity.closest("table"); const onlineAmount = clanHeroesTable.querySelectorAll("img[src$='clans/online.gif']").length; const offlineAmount = clanHeroesTable.querySelectorAll("img[src$='clans/offline.gif']").length; const inBattleAmount = clanHeroesTable.querySelectorAll("img[src$='clans/battle.gif']").length; const playArcomagAmount = clanHeroesTable.querySelectorAll("img[src$='clans/arcomag.gif']").length; const clanInfoTable = document.querySelector("a[href^='clan_log.php?id']").closest("table"); const firstRow = clanInfoTable.rows[0]; firstRow.cells[0].insertAdjacentHTML("beforeend", ` <span id=shortClanActivityInfoSpan> <span style="${onlineAmount > 0 ? "" : "display: none;"}"><img src="https://dcdn.heroeswm.ru/i/clans/online.gif" align="absmiddle" border="0" height="15" width="15"> <b>${isEn ? "Online" : "В игре"}:</b> ${onlineAmount} </span> <span style="${inBattleAmount > 0 ? "" : "display: none;"}"><img src="https://dcdn.heroeswm.ru/i/clans/battle.gif" align="absmiddle" border="0" height="15" width="15"> <b>${isEn ? "In combat" : "В бою"}:</b> ${inBattleAmount} </span> <span style="${playArcomagAmount > 0 ? "" : "display: none;"}"><img src="https://dcdn.heroeswm.ru/i/clans/arcomag.gif" align="absmiddle" border="0" height="15" width="15"> <b>${isEn ? "In card match" : "В таверне"}:</b> ${playArcomagAmount} </span> </span>`); const spoiler = addElement("div", { id: `clanStatisticsSpoiler`, style: "display: inline-block; cursor: pointer;", innerHTML: `<img id="pl_info_parts_open_img" src="https://dcdn.heroeswm.ru/i/inv_im/btn_expand.svg" style="vertical-align: middle;">` }, document.getElementById("shortClanActivityInfoSpan")); spoiler.addEventListener("click", function() { setPlayerValue("clanStatisticsSpoiled", !getPlayerBool("clanStatisticsSpoiled")); clanStatisticsRowBind(); }); const clanHeroes = Array.from(clanHeroesTable.rows).filter(x => x.cells[2].querySelector("a[href^='pl_info.php?id=']")).map(x => { const level = parseInt(x.cells[3].innerText); const fractionImage = x.cells[2].querySelector("img"); const fractionNumber = parseInt(fractionImage.src.match(/\/i\/f\/r(\d+).png/)[1]); return { level: level, fractionImage: fractionImage, fraction: fractionImage.title, fractionNumber: fractionNumber }; }); const clanHeroesAmount = clanHeroes.length; const heroesLevels = groupBy(clanHeroes, "level"); const clanLevels = Object.keys(heroesLevels).map(x => ({ level: parseInt(x), amount: heroesLevels[x].length })); clanLevels.sort((a, b) => b.level - a.level); const heroesFractions = groupBy(clanHeroes, "fractionNumber"); // console.log(heroesFractions); const clanFractions = Object.keys(heroesFractions).map(x => ({ fractionNumber: parseInt(x) % 100, amount: heroesFractions[x].length, fractionImage: heroesFractions[x][0].fractionImage, fraction: heroesFractions[x][0].fraction, altNumber: parseInt(x) >= 100 ? Math.round(parseInt(x) / 100) : 0 })); clanFractions.sort((a, b) => a.fractionNumber == b.fractionNumber ? a.altNumber - b.altNumber : a.fractionNumber - b.fractionNumber); // console.log(clanFractions); const clanStatisticsRow = addElement('tr', { id: "clanStatisticsRow" }, firstRow, "afterend"); clanStatisticsRow.innerHTML = ` <td colspan="2" class="wbwhite"> <table width="100%" height="100%"> <tr> <td width="60%" valign="top" style="border-right:1px #5D413A solid;"> <table width="100%" cellpadding="5"> <tr> <td align="center"> <b>${isEn ? 'All' : 'Всего'}:</b> ${clanHeroesAmount} <b>${isEn ? 'Online' : 'В сети'}:</b> ${clanHeroesAmount - offlineAmount} (${Math.round((clanHeroesAmount - offlineAmount) / clanHeroesAmount * 100)}%) </td> </tr> <tr> <td align="center" style="white-space:nowrap"> <img src="https://dcdn.heroeswm.ru/i/clans/online.gif" align="absmiddle" border="0" height="15" width="15"> <b>${isEn ? "Online" : "В игре"}:</b> ${onlineAmount} <img src="https://dcdn.heroeswm.ru/i/clans/battle.gif" align="absmiddle" border="0" height="15" width="15"> <b>${isEn ? "In combat" : "В бою"}:</b> ${inBattleAmount} <img src="https://dcdn.heroeswm.ru/i/clans/arcomag.gif" align="absmiddle" border="0" height="15" width="15"> <b>${isEn ? "In card match" : "В таверне"}:</b> ${playArcomagAmount} <img src="https://dcdn.heroeswm.ru/i/clans/offline.gif" align="absmiddle" border="0" height="15" width="15"> <b>${isEn ? "Offline" : "Не в игре"}:</b> ${offlineAmount} </td> </tr> <tr> <td> ${clanFractions.map(x => `<img src="${x.fractionImage.src}" align="absmiddle" border="0" height="15" width="15"> <b>${x.fraction}:</b> ${x.amount} (${Math.round(x.amount / clanHeroesAmount * 100)}%)`).join("<br>")} </td> </tr> </table> </td> <td valign="top" height="100%"> <table width="100%" height="100%" cellpadding="5"> <tr> <td align="center"> <b>${isEn ? 'The average level of heroes' : 'Средний уровень героев'}:</b> ${round0(clanHeroes.reduce((t, x) => t + x.level, 0) / clanHeroesAmount)} </td> </tr> <tr> <td height="100%" valign="middle"> ${clanLevels.map(x => `<b>${x.level} ${isEn ? 'level' : 'уровней'}:</b> ${x.amount} (${Math.round(x.amount / clanHeroesAmount * 100)}%)`).join("<br>")} </td> </tr> <tr> <td align="right" valign="bottom"> </td> </tr> </table> </td> </tr> </table> </td>`; clanStatisticsRowBind(); } } function clanStatisticsRowBind() { const spoiled = getPlayerBool("clanStatisticsSpoiled"); const clanStatisticsSpoiler = document.getElementById("clanStatisticsSpoiler"); clanStatisticsSpoiler.querySelector("img").style.transform = spoiled ? 'rotate(0deg)' : 'rotate(90deg)'; clanStatisticsSpoiler.title = isEn ? (spoiled ? "Show clan statistics" : "Hide clan statistics") : (spoiled ? "Показать статистику клана" : "Скрыть статистику клана"); document.getElementById("clanStatisticsRow").style.display = spoiled ? "none" : ""; } function getViewingPlayerLevel() { if(location.pathname == "/home.php" || location.pathname == "/pl_info.php") { if(isNewPersonPage) { const levelInfoCell = Array.from(document.querySelectorAll("div.home_pers_info")).find(x => x.innerHTML.includes(isEn ? "Combat level" : "Боевой уровень")); return parseInt(levelInfoCell.querySelector("div[id=bartext] > span").innerText); } else { const playerLevelExec = new RegExp(`<b>${isEn ? "Combat level" : "Боевой уровень"}: (\\d+?)<\\/b>`).exec(document.documentElement.innerHTML); if(playerLevelExec) { return parseInt(playerLevelExec[1]); } } } return 0; } function getPlayerFraction() { let fractionSourceText; if(location.pathname == '/home.php') { const fractionImage = isNewPersonPage ? document.querySelector("div#hwm_no_zoom div.home_main_pers_block center a[href^='castle.php'] img") : document.querySelector("body > center table.wb > tbody > tr:nth-child(2) center a[href^='castle.php'] img"); fractionSourceText = fractionImage?.src; } const playerFractionExec = /\/i\/f\/r(\d{1,3})\.png/.exec(fractionSourceText || document.querySelector("body").innerHTML); if(playerFractionExec) { return playerFractionExec[1]; } } // https://dcdn3.heroeswm.ru/i/april2023/gn_face.png // https://dcdn.heroeswm.ru/i/april2023/pvp_gerb2.png // https://dcdn3.heroeswm.ru/i/april2023/gv_face.png // https://dcdn1.heroeswm.ru/i/april2023/gr_face.png // https://dcdn1.heroeswm.ru/i/april2023/go_face.png // https://dcdn.heroeswm.ru/i/kukla_png/premium/1april2023/p8ap.png?v=10.d20e1e // https://dcdn1.heroeswm.ru/i/kukla_png/premium/1april2023/p1ap.png?v=10.d20e1e // https://dcdn.heroeswm.ru/i/kukla_png/premium/1april2023/p2ap.png?v=10.d20e1e // https://dcdn.heroeswm.ru/i/kukla_png/premium/1april2023/p3ap.png?v=10.d20e1e // https://dcdn3.heroeswm.ru/i/kukla_png/premium/1april2023/p4ap.png?v=10.d20e1e // https://dcdn3.heroeswm.ru/i/kukla_png/premium/1april2023/p5ap.png?v=10.d20e1e // https://dcdn2.heroeswm.ru/i/kukla_png/premium/1april2023/p6ap.png?v=10.d20e1e // https://dcdn2.heroeswm.ru/i/kukla_png/premium/1april2023/p7ap.png?v=10.d20e1e // https://dcdn.heroeswm.ru/i/kukla_png/premium/1april2023/p9ap.png?v=10.d20e1e // https://dcdn.heroeswm.ru/i/kukla_png/premium/1april2023/p10ap.png?v=10.d20e1e // https://dcdn.heroeswm.ru/i/transport/1april/150/2.png // https://dcdn.heroeswm.ru/i/transport/1april/150/108.png // https://dcdn.heroeswm.ru/i/transport/1april/150/150.png