您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Reorders certificates based on completion percentage and simplifies the interface
当前为
// ==UserScript== // @name Reorder Certificates // @namespace FarmRPGCertificates // @version 1.0.26 // @description Reorders certificates based on completion percentage and simplifies the interface // @author ClientCoin // @match *farmrpg.com/index.php // @match *farmrpg.com/ // @match *alpha.farmrpg.com/ // @match *alpha.farmrpg.com/index.php // @icon https://www.google.com/s2/favicons?sz=64&domain=farmrpg.com // @grant none // ==/UserScript== function reorderCertificates() { const locName = location.hash.slice(location.hash.search(/[^#!\/]/), location.hash.search(/.php/)) if (locName != "temple") { return; } //console.log("%c[Script] Reordering certificates...", "color: cyan; font-weight: bold;"); let allContentBlocks = document.querySelectorAll(".content-block"); let certificatesContainer = null; allContentBlocks.forEach(block => { let titleElement = block.querySelector(".content-block-title"); if (titleElement && titleElement.textContent.trim() === "Secret Chains") { certificatesContainer = block.querySelector(".list-block ul"); } }); if (!certificatesContainer) { console.warn("%c[Script] Certificates container not found. Exiting.", "color: red;"); return; } let certificateElements = Array.from(certificatesContainer.querySelectorAll("li")); if (certificateElements.length === 0) { console.warn("%c[Script] No certificate elements found. Exiting.", "color: red;"); return; } //console.log("%c[Script] Found certificate elements:", "color: cyan;", certificateElements); let certificateBlocks = certificateElements.map(certificate => { let progress = extractProgress(certificate); //console.log(`%c[Script] Extracted progress: ${progress}%`, "color: lightgreen;"); return { element: certificate, progress }; }); let completedCount = certificateBlocks.filter(c => c.progress === 100).length; let maxCount = certificateBlocks.length; // Sorting: Completed (100%) certificates at the bottom certificateBlocks.sort((a, b) => { // Move 100% completed items to the bottom if (a.progress === 100 && b.progress !== 100) return 1; if (b.progress === 100 && a.progress !== 100) return -1; // Sort by highest progress first let progressSort = b.progress - a.progress; if (progressSort !== 0) return progressSort; // If progress is the same, sort by itemsToGo (ascending) return a.itemsToGo - b.itemsToGo; }); //console.log("%c[Script] Certificates sorted by progress.", "color: cyan;"); certificatesContainer.innerHTML = ""; // Clear the list // Insert summary at the top let summaryElement = document.createElement("li"); summaryElement.innerHTML = ` <div style="font-weight: bold; color: gold; text-align: center; padding: 5px;"> ${completedCount}/${maxCount} Certificates COMPLETE </div> `; certificatesContainer.appendChild(summaryElement); // Append reordered certificates certificateBlocks.forEach(({ element }) => { simplifyText(element); certificatesContainer.appendChild(element); }); console.log("Certificates reordered and updated."); } function extractProgress(element) { let titleElement = element.querySelector(".item-title"); if (!titleElement) { console.warn("%c[Script] Title element not found in certificate block.", "color: orange;"); return 0; } // Extract sacrificed and required item counts let progressMatch = titleElement.innerText.match(/(\d{1,3}(?:,\d{3})*) \/ (\d{1,3}(?:,\d{3})*) Items Sacrificed/); if (!progressMatch) { console.warn("%c[Script] No progress values found in:", "color: orange;", titleElement.innerText); return 0; } let sacrificed = parseInt(progressMatch[1].replace(/,/g, '')); // Remove commas let required = parseInt(progressMatch[2].replace(/,/g, '')); // Calculate precise percentage let progress = (sacrificed / required) * 100; //console.log(`%c[Script] Corrected progress: ${progress.toFixed(2)}% (${sacrificed}/${required})`, "color: lightgreen;"); return progress; } function simplifyText(element) { let titleElement = element.querySelector(".item-title"); let imgElement = element.querySelector(".item-media img"); if (!titleElement) { console.warn("%c[Script] Title element not found in certificate block.", "color: orange;"); return; } if (element.classList.contains("row")) { element.style.marginBottom = "0px"; } /* element.style.padding = "1px 0"; // Reduce vertical padding element.style.margin = "2px"; // Remove margins element.style.lineHeight = "0"; // Reduce space between lines let itemInner = element.querySelector(".item-inner"); if (itemInner) { itemInner.style.padding = "1px 0"; } let itemTitle = element.querySelector(".item-title"); if (itemTitle) { itemTitle.style.margin = "0"; } */ let nameMatch = titleElement.innerText.match(/Certificate of (.+?) Giving/); let progressMatch = titleElement.innerText.match(/(\d+(?:,\d+)?) \/ (\d+(?:,\d+)?) Items Sacrificed/); let onHandMatch = titleElement.innerText.match(/Sacrifice: (.+?) \(You have (\d+(?:,\d+)?)\)/); if (nameMatch && progressMatch && onHandMatch) { let itemName = nameMatch[1]; let totalRequired = parseInt(progressMatch[2].replace(/,/g, '')); let sacrificed = parseInt(progressMatch[1].replace(/,/g, '')); let onHand = parseInt(onHandMatch[2].replace(/,/g, '')); let itemsToGo = totalRequired - sacrificed; let progressPercent = (sacrificed / totalRequired) * 100; let color = "white"; if (itemsToGo === 0) color = "gold"; else if (progressPercent >= 75) color = "lightgreen"; else if (sacrificed < 10000) color = "grey"; let nn = "COMPLETE"; let outputPad = itemsToGo === 0 ? `${nn.toLocaleString().padStart(13, '\u00A0')} [${onHand.toLocaleString().padStart(7, '\u00A0')} on hand]` : `${itemsToGo.toLocaleString().padStart(7, '\u00A0')} to go [${onHand.toLocaleString().padStart(7, '\u00A0')} on hand]` let textContent = `<span style="color: ${color};"> <div style="display:flex;flex-flow:row nowrap;align-items:center;vertical-align:middle;margin-top:auto;margin-bottom:auto;"> <div style="width:20%;text-align:left;">${itemName}: </div> <div style="width:80%;text-align:left;">${outputPad}</div> </div> </span>`; titleElement.outerHTML = `<span style="font-family: monospace; width: 100%">${textContent}</span>`; if (imgElement) { imgElement.style.width = "1rem"; imgElement.style.height = "1rem"; } let smallImgElement = element.querySelector(".item-after img"); if (smallImgElement) { smallImgElement.style.width = "1rem"; smallImgElement.style.height = "1rem"; } //console.log(`%c[Script] Updated text for ${itemName}: ${itemsToGo} to go, ${onHand} on hand.`, "color: lightblue;"); } else { console.warn("%c[Script] Failed to extract data for certificate text update.", "color: orange;"); } } function init() { //console.log("%c[Script] Initializing...", "color: green;"); reorderCertificates(); injectCSS(); } window.addEventListener("load", init); // Ensures the script runs only once function injectCSS() { const style = document.createElement('style'); style.innerHTML = ` .list-block .item-content { min-height: 0 !important; } .list-block .item-inner { min-height: 0 !important; } `; document.head.appendChild(style); } $(document).ready( () => { const target = document.querySelector("#fireworks") const observer = new MutationObserver( mutation => {if (mutation[0]?.attributeName == "data-page") reorderCertificates()} ) const config = { attributes: true, childlist: true, subtree: true } observer.observe(target, config); const observera = new MutationObserver(() => { reorderCertificates(); }); })