您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enhanced pickpocketing with color coding and auto-picker - Framework Module
当前为
// ==UserScript== // @name Torn Pickpocket Module // @namespace http://tampermonkey.net/ // @version 1.1 // @description Enhanced pickpocketing with color coding and auto-picker - Framework Module // @match https://www.torn.com/* // @grant GM_setValue // @grant GM_getValue // @grant unsafeWindow // @license MIT (With Credit) // ==/UserScript== (function() { 'use strict'; // Use unsafeWindow to match framework const globalWindow = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window; console.log('[PICKPOCKET] Module starting...'); // PICKPOCKETING CONFIG const categoryColorMap = { "Safe": "#37b24d", "Moderately Unsafe": "#74b816", "Unsafe": "#f59f00", "Risky": "#f76707", "Dangerous": "#f03e3e", "Very Dangerous": "#7048e8", }; const markGroups = { "Safe": ["Drunk man", "Drunk woman", "Homeless person", "Junkie", "Elderly man", "Elderly woman"], "Moderately Unsafe": ["Classy lady", "Laborer", "Postal worker", "Young man", "Young woman", "Student"], "Unsafe": ["Rich kid", "Sex worker", "Thug"], "Risky": ["Jogger", "Businessman", "Businesswoman", "Gang member", "Mobster"], "Dangerous": ["Cyclist"], "Very Dangerous": ["Police officer"], }; const activityTypes = ["Walking", "Stumbling", "Loitering", "Listening to music", "Distracted", "Soliciting", "Running", "Jogging"]; // Settings let ppSettings = { coloringEnabled: GM_getValue('ppColoringEnabled', true), autoPickerEnabled: GM_getValue('ppAutoPickerEnabled', false), targetCategories: GM_getValue('ppTargetCategories', ["Safe"]), targetActivities: GM_getValue('ppTargetActivities', ["Stumbling"]), autoPickDelay: GM_getValue('ppAutoPickDelay', 3000), maxNerve: GM_getValue('ppMaxNerve', 5), randomDelay: GM_getValue('ppRandomDelay', true), maxActions: GM_getValue('ppMaxActions', 50), safetyMode: GM_getValue('ppSafetyMode', true) }; // State let processedTargets = new Set(); let autoPickerInterval = null; let actionCount = 0; let sessionStart = Date.now(); function saveSettings() { Object.keys(ppSettings).forEach(key => { GM_setValue(`pp${key.charAt(0).toUpperCase() + key.slice(1)}`, ppSettings[key]); }); } function log(msg, type = 'info') { if (globalWindow.TornFramework && globalWindow.TornFramework.log) { globalWindow.TornFramework.log(msg, type, 'PICKPOCKET'); } else { console.log(`[PICKPOCKET] ${msg}`); } } function addRandomDelay(baseDelay) { if (!ppSettings.randomDelay) return baseDelay; const variance = baseDelay * 0.3; return baseDelay + (Math.random() * variance * 2 - variance); } function isRateLimited() { if (!ppSettings.safetyMode) return false; if (actionCount >= ppSettings.maxActions) { return true; } return false; } function processCurrentTargets() { if (!ppSettings.coloringEnabled) return; try { const targetElements = document.querySelectorAll('.titleAndProps___DdeVu > div'); targetElements.forEach((titleDiv) => { const titleText = titleDiv.textContent.trim().split(' (')[0]; if (!titleText) return; let category = null; for (const cat in markGroups) { if (markGroups[cat].includes(titleText)) { category = cat; break; } } if (category) { titleDiv.style.color = categoryColorMap[category]; titleDiv.style.fontWeight = 'bold'; titleDiv.style.textShadow = '0 1px 2px rgba(0,0,0,0.5)'; if (!titleDiv.textContent.includes(`(${category})`)) { titleDiv.textContent = `${titleText} (${category})`; } } }); } catch (error) { log(`Target processing failed: ${error.message}`, 'error'); } } function getCurrentNerve() { try { const nerveElement = document.querySelector('.bar-value___NTdce'); if (nerveElement) { const nerveText = nerveElement.textContent; const match = nerveText.match(/(\d+)/); return match ? parseInt(match[1]) : 0; } const altNerveElement = document.querySelector('[class*="nerve"] .bar-value, .nerve-bar .bar-value'); if (altNerveElement) { const match = altNerveElement.textContent.match(/(\d+)/); return match ? parseInt(match[1]) : 0; } return 100; } catch (error) { log(`Nerve reading failed: ${error.message}`, 'error'); return 0; } } function getCategoryPriority(category) { const priorities = { "Safe": 1, "Moderately Unsafe": 2, "Unsafe": 3, "Risky": 4, "Dangerous": 5, "Very Dangerous": 6 }; return priorities[category] || 999; } function findBestTarget() { if (isRateLimited()) { log('Rate limited - skipping target search', 'warning'); return null; } try { const crimeOptions = document.querySelectorAll('.crime-option'); const currentNerve = getCurrentNerve(); if (currentNerve < 1) { log('Insufficient nerve for pickpocketing', 'warning'); return null; } const validTargets = []; for (const option of crimeOptions) { const titleElement = option.querySelector('.titleAndProps___DdeVu > div'); const activityElement = option.querySelector('.activity___e7mdA'); const buttonElement = option.querySelector('.commit-button'); if (!titleElement || !buttonElement) continue; const titleText = titleElement.textContent.trim().split(' (')[0]; const activityText = activityElement ? activityElement.textContent.trim().split('\n')[0] : ''; const ariaLabel = buttonElement.getAttribute('aria-label') || ''; const nerveMatch = ariaLabel.match(/(\d+)\s*nerve/i); const nerveCost = nerveMatch ? parseInt(nerveMatch[1]) : 5; if (currentNerve < nerveCost || nerveCost > ppSettings.maxNerve) continue; if (buttonElement.getAttribute('aria-disabled') === 'true') continue; let targetCategory = null; for (const cat in markGroups) { if (markGroups[cat].includes(titleText)) { targetCategory = cat; break; } } if (!targetCategory || !ppSettings.targetCategories.includes(targetCategory)) continue; if (ppSettings.targetActivities.length > 0) { if (!ppSettings.targetActivities.some(activity => activityText.includes(activity))) continue; } validTargets.push({ element: buttonElement, title: titleText, activity: activityText, category: targetCategory, nerve: nerveCost, priority: getCategoryPriority(targetCategory) }); } validTargets.sort((a, b) => { if (a.priority !== b.priority) return a.priority - b.priority; return a.nerve - b.nerve; }); return validTargets[0] || null; } catch (error) { log(`Target search failed: ${error.message}`, 'error'); return null; } } function performAutoPick(isTest = false) { try { const target = findBestTarget(); if (!target) { const msg = isTest ? 'No valid targets available for test' : 'No targets match current criteria'; log(msg, 'warning'); return false; } if (isTest) { log(`Test successful: Would pick ${target.title} (${target.category}) - ${target.activity} [${target.nerve} nerve]`, 'success'); return true; } if (ppSettings.safetyMode && isRateLimited()) { log('Safety mode: Action blocked due to rate limiting', 'warning'); return false; } target.element.click(); actionCount++; log(`Auto-picked: ${target.title} (${target.category}) [${target.nerve} nerve] - Activity: ${target.activity}`, 'success'); processedTargets.add(target.title + target.activity); setTimeout(() => { processedTargets.delete(target.title + target.activity); }, 30000); return true; } catch (error) { log(`Auto pick failed: ${error.message}`, 'error'); return false; } } function startAutoPicker() { if (autoPickerInterval) return; try { log('Auto picker starting...', 'success'); autoPickerInterval = setInterval(() => { if (ppSettings.autoPickerEnabled && isOnPickpocketPage()) { if (ppSettings.safetyMode && isRateLimited()) { log('Auto picker paused - rate limit reached', 'warning'); return; } performAutoPick(); } }, addRandomDelay(ppSettings.autoPickDelay)); } catch (error) { log(`Auto picker start failed: ${error.message}`, 'error'); } } function stopAutoPicker() { if (autoPickerInterval) { clearInterval(autoPickerInterval); autoPickerInterval = null; log('Auto picker stopped', 'warning'); } } function isOnPickpocketPage() { return window.location.href.includes('crimes') && (document.querySelector('.pickpocketing-root') !== null || document.querySelector('[class*="pickpocket"]') !== null || document.querySelector('.crime-option') !== null); } // Create menu section HTML const menuSection = ` <h4 style="margin: 0 0 12px 0; color: #37b24d;">👤 Pickpocketing</h4> <div style="display: grid; grid-template-columns: 1fr auto; gap: 10px; align-items: center; margin-bottom: 12px;"> <label style="display: flex; align-items: center; cursor: pointer;"> <input type="checkbox" id="ppColoringEnabled" ${ppSettings.coloringEnabled ? 'checked' : ''}> <span style="margin-left: 8px;">Target Color Coding</span> </label> <div style="font-size: 10px; color: #999;">Visual aid</div> </div> <div style="display: flex; align-items: center; margin-bottom: 12px; padding: 8px; background: rgba(55,178,77,0.1); border-radius: 6px;"> <label style="display: flex; align-items: center; cursor: pointer; flex-grow: 1;"> <input type="checkbox" id="ppAutoPickerEnabled" ${ppSettings.autoPickerEnabled ? 'checked' : ''}> <span style="margin-left: 8px; font-weight: bold; color: #37b24d;">🤖 Auto Picker</span> </label> <div id="ppAutoPickStatus" style="padding: 4px 8px; border-radius: 4px; font-size: 10px; font-weight: bold; background: ${ppSettings.autoPickerEnabled ? '#37b24d' : '#666'}; color: white;"> ${ppSettings.autoPickerEnabled ? 'ACTIVE' : 'DISABLED'} </div> </div> <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 12px;"> <div> <label style="display: block; margin-bottom: 4px; font-size: 10px;">Base Delay (ms):</label> <input type="number" id="ppAutoPickDelay" value="${ppSettings.autoPickDelay}" min="1000" max="30000" step="500" style="width: 100%; padding: 6px; background: #333; color: white; border: 1px solid #555; border-radius: 4px; font-size: 11px;"> </div> <div> <label style="display: block; margin-bottom: 4px; font-size: 10px;">Max Nerve Cost:</label> <input type="number" id="ppMaxNerve" value="${ppSettings.maxNerve}" min="1" max="50" style="width: 100%; padding: 6px; background: #333; color: white; border: 1px solid #555; border-radius: 4px; font-size: 11px;"> </div> </div> <div style="margin-bottom: 12px;"> <label style="display: block; margin-bottom: 6px; font-weight: bold; font-size: 11px;">🎯 Target Categories:</label> <div id="ppCategoryCheckboxes" style="max-height: 120px; overflow-y: auto; border: 1px solid #555; padding: 8px; border-radius: 4px; background: rgba(0,0,0,0.3);"> ${Object.keys(markGroups).map(category => ` <label style="display: block; margin-bottom: 4px; cursor: pointer; font-size: 11px; padding: 2px 4px; border-radius: 3px; transition: background 0.2s;"> <input type="checkbox" class="ppCategoryCheck" value="${category}" ${ppSettings.targetCategories.includes(category) ? 'checked' : ''}> <span style="margin-left: 6px; color: ${categoryColorMap[category]}; font-weight: bold;">●</span> <span style="margin-left: 4px;">${category}</span> </label> `).join('')} </div> </div> <div style="margin-bottom: 12px;"> <label style="display: block; margin-bottom: 6px; font-weight: bold; font-size: 11px;">🚶 Target Activities:</label> <div id="ppActivityCheckboxes" style="max-height: 100px; overflow-y: auto; border: 1px solid #555; padding: 8px; border-radius: 4px; background: rgba(0,0,0,0.3);"> ${activityTypes.map(activity => ` <label style="display: block; margin-bottom: 3px; cursor: pointer; font-size: 10px; padding: 2px 4px; border-radius: 3px; transition: background 0.2s;"> <input type="checkbox" class="ppActivityCheck" value="${activity}" ${ppSettings.targetActivities.includes(activity) ? 'checked' : ''}> <span style="margin-left: 6px;">${activity}</span> </label> `).join('')} </div> </div> <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 12px;"> <div> <label style="display: block; margin-bottom: 4px; font-size: 10px;">Max Actions/Hour:</label> <input type="number" id="ppMaxActions" value="${ppSettings.maxActions}" min="10" max="200" style="width: 100%; padding: 6px; background: #333; color: white; border: 1px solid #555; border-radius: 4px; font-size: 10px;"> </div> <div style="display: flex; align-items: end;"> <label style="display: flex; align-items: center; cursor: pointer;"> <input type="checkbox" id="ppSafetyMode" ${ppSettings.safetyMode ? 'checked' : ''}> <span style="margin-left: 6px; font-size: 10px;">Safety Mode</span> </label> </div> </div> <button id="ppTestPick" style="width: 100%; padding: 8px; background: linear-gradient(45deg, #37b24d, #51cf66); border: none; color: white; border-radius: 6px; cursor: pointer; font-size: 11px; font-weight: bold; box-shadow: 0 2px 8px rgba(55,178,77,0.3); transition: all 0.2s;">🧪 Test Auto Pick</button> `; function setupEventHandlers() { // Coloring toggle const coloringToggle = document.getElementById('ppColoringEnabled'); if (coloringToggle) { coloringToggle.onchange = function() { ppSettings.coloringEnabled = this.checked; saveSettings(); setTimeout(processCurrentTargets, 100); log(`Color coding ${this.checked ? 'enabled' : 'disabled'}`, 'info'); }; } // Auto picker toggle const autoPickToggle = document.getElementById('ppAutoPickerEnabled'); if (autoPickToggle) { autoPickToggle.onchange = function() { ppSettings.autoPickerEnabled = this.checked; const status = document.getElementById('ppAutoPickStatus'); if (status) { status.textContent = ppSettings.autoPickerEnabled ? 'ACTIVE' : 'DISABLED'; status.style.background = ppSettings.autoPickerEnabled ? '#37b24d' : '#666'; } if (ppSettings.autoPickerEnabled && isOnPickpocketPage() && !isRateLimited()) { startAutoPicker(); } else { stopAutoPicker(); } saveSettings(); log(`Auto picker ${this.checked ? 'enabled' : 'disabled'}`, 'info'); }; } // Number inputs ['ppAutoPickDelay', 'ppMaxNerve', 'ppMaxActions'].forEach(id => { const input = document.getElementById(id); if (input) { input.onchange = function() { const setting = id.replace('pp', '').charAt(0).toLowerCase() + id.replace('pp', '').slice(1); ppSettings[setting] = parseInt(this.value); saveSettings(); // Restart auto picker if running and delay changed if (id === 'ppAutoPickDelay' && autoPickerInterval) { stopAutoPicker(); startAutoPicker(); } }; } }); // Safety mode toggle const safetyToggle = document.getElementById('ppSafetyMode'); if (safetyToggle) { safetyToggle.onchange = function() { ppSettings.safetyMode = this.checked; saveSettings(); log(`Safety mode ${this.checked ? 'enabled' : 'disabled'}`, 'info'); }; } // Category checkboxes document.querySelectorAll('.ppCategoryCheck').forEach(checkbox => { checkbox.onchange = () => { ppSettings.targetCategories = Array.from(document.querySelectorAll('.ppCategoryCheck:checked')).map(cb => cb.value); saveSettings(); log(`Target categories updated: ${ppSettings.targetCategories.join(', ')}`, 'info'); }; }); // Activity checkboxes document.querySelectorAll('.ppActivityCheck').forEach(checkbox => { checkbox.onchange = () => { ppSettings.targetActivities = Array.from(document.querySelectorAll('.ppActivityCheck:checked')).map(cb => cb.value); saveSettings(); log(`Target activities updated: ${ppSettings.targetActivities.join(', ')}`, 'info'); }; }); // Test button const testBtn = document.getElementById('ppTestPick'); if (testBtn) { testBtn.onclick = () => { log('Testing auto pick functionality...', 'warning'); const result = performAutoPick(true); if (!result) { log('Test failed - check your target settings or visit crimes page', 'error'); } }; } } // Module configuration const moduleConfig = { name: 'Pickpocket', version: '1.1', description: 'Enhanced pickpocketing with color coding and auto-picker', menuSection: menuSection, initialize: function() { log('Pickpocket module initializing...', 'info'); setupEventHandlers(); // Start observer for target processing const observer = new MutationObserver(() => { if (ppSettings.coloringEnabled) { clearTimeout(observer.debounceTimer); observer.debounceTimer = setTimeout(processCurrentTargets, 300); } }); observer.observe(document.body, { childList: true, subtree: true }); // Initial target processing setTimeout(processCurrentTargets, 1000); // Auto-start if enabled and on pickpocket page if (ppSettings.autoPickerEnabled && isOnPickpocketPage()) { setTimeout(startAutoPicker, 2000); log('Auto picker will start in 2 seconds (on pickpocket page)', 'info'); } log('Pickpocket module initialized successfully', 'success'); }, cleanup: function() { stopAutoPicker(); log('Pickpocket module cleaned up', 'info'); }, isActive: function() { return ppSettings.autoPickerEnabled && autoPickerInterval !== null && isOnPickpocketPage(); } }; function initializePickpocketModule() { log('Attempting to register pickpocket module with framework...', 'info'); // Register with framework if (globalWindow.TornFramework.registerModule(moduleConfig)) { log('Pickpocket module registered successfully', 'success'); // Page change detection let currentUrl = window.location.href; const urlObserver = new MutationObserver(() => { if (window.location.href !== currentUrl) { currentUrl = window.location.href; if (!isOnPickpocketPage() && autoPickerInterval) { stopAutoPicker(); log('Left pickpocket page - auto picker stopped', 'info'); } else if (isOnPickpocketPage() && ppSettings.autoPickerEnabled && !autoPickerInterval) { setTimeout(startAutoPicker, 1000); log('Entered pickpocket page - auto picker starting', 'info'); } } }); urlObserver.observe(document.body, { childList: true, subtree: true }); } else { log('Failed to register pickpocket module', 'error'); } } // Wait for framework function waitForFramework() { console.log('[PICKPOCKET] Checking for framework...'); if (globalWindow.TornFramework && globalWindow.TornFramework.initialized) { console.log('[PICKPOCKET] Framework found, initializing module'); initializePickpocketModule(); } else { console.log('[PICKPOCKET] Framework not ready, waiting...'); setTimeout(waitForFramework, 500); } } // Start initialization waitForFramework(); })();