您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Warns if you are actively selling items in Bazaar or Item Market. Resets saved settings on update/reinstall.
// ==UserScript== // @name Mug protection // @namespace Nurv.IronNerd.me // @version 0.4 // @description Warns if you are actively selling items in Bazaar or Item Market. Resets saved settings on update/reinstall. // @author Nurv [669537] // @match https://www.torn.com/* // @exclude https://www.torn.com/loader.php?sid=attack* // @exclude https://www.torn.com/pc.php* // @grant GM_xmlhttpRequest // @grant GM_registerMenuCommand // @license Copyright IronNerd.me // ==/UserScript== (function () { 'use strict'; // ---------------------------- // CONFIG & STORAGE MANAGEMENT // ---------------------------- const SCRIPT_VERSION = "0.4"; const STORAGE_KEYS = { API_KEY: 'tornApiKey', GHOST_ID: 'ghostId', HAS_PROMPTED: 'hasPrompted', SCRIPT_VERSION: 'mugProtectionScriptVersion' }; // If the stored version isn’t the current one, then clear our saved keys. if (localStorage.getItem(STORAGE_KEYS.SCRIPT_VERSION) !== SCRIPT_VERSION) { localStorage.removeItem(STORAGE_KEYS.API_KEY); localStorage.removeItem(STORAGE_KEYS.GHOST_ID); localStorage.removeItem(STORAGE_KEYS.HAS_PROMPTED); localStorage.setItem(STORAGE_KEYS.SCRIPT_VERSION, SCRIPT_VERSION); console.log("Mug Protection: New installation or update detected – settings have been reset."); } // Retrieve saved settings let apiKey = localStorage.getItem(STORAGE_KEYS.API_KEY) || null; let ghostId = localStorage.getItem(STORAGE_KEYS.GHOST_ID) || null; let hasPrompted = localStorage.getItem(STORAGE_KEYS.HAS_PROMPTED) || null; // ------------------------------------ // PROMPT FOR SETTINGS / INITIALIZATION // ------------------------------------ function promptForInputs() { const enteredApiKey = prompt("Enter your Torn API key (leave blank to skip):", apiKey || ""); if (enteredApiKey) { apiKey = enteredApiKey.trim(); localStorage.setItem(STORAGE_KEYS.API_KEY, apiKey); console.log("Mug Protection: API key saved."); } else { console.log("Mug Protection: No API key entered. Default features will be active."); } const enteredGhostId = prompt("Enter Ghost Friend ID (leave blank to skip):", ghostId || ""); if (enteredGhostId) { ghostId = enteredGhostId.trim(); localStorage.setItem(STORAGE_KEYS.GHOST_ID, ghostId); console.log(`Mug Protection: Ghost Friend ID saved as: ${ghostId}`); } else { console.log("Mug Protection: No Ghost Friend ID entered. Ghost Friend feature will be inactive."); } localStorage.setItem(STORAGE_KEYS.HAS_PROMPTED, 'true'); } function initialize() { if (!hasPrompted) { promptForInputs(); } } // ------------------------- // CORE FUNCTIONALITY // ------------------------- // Add the Ghost Friend icon to the status bar if not already added. function addGhostIcon() { // Prevent duplicate insertion. if (document.getElementById("ghostFriendIcon")) { return; } const tradeUrl = ghostId ? `https://www.torn.com/trade.php#step=start&userID=${ghostId}` : "https://www.torn.com/trade.php"; const ghostIconHtml = ` <li id="ghostFriendIcon" class="icon-ghost"> <a href="${tradeUrl}" aria-label="Ghost Friend" tabindex="0" style="color: white;" data-is-tooltip-opened="false"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white" width="24px" height="24px"> <path d="M12 2C7.59 2 4 5.59 4 10c0 3.91 2.82 7.19 6.68 7.89l.32.06v3.15l-1.32-1.32-.71-.71-.71.71-1.82 1.83v-5.35c.58.25 1.19.4 1.82.49v4.55l2.53-2.53c.22-.22.51-.34.82-.34h1.03c.31 0 .6.12.82.34l2.53 2.53v-4.55c.63-.09 1.24-.24 1.82-.49v5.35l-1.82-1.83-.71-.71-.71.71-1.32 1.32V18l.32-.06C17.18 17.19 20 13.91 20 10c0-4.41-3.59-8-8-8zm-3 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm6 0c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/> </svg> </a> </li> `; const iconContainerSelector = window.innerWidth <= 784 ? ".status-icons___gPkXF.mobile___MWm2o" : ".status-icons___gPkXF"; const statusIcons = document.querySelector(iconContainerSelector); if (statusIcons) { statusIcons.insertAdjacentHTML("beforeend", ghostIconHtml); console.log("Mug Protection: Ghost Friend icon added."); } } // Check if the user is in the hospital by looking for the hospital icon. function isInHospital() { const hospitalSelector = window.innerWidth <= 784 ? "li.icon15___IohoO > a[aria-label*='Hospital']" : "li[class*='icon15'] a[aria-label*='Hospital']"; return document.querySelector(hospitalSelector) !== null; } // Display a warning banner with a custom message. async function displayBanner(message) { console.log("Mug Protection: Displaying banner:", message); removeBanner(); const banner = document.createElement("div"); banner.id = "selling-warning-banner"; Object.assign(banner.style, { backgroundColor: "red", position: "fixed", top: "0", width: "100%", zIndex: "99999", padding: "12px", textAlign: "center", color: "white", fontWeight: "bold", cursor: "pointer", wordWrap: "break-word", whiteSpace: "normal" }); const bannerLink = document.createElement("a"); bannerLink.href = "https://www.torn.com/item.php#medical-items"; bannerLink.target = "_blank"; bannerLink.style.color = "white"; bannerLink.style.textDecoration = "none"; bannerLink.innerHTML = message; banner.appendChild(bannerLink); document.body.appendChild(banner); // Remove the banner after 7 seconds. setTimeout(removeBanner, 7000); } // Remove the warning banner, if present. function removeBanner() { const banner = document.getElementById("selling-warning-banner"); if (banner) { banner.remove(); console.log("Mug Protection: Banner removed."); } } // Fetch API data using the Fetch API. async function fetchApiData(url) { console.log("Mug Protection: Fetching API data from:", url); try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error("Mug Protection: Error fetching API data:", error); return null; } } // Calculate the total value from an array of items. function calculateTotal(items, key = "amount") { return items.reduce((sum, item) => { const price = parseFloat(item.price) || 0; const quantity = parseFloat(item[key]) || 1; return sum + (price * quantity); }, 0); } // Check whether items are being actively sold and display a warning banner if so. async function checkSellingStatus() { console.log("Mug Protection: Checking selling status..."); if (isInHospital()) { console.log("Mug Protection: User is in the hospital."); if (ghostId) { addGhostIcon(); } return; } const bazaarSelector = window.innerWidth <= 784 ? "li.icon35___tya65 > a[aria-label*='Bazaar']" : "li[class*='icon35'] a[aria-label*='Bazaar']"; const itemMarketSelector = window.innerWidth <= 784 ? "li.icon36___cAwTk > a[aria-label*='Item Market']" : "li[class*='icon36'] a[aria-label*='Item Market']"; const isBazaarActive = document.querySelector(bazaarSelector) !== null; const isItemMarketActive = document.querySelector(itemMarketSelector) !== null; console.log("Mug Protection: Bazaar Active:", isBazaarActive, "Item Market Active:", isItemMarketActive); if (!isBazaarActive && !isItemMarketActive) { console.log("Mug Protection: No active selling detected."); return; } if (apiKey) { try { const bazaarData = isBazaarActive ? await fetchApiData(`https://api.torn.com/user/?selections=bazaar&key=${apiKey}`) : null; const bazaarValue = bazaarData && bazaarData.bazaar ? calculateTotal(bazaarData.bazaar, "quantity") : 0; const itemMarketData = isItemMarketActive ? await fetchApiData(`https://api.torn.com/v2/user/itemmarket?key=${apiKey}`) : null; const itemMarketValue = itemMarketData && itemMarketData.itemmarket ? calculateTotal(itemMarketData.itemmarket, "amount") : 0; const totalValue = bazaarValue + itemMarketValue; if (totalValue > 0) { await displayBanner(`You have items worth $${totalValue.toLocaleString()} actively listed. Consider Self-Hosping to avoid being mugged!`); } } catch (error) { console.error("Mug Protection: Error processing API data:", error); } } else { // If no API key is provided, fall back to a simpler warning. if (isBazaarActive) { await displayBanner("You are actively selling items in the Bazaar. <a href='https://www.torn.com/item.php#medical-items' style='color: white;'>Consider Self-Hosping to avoid being mugged!</a>"); } if (isItemMarketActive) { await displayBanner("You are actively selling items in the Item Market. <a href='https://www.torn.com/item.php#medical-items' style='color: white;'>Consider Self-Hosping to avoid being mugged!</a>"); } } } // ------------------------- // MENU COMMAND & HANDLERS // ------------------------- // Allow the user to manually reset settings via the script manager’s menu. function resetSettings() { localStorage.removeItem(STORAGE_KEYS.API_KEY); localStorage.removeItem(STORAGE_KEYS.GHOST_ID); localStorage.removeItem(STORAGE_KEYS.HAS_PROMPTED); console.log("Mug Protection: Settings have been cleared."); promptForInputs(); } if (typeof GM_registerMenuCommand === "function") { GM_registerMenuCommand("Reset Mug Protection Settings", resetSettings); } // ------------------------- // STARTUP // ------------------------- initialize(); document.addEventListener("DOMContentLoaded", checkSellingStatus); })();