您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Shows EXECUTE indicator when opponent can be executed
// ==UserScript== // @name Torn Execute Indicator // @namespace http://tampermonkey.net/ // @version 1.2 // @description Shows EXECUTE indicator when opponent can be executed // @author PedroXimenez // @match *://www.torn.com/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; // Check if we're on an attack page (loader.php?sid=attack) if (!window.location.pathname.includes('loader.php')) { return; // Exit if not on loader.php } const urlParams = new URLSearchParams(window.location.search); if (urlParams.get('sid') !== 'attack') { return; // Exit if not on attack page } // Store last logged values to avoid duplicate console output (on window to persist) if (!window.executeLastLoggedValues) { window.executeLastLoggedValues = { executeThreshold: null, opponentHealth: null, lifePercentage: null, canExecute: null }; } function canExecuteTarget(html) { // Extract execute percentage (e.g., "15%" from "below 15% life") const executeMatch = html.match(/below\s+(\d+)%\s+life/i); if (!executeMatch) { return false; // No execute threshold found } const executeThreshold = parseInt(executeMatch[1]); // Find all player divs const playerDivs = document.querySelectorAll('[class*="player___"]'); if (playerDivs.length < 2) { return false; // Need at least 2 players } // Find the opponent's player div (the one without attack buttons) let opponentDiv = null; for (const playerDiv of playerDivs) { const hasAttackButtons = playerDiv.querySelector('[aria-label*="Attack with"]'); if (!hasAttackButtons) { opponentDiv = playerDiv; break; } } if (!opponentDiv) { return false; // Couldn't find opponent div } // Extract health from the opponent's div const healthElement = opponentDiv.querySelector('[id*="player-health-value"]'); if (!healthElement) { return false; // No health element found } const healthText = healthElement.textContent; const healthMatch = healthText.match(/(\d{1,3}(?:,\d{3})*)\s*\/\s*(\d{1,3}(?:,\d{3})*)/); if (!healthMatch) { return false; // Couldn't parse health values } const opponentHealth = { current: parseInt(healthMatch[1].replace(/,/g, '')), max: parseInt(healthMatch[2].replace(/,/g, '')) }; // Calculate life percentage const lifePercentage = (opponentHealth.current / opponentHealth.max) * 100; // Check if life percentage is at or below the execute threshold const canExecute = lifePercentage <= executeThreshold; // Only log if values have changed const currentHealthStr = `${opponentHealth.current}/${opponentHealth.max}`; const currentLifePercentage = lifePercentage.toFixed(2); if (window.executeLastLoggedValues.executeThreshold !== executeThreshold || window.executeLastLoggedValues.opponentHealth !== currentHealthStr || window.executeLastLoggedValues.lifePercentage !== currentLifePercentage || window.executeLastLoggedValues.canExecute !== canExecute) { console.log(`Execute threshold: ${executeThreshold}%`); console.log(`Opponent health: ${currentHealthStr}`); console.log(`Opponent life percentage: ${currentLifePercentage}%`); console.log(`Can execute: ${canExecute}`); // Update last logged values window.executeLastLoggedValues.executeThreshold = executeThreshold; window.executeLastLoggedValues.opponentHealth = currentHealthStr; window.executeLastLoggedValues.lifePercentage = currentLifePercentage; window.executeLastLoggedValues.canExecute = canExecute; } // Add EXECUTE indicator to the figure if can execute if (canExecute) { // Find the figure element that contains the execute weapon const executeElement = document.querySelector('[data-bonus-attachment-description*="below"][data-bonus-attachment-description*="life"]'); if (executeElement) { // Find the nearest figure element (should be a sibling or nearby) const weaponWrapper = executeElement.closest('.weaponWrapper___h3buK'); if (weaponWrapper) { const figure = weaponWrapper.querySelector('figure'); if (figure && !figure.querySelector('.execute-indicator')) { const indicator = document.createElement('div'); indicator.className = 'execute-indicator'; indicator.textContent = 'EXECUTE'; indicator.style.cssText = ` position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: red; font-weight: bold; font-size: 20px; text-shadow: 2px 2px 4px rgba(0,0,0,0.8); pointer-events: none; z-index: 1000; `; figure.style.position = 'relative'; figure.appendChild(indicator); } } } } return canExecute; } // Function to remove existing EXECUTE indicators function removeExecuteIndicators() { const indicators = document.querySelectorAll('.execute-indicator'); indicators.forEach(indicator => indicator.remove()); } // Function to run the check and update display function checkAndUpdate() { removeExecuteIndicators(); // Clear any existing indicators const result = canExecuteTarget(document.documentElement.innerHTML); return result; } // Set up continuous monitoring function startMonitoring(intervalMs = 250) { // First check if there's an execute attachment on the page const hasExecuteAttachment = document.querySelector('[data-bonus-attachment-description*="below"][data-bonus-attachment-description*="life"]'); if (!hasExecuteAttachment) { console.log('No execute attachment found on this page - monitoring not started'); return null; } // Initial check checkAndUpdate(); // Set up interval for continuous checking const intervalId = setInterval(checkAndUpdate, intervalMs); console.log(`Execute monitor started (checking every ${intervalMs}ms)`); console.log('To stop monitoring, run: stopMonitoring()'); // Store the interval ID globally so it can be stopped window.executeMonitorInterval = intervalId; return intervalId; } // Function to stop monitoring function stopMonitoring() { if (window.executeMonitorInterval) { clearInterval(window.executeMonitorInterval); removeExecuteIndicators(); console.log('Execute monitor stopped'); delete window.executeMonitorInterval; } } // Wait for page to load before starting monitoring // Torn dynamically loads content, so we need to wait a bit setTimeout(() => { startMonitoring(); }, 5000); // Wait 2 seconds for page content to load // Also try to start monitoring when the DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { setTimeout(startMonitoring, 1000); }); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址