您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Fair Game QOL Enhancements
// ==UserScript== // @name Fair Game QoL v1 // @namespace https://fair.kaliburg.de/# // @version 0.500 // @description Fair Game QOL Enhancements // @author Aqualxx // @match https://fair.kaliburg.de/ // @include *kaliburg.de* // @run-at document-end // @icon https://www.google.com/s2/favicons?domain=kaliburg.de // @grant unsafeWindow // @license MIT // ==/UserScript== // Script made by aqualxx#5004 and maintained by Lynn#6969 // Features include: // Larger ladder size // Indicators // Keybinds // 🍇🍇🍇 // Time estimates ////////////////////// // Options // ////////////////////// if (typeof unsafeWindow !== 'undefined') { window = unsafeWindow; } window.qolOptions = { expandedLadder: { enabled: false, size: 30 }, scrollableLadder: false, keybinds: false, scrollablePage: false, promotePoints: true, multiLeader: { "default": "Both", // <--- Change this value to save between refreshs "Disabled": false, "Both": "[NUMBER xSTATUS]", "Square": "[xSTATUS]", "Number": "[NUMBER]", }, } ////////////////////////////////////// // DO NOT EDIT BEYOND HERE // ////////////////////////////////////// window.subscribeToDomNode = function(id, callback) { let input = $("#"+id)[0]; if (input) { input.addEventListener("change", callback); } else { console.log(`Id ${id} was not found subscribing to change events`); } } document.addEventListener("keyup", event => { if (!qolOptions.keybinds) return; if (!event.target.isEqualNode($("body")[0])) return; if (event.key === "b") { event.preventDefault() //buyBias(event); } if (event.key === "m") { event.preventDefault(); //buyMulti(event); } }); if (qolOptions.expandedLadder.enabled) { $('#infoText').parent().parent().removeClass('col-7').addClass('col-12'); $('#infoText').parent().parent().next().hide(); } clientData.ladderAreaSize = 1; $('body').css("line-height", 1); clientData.ladderPadding = qolOptions.expandedLadder.size / 2; function addTableColumns() { $("#ladderBody").parent().find("thead").html(` <tr class="thead-light"> <th>#</th> <th>Stats</th> <th>Username</th> <th class="text-end">Power</th> <th class="text-end">ETA to #1</th> <th class="text-end">ETA to You</th> <th class="text-end">Points</th> </tr> `); } addTableColumns(); numberFormatter = new numberformat.Formatter({ format: 'hybrid', sigfigs: 6, flavor: 'short', minSuffix: 1e10, maxSmall: 0 }); window.secondsToHms = function(d) { d = Number(d); if (d === 0) return "0s"; var h = Math.floor(d / 3600); var m = Math.floor(d % 3600 / 60); let s = d % 3600 % 60; if (h == 0 && m == 0 && s !== 0 && Math.abs(s) < 1) { return "<1s"; } else { s = Math.floor(s); } var hDisplay = h > 0 ? h + "h " : ""; var mDisplay = m > 0 ? m + "m " : ""; var sDisplay = s > 0 ? s + "s " : ""; return hDisplay + mDisplay + sDisplay; } // returns positive minimal positive solution or "Inf" window.solveQuadratic = function(a, b, c) { if (a == 0) { return -c / b > 0 ? (-c / b).toFixed(2) : "Inf"; } else { let discriminant = b * b - 4 * a * c; if (discriminant < 0) return "Inf"; const root1 = (-b + Math.sqrt(discriminant)) / (2 * a); const root2 = (-b - Math.sqrt(discriminant)) / (2 * a); if (root1 > 0 && root2 > 0) { return Math.min(root1, root2).toFixed(2); } else { let maxRoot = Math.max(root1, root2).toFixed(2); if (maxRoot < 0) return "Inf"; else return maxRoot; } } } window.getAcc = function(ranker) { if (ranker.rank === 1 || !ranker.growing) return 0; return (ranker.bias + ranker.rank - 1) * ranker.multiplier; } window.writeNewRow = function(body, ranker) { let row = body.insertRow(); const myAcc = getAcc(ladderData.yourRanker); const theirAcc = getAcc(ranker); const a = (theirAcc - myAcc) * 0.5; const b = (ranker.growing ? ranker.power : 0) - ladderData.yourRanker.power; const c = ranker.points - ladderData.yourRanker.points; let timeLeft = solveQuadratic(a, b, c); timeLeft = secondsToHms(timeLeft); if (timeLeft == '') { timeLeft = "Never"; } const pointsToFirst = ladderData.firstRanker.points.sub(ranker.points); const firstPowerDifference = ranker.power - (ladderData.firstRanker.growing ? ladderData.firstRanker.power : 0); const pointsLeftPromote = infoData.pointsForPromote.mul(ladderData.currentLadder.number) - ranker.points; let timeToFirst = ""; if (ladderData.firstRanker.points.lessThan(infoData.pointsForPromote.mul(ladderData.currentLadder.number))) { // Time to reach minimum promotion points of the ladder timeToFirst = 'L' + secondsToHms(solveQuadratic(theirAcc/2, ranker.power, -pointsLeftPromote)); } else { // time to reach first ranker timeToFirst = secondsToHms(solveQuadratic(theirAcc/2, firstPowerDifference, -pointsToFirst)); } if (!ranker.growing || (ranker.rank === 1 && ladderData.firstRanker.points.greaterThan(infoData.pointsForPromote.mul(ladderData.currentLadder.number)))) timeToFirst = ""; if (ladderData.yourRanker.rank == ranker.rank) { timeLeft = ""; } let assholeTag = (ranker.timesAsshole < infoData.assholeTags.length) ? infoData.assholeTags[ranker.timesAsshole] : infoData.assholeTags[infoData.assholeTags.length - 1]; let rank = (ranker.rank === 1 && !ranker.you && ranker.growing && ladderData.rankers.length >= Math.max(infoData.minimumPeopleForPromote, ladderData.currentLadder.number) && ladderData.firstRanker.points.cmp(infoData.pointsForPromote.mul(ladderData.currentLadder.number)) >= 0 && ladderData.yourRanker.vinegar.cmp(getVinegarThrowCost()) >= 0) ? '<a href="#" style="text-decoration: none" onclick="throwVinegar(event)">🍇</a>' : ranker.rank; let multiPrice = "" if ((ranker.rank === 1 && ranker.growing) && qolOptions.multiLeader[$("#leadermultimode")[0].value]) { multiPrice = qolOptions.multiLeader[$("#leadermultimode")[0].value] .replace("NUMBER",`${numberFormatter.format(Math.pow(ladderData.currentLadder.number+1, ranker.multiplier+1))}`) .replace("STATUS", `${(ranker.power >= Math.pow(ladderData.currentLadder.number+1, ranker.multiplier+1)) ? "🟩" : "🟥"}`) } row.insertCell(0).innerHTML = rank + " " + assholeTag; row.insertCell(1).innerHTML = `[+${ranker.bias.toString().padStart(2,"0")} x${ranker.multiplier.toString().padStart(2,"0")}]`; row.insertCell(2).innerHTML = `${ranker.username}`; row.cells[2].style.overflow = "hidden"; row.insertCell(3).innerHTML = `${multiPrice} ${numberFormatter.format(ranker.power)} ${ranker.growing ? ranker.rank != 1 ? "(+" + numberFormatter.format((ranker.rank - 1 + ranker.bias) * ranker.multiplier) + ")" : "" : "(Promoted)"}`; row.cells[3].classList.add('text-end'); row.insertCell(4).innerHTML = timeToFirst; row.cells[4].classList.add('text-end'); row.insertCell(5).innerHTML = timeLeft; row.cells[5].classList.add('text-end'); row.insertCell(6).innerHTML = `${numberFormatter.format(ranker.points)}`; row.cells[6].classList.add('text-end'); if (ranker.you) { row.classList.add('table-active'); } else if (!ranker.growing) { row.style['background-color'] = "#C0C0C0"; } else if ((ranker.rank < ladderData.yourRanker.rank && timeLeft != 'Never') || (ranker.rank > ladderData.yourRanker.rank && timeLeft == 'Never')) { row.style['background-color'] = "#A0EEA0"; } else if ((ranker.rank < ladderData.yourRanker.rank && timeLeft == 'Never') || (ranker.rank > ladderData.yourRanker.rank && timeLeft != 'Never')) { row.style['background-color'] = "#EEA0A0"; } } window.updateLadder = function() { let size = ladderData.rankers.length; let rank = ladderData.yourRanker.rank; let ladderArea = Math.floor(rank / clientData.ladderAreaSize); let startRank = (ladderArea * clientData.ladderAreaSize) - clientData.ladderPadding; let endRank = startRank + clientData.ladderAreaSize - 1 + (2 * clientData.ladderPadding); let body = document.getElementById("ladderBody"); body.innerHTML = ""; if (startRank > 1) writeNewRow(body, ladderData.firstRanker); for (let i = 0; i < ladderData.rankers.length; i++) { let ranker = ladderData.rankers[i]; if ((ranker.rank >= startRank && ranker.rank <= endRank)) writeNewRow(body, ranker); } let tag1 = '<span>', tag2 = '</span>'; if (ladderData.yourRanker.vinegar.cmp(getVinegarThrowCost()) >= 0) { tag1 = '<span style="color: plum">' tag2 = '</span>' } let grapesTimeLeft = secondsToHms((getVinegarThrowCost() - ladderData.yourRanker.vinegar) / ladderData.yourRanker.grapes); const fillsPerHour = (new Decimal(3600)).div(getVinegarThrowCost().div(ladderData.yourRanker.grapes)); if (grapesTimeLeft == '') { if (ladderData.yourRanker.grapes > 0) { grapesTimeLeft = "0s"; } else { grapesTimeLeft = "infinite time"; } } $('#infoText').html(`<p>Grapes: ${numberFormatter.format(ladderData.yourRanker.grapes)}<\p>`+ `<p>${tag1} Vinegar: ${numberFormatter.format(ladderData.yourRanker.vinegar)}/${numberFormatter.format(getVinegarThrowCost())} (+${numberFormatter.format(ladderData.yourRanker.grapes)} per/s) ${tag2}<\p>`+ `<p>There is ${grapesTimeLeft} left until you can throw vinegar at #1, fills per hour: ` + fillsPerHour.toFixed(2) + "<\p><p><br><br><br><\p>"); $('#usernameLink').html(ladderData.yourRanker.username); $('#usernameText').html("+" + ladderData.yourRanker.bias + " x" + ladderData.yourRanker.multiplier); $('#rankerCount').html("Rankers: " + ladderStats.growingRankerCount + "/" + ladderData.rankers.length); $('#ladderNumber').html("Ladder # " + ladderData.currentLadder.number); if (qolOptions.promotePoints) { $('#manualPromoteText').show() $('#manualPromoteText').html("Points needed for " + ((ladderData.currentLadder.number === infoData.assholeLadder) ? "being an asshole" : "manually promoting") + ": " + numberFormatter.format(ladderStats.pointsNeededForManualPromote)); } else { $('#manualPromoteText').hide() } let offCanvasBody = $('#offCanvasBody'); offCanvasBody.empty(); for (let i = 1; i <= ladderData.currentLadder.number; i++) { let ladder = $(document.createElement('li')).prop({ class: "nav-link" }); let ladderLinK = $(document.createElement('a')).prop({ href: '#', innerHTML: 'Chad #' + i, class: "nav-link h5" }); ladderLinK.click(async function () { changeChatRoom(i); }) ladder.append(ladderLinK); offCanvasBody.prepend(ladder); } showButtons(); } window.showButtons = function() { let biasButton = $('#biasButton'); let multiButton = $('#multiButton'); let biasCost = getUpgradeCost(ladderData.yourRanker.bias + 1); if (ladderData.yourRanker.points.cmp(biasCost) >= 0) { biasButton.prop("disabled", false); } else { biasButton.prop("disabled", true); } let multiCost = getUpgradeCost(ladderData.yourRanker.multiplier + 1); if (ladderData.yourRanker.power.cmp(new Decimal(multiCost)) >= 0) { multiButton.prop("disabled", false); } else { multiButton.prop("disabled", true); } const myAcc = getAcc(ladderData.yourRanker); let nextMultiTime = ladderData.yourRanker.power.lessThan(multiCost) ? (multiCost-ladderData.yourRanker.power)/myAcc : 0; // Payback is the time it takes for the difference between new and old growth functions to gain current points. // Rank changes are not taken into account so this estimate is conservative. // For multi payback you will need to solve accel_diff / 2 * t^2 - power * t - points = 0 let nextMultiPayback = 0; if (nextMultiTime > 0) { // If you don't have the required power calculate cost with future values const targetPoints = ladderData.yourRanker.points.add(ladderData.yourRanker.power.times(nextMultiTime)).add(myAcc * myAcc * nextMultiTime / 2); nextMultiPayback = solveQuadratic((ladderData.yourRanker.rank - 1 + ladderData.yourRanker.bias)/2, -multiCost, -targetPoints); } else { nextMultiPayback = solveQuadratic((ladderData.yourRanker.rank - 1 + ladderData.yourRanker.bias)/2, -ladderData.yourRanker.power, -ladderData.yourRanker.points); } nextMultiTime = secondsToHms(nextMultiTime); nextMultiPayback = secondsToHms(nextMultiPayback); let nextBiasTime = ladderData.yourRanker.points.lessThan(biasCost) ? solveQuadratic(myAcc/2, ladderData.yourRanker.power, -biasCost) : 0; // For bias payback you will need to solve accel_diff / 2 * t^2 - points = 0 let nextBiasPayback = 0; if (nextBiasTime > 0) { // If you don't have the required points calculate cost with future value nextBiasPayback = solveQuadratic(ladderData.yourRanker.multiplier/2, 0, -biasCost); } else { nextBiasPayback = solveQuadratic(ladderData.yourRanker.multiplier/2, 0, -ladderData.yourRanker.points); } nextBiasTime = secondsToHms(nextBiasTime); nextBiasPayback = secondsToHms(nextBiasPayback); $('#biasTooltip').attr('data-bs-original-title', `${nextBiasTime}/${nextBiasPayback} ` + numberFormatter.format(biasCost) + ' Points'); $('#multiTooltip').attr('data-bs-original-title', `${nextMultiTime}/${nextMultiPayback} ` + numberFormatter.format(multiCost) + ' Power'); let promoteButton = $('#promoteButton'); let assholeButton = $('#assholeButton'); let ladderNumber = $('#ladderNumber'); if (ladderData.firstRanker.you && ladderData.firstRanker.points.cmp(ladderStats.pointsNeededForManualPromote) >= 0) { if (ladderData.currentLadder.number === infoData.assholeLadder) { promoteButton.hide() ladderNumber.hide() assholeButton.show() } else { assholeButton.hide() ladderNumber.hide() promoteButton.show() } } else { assholeButton.hide() promoteButton.hide() ladderNumber.show() } // Auto-Promote Button let autoPromoteButton = $('#autoPromoteButton'); let autoPromoteTooltip = $('#autoPromoteTooltip'); let autoPromoteCost = getAutoPromoteGrapeCost(ladderData.yourRanker.rank); if (!ladderData.yourRanker.autoPromote && ladderData.currentLadder.number >= infoData.autoPromoteLadder && ladderData.currentLadder.number !== infoData.assholeLadder) { autoPromoteButton.show(); if (ladderData.yourRanker.grapes.cmp(autoPromoteCost) >= 0) { autoPromoteButton.prop("disabled", false); } else { autoPromoteButton.prop("disabled", true); } autoPromoteTooltip.attr('data-bs-original-title', numberFormatter.format(autoPromoteCost) + ' Grapes'); } else { autoPromoteButton.hide(); } } window.setLadderRows = function() { var input = Number($("#rowsInput")[0].value); if (isNaN(input)) { $("#rowsInput")[0].value = ''; return; } if (input < 10) { $("#rowsInput")[0].value = '10'; return; } qolOptions.expandedLadder.size = input; clientData.ladderPadding = qolOptions.expandedLadder.size / 2; } window.expandLadder = function(enabled) { var ladder = document.querySelector(".ladder-container"); if (!enabled && ladder) { ladder.outerHTML = ladder.innerHTML; return; } if (document.getElementsByClassName("ladder-container").length > 0) { return; } if(!enabled) { return; } var ladder = document.querySelector(".caption-top"); var ladderParent = ladder.parentElement; var ladderContainer = document.createElement("div"); ladderContainer.className = "ladder-container"; ladderContainer.style.width = "100%"; ladderContainer.style.height = "64vh"; ladderContainer.style.overflow = "auto"; ladderContainer.style.border = "gray solid 2px"; ladderParent.replaceChild(ladderContainer, ladder); ladderContainer.appendChild(ladder); } window.addOption = function(optionElement) { $("#offcanvasOptions").children(".offcanvas-body")[0].appendChild(optionElement); } window.addOptionDevider = function() { var optionElement = document.createElement("hr"); addOption(optionElement); } window.addNewSection = function(name) { addOptionDevider(); var optionElement = document.createElement("h4"); optionElement.innerHTML = name; addOption(optionElement); } window.baseOptionDiv = function(content = "") { var newDiv = document.createElement("div"); newDiv.style = "display: block; padding: 0.5rem; font-size:1.25rem" newDiv.innerHTML = content; return newDiv; } window.ButtonOption = function(name, id) { var newDiv = baseOptionDiv(); var button = document.createElement("button"); button.className = "btn btn-primary"; button.innerHTML = name; button.id = id; newDiv.appendChild(button); return newDiv; } window.SliderOption = function(name, id, min, max, step, value) { var newDiv = baseOptionDiv(); var slider = document.createElement("input"); slider.type = "range"; slider.min = min; slider.max = max; slider.step = step; slider.value = value; slider.style = "width: 100%"; slider.id = id; var sliderLabel = document.createElement("label"); slider.oninput = function() { sliderLabel.innerHTML = name + ": " + slider.value; } sliderLabel.innerHTML = name + ": " + slider.value; newDiv.appendChild(sliderLabel); newDiv.appendChild(slider); return newDiv; } window.SelectOption = function(title, id, values) { //values is an array of objects with display and value properties return baseOptionDiv (`<span>${title}</span> <select name="fonts" id="${id}" class="form-select"> ${values.map(function(value) { return `<option value="${value.value}">${value.display}</option>` }).join("")} </select>`); } window.TextInputOption = function(title, id, placeholder, maxlength, onclick) { return baseOptionDiv (`<span>${title}</span> <div class="input-group"> <input class="form-control shadow-none" id="${id}" maxlength="${maxlength}" placeholder="${placeholder}" type="text"> <button class="btn btn-primary shadow-none" id="rowsButton" onclick="${onclick}">Set</button> </div>`); } window.CheckboxOption = function(title, optionID, defaultChecked=false) { return baseOptionDiv(`<input type="checkbox" ${defaultChecked?"checked='checked'" : ""} id="${optionID}"><span style="padding: 10px">${title}</span>`); } // Holy crap this took me way too long $(".navbar-toggler")[0].style['border-color'] = "rgba(0,0,0,0.5)"; $(".navbar-toggler")[0].style['width'] = "5%"; $(`<button aria-controls="offcanvasNavbar" class="navbar-toggler" data-bs-target="#offcanvasOptions" data-bs-toggle="offcanvas" type="button col" style="border-color: rgba(0, 0, 0, 0.5); width: 5%; height: 40px;"><span class="bi bi-gear-fill fs-3 mb-3"></span></button>`).insertBefore(".navbar-toggler"); $("#offcanvasNavbar").clone().attr("id", "offcanvasOptions").width("400px").insertAfter("#offcanvasNavbar"); $("#offcanvasOptions").children(".offcanvas-header").children("#offcanvasNavbarLabel").html("Options"); $("#offcanvasOptions").children(".offcanvas-body").children().remove(); addOption(SelectOption("Ladder Font", "ladderFonts", [ {display: "Default", value: ""}, {display: "BenchNine", value: "BenchNine"}, {display: "Roboto", value: "Roboto"}, {display: "Lato", value: "Lato"}, ])) addOption(TextInputOption("Ladder Rows", "rowsInput", "# of rows, min 10, default 30", "4", "setLadderRows()")) addOption(CheckboxOption("Full scrollable ladder", "scrollableLadder", qolOptions.scrollableLadder)) addOption(CheckboxOption("Expand ladder size", "expandedLadder", qolOptions.expandedLadder.enabled)) //addOption(CheckboxOption("Keybinds", "keybinds", qolOptions.keybinds)) addOption(CheckboxOption("Make page scrollable", "scrollablePage", qolOptions.scrollablePage)) addOption(CheckboxOption("Show points for promotion", "promotePoints", qolOptions.promotePoints)) addOption(SelectOption("Leader Multi Requirement", "leadermultimode", [ {display: "[524288 x🟩]", value: "Both"}, {display: "[x🟩 / x🟥]", value: "Square"}, {display: "[524288]", value: "Number"}, {display: "Disabled", value: "Disabled"}, ])) if (qolOptions.scrollablePage) document.body.style.removeProperty('overflow-y'); if (qolOptions.scrollableLadder) expandLadder(true) $("#leadermultimode")[0].value = qolOptions.multiLeader["default"] $("#expandedLadder")[0].addEventListener("change", (event)=>{ let boxChecked = $("#expandedLadder")[0].checked; qolOptions.expandedLadder.enabled = boxChecked; if (boxChecked) { $('#infoText').parent().parent().removeClass('col-7').addClass('col-12'); $('#infoText').parent().parent().next().hide(); } else { $('#infoText').parent().parent().addClass('col-7').removeClass('col-12'); $('#infoText').parent().parent().next().show(); } }); $("#scrollablePage")[0].addEventListener("change", (event)=>{ let boxChecked = $("#scrollablePage")[0].checked; qolOptions.scrollablePage = boxChecked; if (boxChecked) { document.body.style.removeProperty('overflow-y'); } else { document.body.style.setProperty('overflow-y', 'hidden'); } }); $("#scrollableLadder")[0].addEventListener("change", (event)=>{ let boxChecked = $("#scrollableLadder")[0].checked; qolOptions.scrollableLadder = boxChecked; expandLadder(qolOptions.scrollableLadder) }) function updateOptions(id, option) { let input = $("#"+id)[0]; if (input) { input.addEventListener("change", (event)=>{ let boxChecked = $("#"+id)[0].checked; qolOptions[option] = boxChecked; }); } else { console.log(`Id ${id} was not found when linking options`); } } updateOptions('promotePoints','promotePoints'); var linkTag = document.createElement('link'); linkTag.rel = "stylesheet"; linkTag.href = "https://fonts.googleapis.com/css2?family=BenchNine:wght@400&display=swap" document.body.appendChild(linkTag); document.querySelector("#ladderFonts").addEventListener('change',function(){ var input = document.querySelector("#ladderFonts").value; switch (input) { case "BenchNine": $("table.table.table-sm.caption-top.table-borderless").css("font-family","'BenchNine', sans-serif"); break; case "Roboto": $("table.table.table-sm.caption-top.table-borderless").css("font-family","'Roboto', sans-serif"); break; case "Lato": $("table.table.table-sm.caption-top.table-borderless").css("font-family","'Lato', sans-serif"); break; default: $("table.table.table-sm.caption-top.table-borderless").css("font-family",""); break; } });