您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a gold indicator to items in the Locksmith and shows the total gold available.
// ==UserScript== // @name Farm RPG Locksmith Gold Indicator // @version 1.0.26 // @description Adds a gold indicator to items in the Locksmith and shows the total gold available. // @author ClientCoin // @icon https://www.google.com/s2/favicons?sz=64&domain=farmrpg.com // @match *://*farmrpg.com/index.php* // @match *://*farmrpg.com/ // @match *://*alpha.farmrpg.com/index.php* // @match *://*alpha.farmrpg.com/ // @grant none // @license MIT // @namespace whatisthisok // ==/UserScript== 'use strict'; // Set to a bitwise sum of desired flags: 1=Errors, 2=Info, 4=Container search details, 8=Detailed item processing. const DEBUG_LEVEL = 0; const DEBUG_ERRORS = 1; const DEBUG_INFO = 2; const DEBUG_CONTAINER_SEARCH = 4; const DEBUG_ITEM_PROCESSING = 8; /** * Custom logging function that checks against the DEBUG_LEVEL bitfield. * @param {string} message - The message to log. * @param {number} level - The log level flag (e.g., DEBUG_ERRORS, DEBUG_INFO). * @param {*} [data=null] - Optional data to log with the message. */ function logDebug(message, level, data = null) { if ((DEBUG_LEVEL & level) === level) { if (data !== null) { console.log(`[Locksmith Gold] ${message}`, data); } else { console.log(`[Locksmith Gold] ${message}`); } } } // A map of item names to the amount of gold they contain. const GOLD_ITEMS = { "Thomas's Tavern Tote": 25, "Stack of Cards": 25, "Pot of Gold (Large)": 50, "Pot of Gold (Small)": 10, "Cornucopia": 25, "Box of Chocolate 01": 25, "Spring Basket 01": 25, "frank's Basket": 25, "Summer Basket": 25, "Christmas Present 01": 50, "Present 02": 50, "Backpack": 25, "Fall Basket": 25, "Treat Bag 04": 25, "Cornucopia 01": 25, "Lovely Present": 25, "Winter Basket": 25, "Box Of Chocolate 02": 25, "Holger's Lunch Box": 25, "Beatrix's Big Box of Boom": 25, "Buddy's School Bag": 25, "Apple Basket": 25, "Treat Bag 05": 25, "Cornucopia 02": 25, "Fancy Present": 25, "Frozen Chest 01": 25, "Heart-shaped Box 01": 25, "Green Backpack": 85, "Pot of Gold (Medium)": 25, "Magical Chest 01": 25, "Rosalie's Beach Tote": 25, "Beatrix's Booming Brawl Box 01": 25, "Beatrix's Booming Brawl Box 02": 25, "Baba's Snack Pack": 25, "Apple Crate 01": 25, "Apple Crate 02": 25, "Treat Bag 06": 25, "Shiny Present": 25, "Frozen Chest 02": 25, "Heart-Shaped Box 02": 25, "Spring Basket 02": 25, "Magical Chest 02": 25, "Buddy's Beach Bag": 25, "Beatrix's Booming Brawl Box 02": 25, // New items added below "5 Gold": 5, "50 Gold": 50, "10 Gold": 10, "25 Gold": 25, "100 Gold": 100, }; const GOLD_EMOJI = '💰'; const PROCESSED_ATTRIBUTE = 'data-fpgi-processed'; const processedItems = new Set(); /** * Main function that orchestrates the entire process. * This is called by the MutationObserver when a relevant page change occurs. */ function addGoldIndicatorsToLocksmith() { logDebug("Executing main script function for Locksmith page.", DEBUG_INFO); // Step 1: Clean up any previous indicators to avoid duplicates on refresh. const oldTotalIndicator = document.getElementById('total-gold-indicator'); if (oldTotalIndicator) { oldTotalIndicator.remove(); logDebug("🗑️ Removed old total gold indicator from previous run.", DEBUG_INFO); } const oldTotalIndicatorFooter = document.getElementById('total-gold-indicator-footer'); if (oldTotalIndicatorFooter) { oldTotalIndicatorFooter.remove(); logDebug("🗑️ Removed old footer total gold indicator from previous run.", DEBUG_INFO); } document.querySelectorAll(`[${PROCESSED_ATTRIBUTE}]`).forEach(el => { el.removeAttribute(PROCESSED_ATTRIBUTE); const oldIndivIndicator = el.querySelector('.individual-gold-indicator'); if(oldIndivIndicator) { oldIndivIndicator.remove(); } // Remove the highlight class from any old items el.style.border = ''; el.style.boxShadow = ''; const titleElement = el.querySelector('.item-title strong'); if (titleElement) { titleElement.style.color = ''; } }); processedItems.clear(); logDebug("✅ Cleaned up old indicators and reset processed flags.", DEBUG_INFO); // Step 2: Find all items that can be opened on the locksmith page. const locksmithItems = document.querySelectorAll('.page[data-page="locksmith"] .list-block:not(.searchbar-not-found) .item-content'); if (locksmithItems.length === 0) { logDebug("No locksmith items found in the current view.", DEBUG_INFO); return; } logDebug(`🔍 Found ${locksmithItems.length} potential items to process.`, DEBUG_INFO); let totalGold = 0; // Step 3: Loop through each item, check for gold, and add an indicator. locksmithItems.forEach((item, index) => { logDebug(`Processing item at index ${index}.`, DEBUG_ITEM_PROCESSING); const itemNameElement = item.querySelector('.item-title strong'); if (itemNameElement) { const itemName = itemNameElement.textContent.trim(); const cleanName = itemName.replace(/\s*\((\d+,?\d*)\)|\s*(\(\d+,\d+\)|\s*\(\d+\))$/, '').trim(); logDebug(`🔎 Extracted item name: "${cleanName}"`, DEBUG_ITEM_PROCESSING); let quantity = 1; const quantityMatch = itemName.match(/\((\d+,?\d*)\)/); if (quantityMatch) { quantity = parseInt(quantityMatch[1].replace(/,/g, ''), 10); } logDebug(`🔢 Item quantity detected as: ${quantity}`, DEBUG_ITEM_PROCESSING); if (GOLD_ITEMS[cleanName]) { const goldAmount = GOLD_ITEMS[cleanName]; const totalItemGold = goldAmount * quantity; logDebug(`✨ Found a match! "${cleanName}" contains ${goldAmount} gold each. Total for this item: ${totalItemGold}.`, DEBUG_ITEM_PROCESSING); // Only count for global total if we haven't seen this item before if (!processedItems.has(cleanName)) { totalGold += totalItemGold; processedItems.add(cleanName); logDebug(`➕ Adding to total gold. Current total: ${totalGold}.`, DEBUG_INFO); } else { logDebug(`⚠️ Item "${cleanName}" already counted for global total. Skipping.`, DEBUG_INFO); } // Visual enhancements item.style.border = '2px solid goldenrod'; item.style.boxShadow = '0 0 5px goldenrod, inset 0 0 5px goldenrod'; itemNameElement.style.color = 'goldenrod'; const goldIndicator = document.createElement('span'); goldIndicator.classList.add('individual-gold-indicator'); goldIndicator.innerHTML = ` <span style="font-size: 11px; color: goldenrod;">(${totalItemGold.toLocaleString()}${GOLD_EMOJI})</span>`; itemNameElement.appendChild(goldIndicator); } else { logDebug(`🤷 No gold amount defined for item: "${cleanName}".`, DEBUG_ITEM_PROCESSING); } } else { logDebug(`❌ No 'strong' tag found within item-title for item at index ${index}, skipping.`, DEBUG_ERRORS); } item.setAttribute(PROCESSED_ATTRIBUTE, 'true'); }); // Step 4: Find the specific warning card and add the total gold indicator. const warningCardInner = document.querySelector('.page[data-page="locksmith"] .card.searchbar-found .card-content-inner'); if (totalGold > 0 && warningCardInner) { logDebug(`💰 Final calculated total gold is: ${totalGold.toLocaleString()}.`, DEBUG_INFO); const totalIndicatorHTML = `<p id="total-gold-indicator" style="text-align: center; font-size: 1.2em; font-weight: bold; margin-bottom: 10px; color: goldenrod;">${GOLD_EMOJI} **Total Gold Available: ${totalGold.toLocaleString()}** ${GOLD_EMOJI}</p>`; const totalIndicatorElement = document.createElement('div'); totalIndicatorElement.innerHTML = totalIndicatorHTML; const totalIndicatorElementFooter = document.createElement('div'); totalIndicatorElementFooter.innerHTML = totalIndicatorHTML; totalIndicatorElementFooter.querySelector('#total-gold-indicator').id = 'total-gold-indicator-footer'; // Insert at the beginning and the end of the warning card content. warningCardInner.prepend(totalIndicatorElement); warningCardInner.append(totalIndicatorElementFooter); logDebug("➕ Added new total gold indicator to the warning card.", DEBUG_INFO); } else { logDebug("📉 No gold-containing items found, or the warning card container could not be located. Skipping total indicator.", DEBUG_INFO); } } // Global scope logic for initialization const target = document.querySelector("#fireworks"); if (target) { logDebug("✅ Target element '#fireworks' found.", DEBUG_INFO); const observer = new MutationObserver(mutations => { logDebug("MutationObserver triggered by a DOM change.", DEBUG_INFO); for (const mutation of mutations) { if (mutation.attributeName === "data-page") { const newPage = target.getAttribute("data-page"); logDebug(`Page change detected. New page is: '${newPage}'`, DEBUG_INFO); if (newPage === "locksmith") { setTimeout(addGoldIndicatorsToLocksmith, 100); } } } }); const config = { attributes: true, attributeFilter: ['data-page'], childList: true, subtree: true }; observer.observe(target, config); logDebug("Observer attached to '#fireworks' element, listening for 'data-page' changes.", DEBUG_INFO); const currentPage = target.getAttribute("data-page"); logDebug(`Initial page check. Current page is: '${currentPage}'`, DEBUG_INFO); if (currentPage === "locksmith") { setTimeout(addGoldIndicatorsToLocksmith, 100); } } else { logDebug("❌ Target element '#fireworks' not found. Script will not run automatically on page changes.", DEBUG_ERRORS); }