您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
color pick-pocket targets based on difficulty
当前为
// ==UserScript== // @name Pickpocket Helper // @namespace http://tampermonkey.net/ // @version 0.5 // @description color pick-pocket targets based on difficulty // @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=16358739&b=0&a=0 // Thanks Emforus [2535044]! // // This script is triggered down at the bottom; see formatCrimesContainerOnce and startListeningToFormatNewCrimes // const lsKey = 'pickpocketSkillLevel'; // Need to wait for page to initialize, before we know this. Assume 1, until then let currentSkillLevel = 1; 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; } function getColorForCrimeChild(crimeChild) { const crimesDivAkaSections = findChildByClassStartingWith('sections', crimeChild); const mainSection = findChildByClassStartingWith('mainSection', crimesDivAkaSections); // e.g. 'Elderly woman' const types = [ 'Businessman', 'Businesswoman', 'Classy lady', 'Elderly man', 'Elderly woman', 'Homeless person', 'Jogger', 'Junkie', 'Police officer', 'Postal Worker', 'Rich kid', 'Sex worker', 'Thug', 'Young man', 'Young woman' ]; let targetType = findChildByClassStartingWith('titleAndProps', mainSection).children[0].textContent; for (let type of types) { if (targetType.startsWith(type)) { // Handle mobile view e.g. "Police officer 5m 10s" targetType = type; } } // e.g. Average 5'0" 158 lbs const physicalProps = findChildByClassStartingWith('titleAndProps', mainSection).children[1].textContent; // Average const build = physicalProps.substring(0, physicalProps.indexOf(' ')); // e.g. Begging0s const activity = findChildByClassStartingWith('activity', mainSection).textContent; // e.g. Begging // The ternary handles mobile - in mobile we don't get the status like "Begging" so we can't do optimize there. const activityName = activity.match(/^\D+/) ? activity.match(/^\D+/)[0] : ''; // e.g. 0s // const activityTime = activity.substring(activityName.length); return colors[getColorSemanticBasedOnAttributes(targetType, build, activityName)]; } let colors = { ideal: '#65E037', easy: '#B4E0AD', 'too-easy': '#C7DCC4', 'too-hard': '#fa8e8e', uncategorized: '#DA85FF' }; let skillCats = ['Safe', 'Moderately Unsafe', 'Unsafe', 'Risky', 'Dangerous', 'Very Dangerous']; let skillStarts = [1, 10, 35, 65, 90, 100]; function getMaxSkillIndex() { let idx = 0; skillStarts.forEach((ele, currentIdx) => { if (Math.floor(currentSkillLevel) >= ele) { idx = currentIdx; } }); return idx; } function getAllSafeSkillCats() { let maxIndex = getMaxSkillIndex(); if (maxIndex >= skillCats.length) { return skillCats.slice(); } else { return skillCats.slice(0, maxIndex + 1); } } const markGroups = { // CS 1-20 'Safe': ['Drunk man', 'Drunk woman', 'Homeless person', 'Junkie', 'Elderly man', 'Elderly woman'], // CS 10-70 'Moderately Unsafe': ['Laborer', 'Postal worker', 'Young man', 'Young woman', 'Student'], // CS 35-90 'Unsafe': ['Classy lady', 'Rich kid', 'Sex worker'], // CS 65+ 'Risky': ['Thug', 'Jogger', 'Businessman', 'Businesswoman', 'Gang member', 'Mobster'], // CS 90+ 'Dangerous': ['Cyclist'], // ??? 'Very Dangerous': ['Police officer'], }; /** * @param mark e.g. 'Rich Kid' * * @return 'too-hard', 'ideal', 'easy', 'too-easy' */ function getMarkIdeality(mark) { let safeSkillCats = getAllSafeSkillCats(); for (let idx = 0; idx < safeSkillCats.length; idx++) { let safeSkillCat = safeSkillCats[idx]; if (markGroups[safeSkillCat].includes(mark)) { if (idx === safeSkillCats.length - 1) { return 'ideal'; } else if (idx === safeSkillCats.length - 2) { return 'easy'; } else { return 'too-easy'; } } }; return 'too-hard'; } /** * * @param markType Elderly woman * @param build Average * @param status Begging * * @return green if ideal, red if too hard, yellow otherwise */ function getColorSemanticBasedOnAttributes(markType, build, status) { // TODO builds and statuses to favor. Too much for now const buildsToAvoid = { 'Businessman': ['Skinny'], 'Drunk man': ['Muscular'], 'Gang member': ['Muscular'], 'Junkie': ['Loitering'], 'Student': ['Athletic'], 'Thug': ['Muscular'] }; const statusesToAvoid = { 'Businessman': ['Walking'], 'Businesswoman': ['Walking'], 'Drunk man': ['Distracted'], 'Drunk woman': ['Distracted'], 'Homeless person': ['Loitering'], 'Junkie': ['Loitering'], 'Laborer': ['Distracted'], 'Sex worker': ['Distracted'] }; let colorSemantic = 'uncategorized'; colorSemantic = getMarkIdeality(markType); if (buildsToAvoid[markType] && buildsToAvoid[markType].includes(build)) { colorSemantic = 'too-hard'; } if (statusesToAvoid[markType] && statusesToAvoid[markType].includes(status)) { colorSemantic = 'too-hard'; } return colorSemantic; } function setCrimeChildColor(crimeChild) { const crimesDivAkaSections = findChildByClassStartingWith('sections', crimeChild); const divContainingButton = findChildByClassStartingWith('commitButtonSection', crimesDivAkaSections) divContainingButton.style.backgroundColor = getColorForCrimeChild(crimeChild) } function getCrimesContainer() { let crimesContainerName = document.querySelectorAll('[class^="crimeOptionGroup"]')[0].classList[0]; return document.getElementsByClassName(crimesContainerName)[0]; } function setSkillLevel() { currentSkillLevel = +document.getElementsByClassName('slick-slide')[0].children[0].children[0].children[0].children[2].textContent; } function formatCrimesContainerOnce() { if (!window.location.href.includes("#/pickpocketing")) { return; } setSkillLevel(); for (let node of getCrimesContainer().children) { setCrimeChildColor(node); } } let observer; let alreadyListening = false; function startListeningToFormatNewCrimes() { if (!window.location.href.includes("#/pickpocketing")) { if (observer) { observer.disconnect(); observer = undefined; } alreadyListening = false; return; } if (alreadyListening) { return; } setSkillLevel(); // Select the node that will be observed for mutations const targetNode = getCrimesContainer(); // Options for the observer (which mutations to observe) const config = { attributes: false, childList: true, subtree: false }; // Callback function to execute when mutations are observed const callback = (mutationList, observer) => { for (const mutation of mutationList) { if (mutation.type === "childList" && mutation.addedNodes.length > 0) { for (let node of targetNode.children) { setCrimeChildColor(node); } } } }; // Create an observer instance linked to the callback function observer = new MutationObserver(callback); // Start observing the target node for configured mutations observer.observe(targetNode, config); alreadyListening = true; } // If we land directly on pickpocket page, these handle it correctly. setTimeout(formatCrimesContainerOnce, 650); setTimeout(startListeningToFormatNewCrimes, 650); // // GreaseMonkey can't listen for Pickpocket page directly, so we run this on all crimes pages. // however if we navigate away from Pickpocket, we stop listening with our observer // window.onpopstate = function(event) { setTimeout(formatCrimesContainerOnce, 650); setTimeout(startListeningToFormatNewCrimes, 650); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址