Automatically scores OTPs based on win rate, games, LP, and play rate
当前为
// ==UserScript==
// @name Onetricks.gg Score Calculation
// @namespace http://tampermonkey.net/
// @version 2.2
// @description Automatically scores OTPs based on win rate, games, LP, and play rate
// @author Joshinon
// @match https://www.onetricks.gg/*
// @grant none
// @run-at document-idle
// @license MIT
// ==/UserScript==
// NOTE: THIS IS AN UNOFFICIAL COMMUNITY EXTENSION. IT IS NOT CREATED, ENDORSED, OR SUPPORTED BY ONETRICKS.GG. PLEASE USE RESPONSIBLY.
(function() {
'use strict';
const POLL_INTERVAL = 300;
let headerAdded = false;
let table, tbody, headerRow;
let sortDirection = 'desc'; // default sort: high → low
let autoSortByScore = true;
let scoreHeaderCell;
function parseNumber(str) {
return parseFloat(str.replace(/[,%LP\s]/g, '').trim());
}
function init() {
table = document.querySelector("table");
if (!table) return false;
tbody = table.querySelector("tbody");
if (!tbody) return false;
const rows = Array.from(tbody.querySelectorAll("tr"));
if (!rows.length) return false;
headerRow = rows[0];
if (!headerAdded) {
scoreHeaderCell = document.createElement("td");
scoreHeaderCell.className = "score-header";
scoreHeaderCell.innerText = "Score ↓";
scoreHeaderCell.style.cursor = "pointer";
scoreHeaderCell.style.fontWeight = "bold";
scoreHeaderCell.style.userSelect = "none";
scoreHeaderCell.style.whiteSpace = "nowrap";
scoreHeaderCell.style.paddingLeft = "6px";
scoreHeaderCell.addEventListener("click", () => {
sortDirection = sortDirection === 'desc' ? 'asc' : 'desc';
scoreHeaderCell.innerText = sortDirection === 'desc' ? "Score ↓" : "Score ↑";
autoSortByScore = true;
calculateScores(true);
});
headerRow.appendChild(scoreHeaderCell);
const otherHeaders = headerRow.querySelectorAll("td:not(.score-header)");
otherHeaders.forEach(cell => {
cell.addEventListener("click", () => {
autoSortByScore = false;
if (scoreHeaderCell) scoreHeaderCell.innerText = "Score";
});
});
headerAdded = true;
}
return true;
}
function calculateScores(forceSort = false) {
if (!table && !init()) return;
const rows = Array.from(tbody.querySelectorAll("tr")).slice(1);
const scoredRows = [];
rows.forEach((row, index) => {
const cells = row.querySelectorAll("td");
if (cells.length < 12) return;
const playRate = parseNumber(cells[8]?.innerText || '');
const games = parseNumber(cells[9]?.innerText || '');
const winRate = parseNumber(cells[10]?.innerText || '');
const lp = parseNumber(cells[7]?.innerText || '');
if ([playRate, games, winRate, lp].some(isNaN)) return;
const reliability = 1 - Math.exp(-games / 250); // more games = more reliable score boost, full confidence at around 600 games
const winrateScore = Math.max(0, (winRate - 40) * 2); // every 5% winrate = +10 points
const lpScore = Math.min(lp * 0.012, 30); // 1.2 point every 100 lp, capped at 2500LP
const commitmentBonus = playRate >= 50 ? 5 : 0; // + flat 5 if playrate >= 50
const score = (winrateScore * reliability * 0.8)
+ (lpScore * 0.45)
+ commitmentBonus;
let scoreCell = row.querySelector(".score-cell");
if (!scoreCell) {
scoreCell = document.createElement("td");
scoreCell.className = "score-cell";
row.appendChild(scoreCell);
}
const roundedScore = score.toFixed(2);
scoreCell.innerText = roundedScore;
scoreCell.style.fontWeight = "bold";
scoreCell.style.color = playRate >= 50 ? "#00ff88" : "#ffffff";
row.dataset.score = roundedScore;
row.dataset.lp = lp;
row.dataset.index = index;
scoredRows.push(row);
});
if (!scoredRows.length) return;
if (!autoSortByScore && !forceSort) return;
const sorted = scoredRows.sort((a, b) => {
const scoreDiff = parseFloat(b.dataset.score) - parseFloat(a.dataset.score);
if (Math.abs(scoreDiff) > 0.0001)
return sortDirection === 'desc' ? scoreDiff : -scoreDiff;
const lpDiff = parseFloat(b.dataset.lp) - parseFloat(a.dataset.lp);
if (lpDiff !== 0)
return sortDirection === 'desc' ? lpDiff : -lpDiff;
return sortDirection === 'desc'
? a.dataset.index - b.dataset.index
: b.dataset.index - a.dataset.index;
});
const others = rows.filter(r => !scoredRows.includes(r));
const frag = document.createDocumentFragment();
frag.appendChild(headerRow);
sorted.forEach(r => frag.appendChild(r));
others.forEach(r => frag.appendChild(r));
tbody.innerHTML = '';
tbody.appendChild(frag);
}
setInterval(calculateScores, POLL_INTERVAL);
})();