您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
color disposal options based on safety
当前为
// ==UserScript== // @name Disposal J.A.R.V.I.S. // @namespace http://tampermonkey.net/ // @version 0.3 // @description color disposal options based on safety // @author Terekhov // @match https://www.torn.com/loader.php?sid=crimes* // @icon https://www.google.com/s2/favicons?sz=64&domain=torn.com // @grant none // ==/UserScript== (function () { 'use strict'; // // Based on guide here https://www.torn.com/forums.php#/p=threads&f=61&t=16367936&b=0&a=0 // Thanks Emforus [2535044]! // // The script start is triggered by formatPageOnce and/or startCheckingPageToFormat // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // This section of the script listens for page load and calls the main crime script // Note -- these functions are different depending on the crime; Pickpocketing, for example, is much more // complex to check for than Disposal. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // If we land directly on disposal page, these handle it correctly. setTimeout(formatPageOnce, 650); let pageLandingInterval = setInterval(startCheckingPageToFormat, 650); // // GreaseMonkey can't listen for disposal page directly, so we run this on all crimes pages. // however if we navigate away from disposal, we stop listening with our observer // let pagePopInterval; window.addEventListener('popstate', function(event) { setTimeout(formatPageOnce, 650); pagePopInterval = setInterval(startCheckingPageToFormat, 650); }); function setSkillLevel() { currentSkillLevel = +document.getElementsByClassName('slick-slide')[0].children[0].children[0].children[0].children[2].textContent; } function formatPageOnce() { if (!window.location.href.includes("#/disposal")) { return; } setSkillLevel(); executeCrimeScript(); } /** * This function clears intervals checking the page, as the page has already been formatted */ function clearPageCheckingIntervals(reason) { if (pageLandingInterval) { console.warn('clearing pageLandingInterval: ' + reason); clearInterval(pageLandingInterval); } if (pagePopInterval) { console.warn('clearing pagePopInterval: ' + reason); clearInterval(pagePopInterval); } } let observer; let alreadyListening = false; /** * This function is called on an interval to see if the page needs formatting. * If it does, it calls {@link #formatPageOnce} and stops checking after that; otherwise, it keeps going. */ function startCheckingPageToFormat() { if (!window.location.href.includes("#/disposal")) { alreadyListening = false; clearPageCheckingIntervals('not disposal page'); return; } if (alreadyListening) { clearPageCheckingIntervals('already listening'); return; } setSkillLevel(); formatPageOnce(); alreadyListening = true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Global variables - functions and variables that can be re-used across all crimes /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * @return the div containing the list of crime targets (for pickpocketing and disposal, at least) */ function getCrimesContainer() { let crimesContainerName = document.querySelectorAll('[class^="crimeOptionGroup"]')[0].classList[0]; return document.getElementsByClassName(crimesContainerName)[0]; } /** * Utility for inspecting children of an element * * @return child which has a class starting with {@param name} */ function findChildByClassStartingWith(name, parentEle) { for (let child of parentEle.children) { for (let childClass of child.classList) { if (!!childClass && childClass.startsWith(name)) { return child; } } } return null; } /** * Utility for inspecting children of an element * * @return child which has a class starting with {@param name} */ function findChildByClassContaining(name, parentEle) { for (let child of parentEle.children) { for (let childClass of child.classList) { if (!!childClass && childClass.indexOf(name) !== -1) { return child; } } } return null; } // Need to wait for page to initialize, before we know this. Assume 1, until then let currentSkillLevel = 1; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // MAIN SCRIPT - The code below is specific to this crime /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * One purpose - execute the main crime script */ function executeCrimeScript() { for (let jobNode of getCrimesContainer().children) { formatJob(jobNode); } } const colors = { safe: '#40Ab24', caution: '#D6BBA2', unsafe: '#B51B1B' }; // List of method types by aria-label const METHOD_TYPES = [ 'Abandon', 'Bury', 'Burn', 'Sink', 'Dissolve' ]; const JOB_METHOD_DIFFICULTIES_MAP = { 'Biological Waste': { safe: ['Bury', 'Burn', 'Sink'], caution: [], unsafe: [] }, 'Body Part': { safe: [], caution: [], unsafe: [] }, 'Broken Appliance': { safe: ['Sink'], caution: ['Abandon', 'Bury'], unsafe: ['Dissolve'] }, 'Building Debris': { safe: ['Sink'], caution: ['Abandon', 'Bury'], unsafe: [] }, 'Dead Body': { safe: [], caution: [], unsafe: [] }, 'Documents': { safe: ['Burn'], caution: ['Abandon', 'Bury'], unsafe: ['Dissolve'] }, 'Firearm': { safe: [], caution: [], unsafe: [] }, 'General Waste': { safe: ['Bury', 'Burn'], caution: ['Abandon', 'Sink'], unsafe: ['Dissolve'] }, 'Industrial Waste': { safe: ['Sink'], caution: ['Abandon', 'Bury'], unsafe: [] }, 'Murder Weapon': { safe: [], caution: [], unsafe: [] }, 'Old Furniture': { safe: ['Burn'], caution: ['Abandon', 'Bury', 'Sink'], unsafe: ['Dissolve'] }, 'Vehicle': { safe: ['Burn', 'Sink'], caution: ['Abandon'], unsafe: [] } } function formatJob(jobNode) { const jobSections = findChildByClassStartingWith('sections', jobNode); // TODO not sure if jobName works for all views const jobName = jobSections.children[1].textContent; let disposalMethodsContainer = findChildByClassContaining('desktopMethodsSection', jobSections); if (!disposalMethodsContainer) { disposalMethodsContainer = findChildByClassContaining('tabletMethodsSection', jobSections); // Have to go one deeper to get the methods container // However they remain the same options disposalMethodsContainer = findChildByClassStartingWith('methodPicker', disposalMethodsContainer); } const methodDifficulties = JOB_METHOD_DIFFICULTIES_MAP[jobName]; if (methodDifficulties) { for (let safeMethod of methodDifficulties.safe) { const node = findChildByClassStartingWith(safeMethod.toLowerCase(), disposalMethodsContainer); if (node) { node.style.border = '3px solid ' + colors.safe; } } for (let cautionMethod of methodDifficulties.caution) { const node = findChildByClassStartingWith(cautionMethod.toLowerCase(), disposalMethodsContainer); if (node) { node.style.border = '2px solid ' + colors.caution; } } for (let unsafeMethod of methodDifficulties.unsafe) { const node = findChildByClassStartingWith(unsafeMethod.toLowerCase(), disposalMethodsContainer); if (node) { node.style.border = '3px solid ' + colors.unsafe; } } } } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址