// ==UserScript==
// @name ClanEventHelper
// @namespace https://greasyfork.org/ru/scripts/396872-claneventhelper
// @version 3.3
// @description try to take over the world!
// @author You
// @include /^https{0,1}:\/\/((www|qrator)\.heroeswm\.ru|178\.248\.235\.15)\/clan_info.+/
// @grant unsafeWindow
// ==/UserScript==
(function (window, undefined) {
let w;
if (typeof unsafeWindow !== undefined) {
w = unsafeWindow;
} else {
w = window;
}
if (w.self !== w.top) {
return;
}
if(!unsafeWindow.updateTable) {
unsafeWindow.updateTable = updateTable;
}
let inBattleImg = `<img src="https://dcdn.heroeswm.ru/i/clans/battle.gif" style="vertical-align: middle; width: 15px; height: 15px;" title="Проводит бой в ивенте" alt="Проводит бой в ивенте">`;
let isInCW = document.querySelector("body > center > table > tbody > tr > td > table > tbody > tr > td > table:nth-child(2) > tbody > tr:nth-child(1) > td:nth-child(2) > img") == null;
let tds = document.querySelector("body > center > table > tbody > tr > td > table > tbody > tr > td > table:nth-child(2) > tbody > tr:nth-child(1)").querySelectorAll("td").length;
class ClanMember {
constructor(id, nick, cl, eventPoints) {
this.id = id;
this.nick = nick;
this.cl = cl;
this.eventPoints = eventPoints;
}
}
let inBattleCount = 0;
let clanMembers = [];
let clanMembersByCL = new Map();
fillClanMembers();
let eventMaxWave;
let currentWave;
let pointsPool = [];
doGet(`https://${location.host}/bselect.php?all=1`, processBselectResponse);
function processBselectResponse(doc) {
doc
.querySelector("body > center > table > tbody > tr > td > table > tbody > tr.wbwhite > td.wb")
.innerHTML
.toString()
.split("<br>")
.filter(battle => battle.match(/<!--(\d{1,3})-->/))
.forEach(battle => {
clanMembers
.filter(member => battle.match(/<!--(\d{1,3})-->/)[1] === "140" && battle.match(/pl_info\.php\?id=\d{1,10}/)[0] === member.id)
.forEach(member => {
member.isInEventBattle = true;
inBattleCount++;
})
});
main()
}
function main() {
fillClanMembersByCl();
eventMaxWave = setEventMaxWave();
fillPointsPool();
currentWave = JSON.parse(JSON.stringify(eventMaxWave));
addContainerToDOM();
addTableToDOM();
if (isInCW && tds === 5 || tds === 6){
setPolzynok();
setStyle();
}
}
function updateTable() {
let rng = document.getElementById('bestInput'); //rng - это Input
let p = document.getElementById('one'); // p - абзац
currentWave = pointsPool[rng.value-1];
p.innerHTML = `До волны: ${currentWave}`;
removeElement("members-table");
addTableToDOM();
}
function addContainerToDOM() {
let s = `<center><div id="members-container" style="width:100%; background: white; border: 1px black solid"></div></center>`;
document.querySelector("body > center > table > tbody > tr > td > table > tbody > tr > td > table:nth-child(1)").insertAdjacentHTML('afterend', s)
}
function addTableToDOM() {
let s = `
<table id="members-table" class="ololo">
<thead class="bestP">
<td style="width:7%"><div style="">БУ</div></td>
<td colspan="2" style="width:20%"><div style="">Топ рез у</div></td>
<td style="width:80%"><div style="">Тянущие клан на дно</div></td>
</thead>
`;
for (let [key, value] of clanMembersByCL.entries()) {
let membersWithMaxWave = getMaxWaveCount(value);
let membersWithNoMaxWave = getMembersWithoutMaxWave(value);
let percentageWithMaxWave = (membersWithMaxWave / value.length) * 100;
s += `
<tr>
<td>${key}</td>
<td>${membersWithMaxWave} из ${value.length}</td>
<td>${percentageWithMaxWave.toFixed(2)}%</td>
<td>${membersArrayToString(membersWithNoMaxWave)} </td>
</tr>`
}
let membersWithMaxWave = getMaxWaveCount(clanMembers);
let percentageWithMaxWave = (membersWithMaxWave / clanMembers.length) * 100;
s += `
<tr>
<td>Всего:</td>
<td colspan="2">${membersWithMaxWave} из ${clanMembers.length} [${percentageWithMaxWave.toFixed(2)}%] <br> avg. wave: ${getAvgWave()}</td>
<td>${getLostPointsTd(getLostPoints(clanMembers))}</td>
</tr>
<tr>
<td>Красавчики:<br>${inBattleImg}: ${inBattleCount}</td>
<td colspan="3">${membersArrayToString(getMembersWithMaxWave(clanMembers))}</td>
</tr>
</table>`;
document.getElementById("members-container").insertAdjacentHTML('beforeend', s)
}
function getLostPointsTd(lostPoints) {
if (lostPoints === 0) {
return `В клане все красавчики`
}
if (lostPoints === 0 && clanMembers.length < 200){
return `Из-за недостачи игроков клан потерял <b style='color: red'>${lostPoints}</b> очков`
}
if (lostPoints > 0) {
return `Из-за <b>?#A*&%!</b> клан потерял <b style='color: red'>${lostPoints}</b> очков`
}
if (lostPoints > 0 && clanMembers.length < 200) {
return `Из-за <b>?#A*&%!</b> и недостачи игроков клан потерял <b style='color: red'>${lostPoints}</b> очков`
}
return ``
}
function fillPointsPool() {
clanMembers.forEach(member => pointsPool.push(member.eventPoints));
pointsPool = pointsPool.filter((v, i, a) => a.indexOf(v) === i).sort((a, b) => a - b);
}
function fillClanMembers() {
document
.querySelector("body > center > table > tbody > tr > td > table > tbody > tr > td > table:nth-child(2) > tbody")
.querySelectorAll("tr")
.forEach(tr => clanMembers.push(createClanMember(tr)));
}
function createClanMember(tr) {
let startTd = isInCW ? 2 : 3;
let clanMember = new ClanMember();
clanMember.id = tr.querySelector("td:nth-child("+ startTd +") > a").getAttribute("href");
clanMember.nick = tr.querySelector("a.pi").innerText;
clanMember.cl = parseInt(tr.querySelector("td:nth-child("+ (startTd+1)+")").innerText);
clanMember.eventPoints = parseFloat(tr.querySelector("td:nth-child("+(startTd+3) +")")
.innerText
.trim()
.replace(",", "")
);
clanMember.eventPoints = isNaN(clanMember.eventPoints) ? 0 : clanMember.eventPoints;
return clanMember;
}
function setEventMaxWave() {
return Math.max(...clanMembers.map(o => o.eventPoints), 0);
}
function getAvgWave() {
return (clanMembers.reduce((sum, member) => sum + member.eventPoints, 0)/clanMembers.length)
.toFixed(2);
}
function fillClanMembersByCl() {
clanMembers
.sort((a, b) => a.cl-b.cl)
.forEach(member =>
clanMembersByCL.has(member.cl)
? clanMembersByCL.get(member.cl).push(member)
: clanMembersByCL.set(member.cl, [member]));
}
function getMaxWaveCount(members) {
return members.filter(member => member.eventPoints >= currentWave).length
}
function getMembersWithMaxWave(members) {
return members
.sort((a, b) => a.eventPoints - b.eventPoints)
.filter(member => member.eventPoints >= currentWave)
.map(member => `<a style="text-decoration: none;" href="${member.id}"><b>${member.nick}</b></a>`)
}
function getMembersWithoutMaxWave(members) {
return members
.sort((a, b) => a.eventPoints - b.eventPoints)
.filter(member => member.eventPoints < currentWave)
.map(member => `<a style="text-decoration: none;" href="${member.id}"><b>${member.nick} </b></a>${member.isInEventBattle ? inBattleImg : ``} : <b style="color: red">${member.eventPoints-0}</b>`);
}
function getLostPoints(members) {
return members
.filter(member => member.eventPoints < currentWave)
.reduce((sum, member) => sum + parseInt((eventMaxWave*100 - member.eventPoints*100).toString()), 0)
/100+(200 - clanMembers.length)*eventMaxWave;
}
function membersArrayToString(members) {
return members.length === 0
? `Таких нет, все красавчики.`
: members.reduce((resultStr, member, index) => resultStr+member+(index<members.length-1?`<b style="color: blue">;</b> `:``),``);
}
function removeElement(id) {
let elem = document.getElementById(id);
return elem.parentNode.removeChild(elem);
}
function setPolzynok() {
let myDiv = `
<input id="bestInput" class ="myPolzynok" type="range" min="1" max="${pointsPool.length}" step="1" value="${pointsPool.length}" oninput="updateTable()">
</br>
<p class="bestP" id="one">До волны: ${currentWave}</p>
`;
document.getElementById("members-container").insertAdjacentHTML("afterbegin", myDiv);
}
function setStyle() {
let style = document.createElement('style');
style.innerHTML = `
.myPolzynok {
-webkit-appearance: none;
margin: 18px 0;
width: 40%;
}
table.ololo td {
text-align: center;
}
table.ololo {
border-collapse: collapse;
}
table.ololo td {
border: 2px solid #c0deff;
padding: 5px;
}
table.ololo tr:first-child td {
border-top: 0;
}
table.ololo tr td:first-child {
border-left: 0;
}
table.ololo tr:last-child td {
border-bottom: 0;
}
table.ololo tr td:last-child {
border-right: 0;
}
.myPolzynok:focus {
outline: none;
}
.myPolzynok:focus {
outline: none;
}
.myPolzynok::-webkit-slider-runnable-track {
width: 100%;
height: 8.4px;
cursor: pointer;
animate: 0.2s;
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
background: #3071a9;
border-radius: 1.3px;
border: 0.2px solid #010101;
}
.myPolzynok::-webkit-slider-thumb {
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
border: 1px solid #000000;
height: 36px;
width: 16px;
border-radius: 3px;
background: #ffffff;
cursor: pointer;
-webkit-appearance: none;
margin-top: -14px;
}
.myPolzynok:focus::-webkit-slider-runnable-track {
background: #367ebd;
}
.myPolzynok::-moz-range-track {
width: 100%;
height: 8.4px;
cursor: pointer;
animate: 0.2s;
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
background: #3071a9;
border-radius: 1.3px;
border: 0.2px solid #010101;
}
.myPolzynok::-moz-range-thumb {
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
border: 1px solid #000000;
height: 36px;
width: 16px;
border-radius: 3px;
background: #ffffff;
cursor: pointer;
}
.myPolzynok::-ms-track {
width: 100%;
height: 8.4px;
cursor: pointer;
animate: 0.2s;
background: transparent;
border-color: transparent;
border-width: 16px 0;
color: transparent;
}
.myPolzynok::-ms-fill-lower {
background: #2a6495;
border: 0.2px solid #010101;
border-radius: 2.6px;
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
}
.myPolzynok::-ms-fill-upper {
background: #3071a9;
border: 0.2px solid #010101;
border-radius: 2.6px;
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
}
.myPolzynok::-ms-thumb {
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
border: 1px solid #000000;
height: 36px;
width: 16px;
border-radius: 3px;
background: #ffffff;
cursor: pointer;
}
.myPolzynok:focus::-ms-fill-lower {
background: #3071a9;
}
.myPolzynok:focus::-ms-fill-upper {
background: #367ebd;
}
.bestP {
color: red;
font-size: 20px !important;
text-shadow: 1px 0 0 #000, 0 -1px 0 #000, 0 1px 0 #000, -1px 0 0 #000;
}
thead.bestP td {
color: red;
border-bottom:1px solid black !important;
border-top:1px solid black !important;
font-size: 20px !important;
text-shadow: 1px 0 0 #000, 0 -1px 0 #000, 0 1px 0 #000, -1px 0 0 #000;
}
`;
document.getElementsByTagName('head')[0].appendChild(style);
}
function doGet(url, callback) {
let http = new XMLHttpRequest();
http.open("GET", url, true); // false for synchronous request
http.overrideMimeType("text/xml; charset=windows-1251");
http.onreadystatechange = function () {//Call a function when the state changes
if (http.readyState === 4 && http.status === 200) {
return callback(new DOMParser().parseFromString(http.responseText, "text/html"));
}
};
http.send(null);
}
})(window);