Torn City Chain Watch Alert

Alert when chain timer drops below user-defined threshold and flash the screen red continuously.

// ==UserScript==
// @name         Torn City Chain Watch Alert
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  Alert when chain timer drops below user-defined threshold and flash the screen red continuously.
// @author       Fu11y
// @match        https://www.torn.com/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    let alertThresholdInSeconds = parseInt(localStorage.getItem('alertThreshold')) || 240;
    let alertedForCurrentThreshold = false;
    let flashIntervalId = null;
    let flashDiv = null;

    function createUI() {
        const wrapper = document.createElement('div');
        wrapper.style.position = 'fixed';
        wrapper.style.top = '10px';
        wrapper.style.right = '10px';
        wrapper.style.zIndex = '10000';
        wrapper.style.backgroundColor = 'rgba(0, 0, 0, 0.6)';
        wrapper.style.padding = '8px';
        wrapper.style.borderRadius = '8px';
        wrapper.style.display = 'flex';
        wrapper.style.alignItems = 'center';
        wrapper.style.gap = '10px';

        const label = document.createElement('label');
        label.textContent = 'Chain Alert Threshold:';
        label.style.color = 'white';
        label.style.fontWeight = 'bold';

        const dropdown = document.createElement('select');
        [60, 90, 120, 150, 180, 210, 240, 270].forEach(seconds => {
            const option = document.createElement('option');
            option.value = seconds;
            option.textContent = `${seconds / 60} minutes`;
            dropdown.appendChild(option);
        });
        dropdown.value = alertThresholdInSeconds;
        dropdown.title = "Set the chain timer alert threshold";
        dropdown.addEventListener('change', (e) => {
            alertThresholdInSeconds = parseInt(e.target.value);
            localStorage.setItem('alertThreshold', alertThresholdInSeconds);
            alertedForCurrentThreshold = false;
        });

        // --- Toggle switch ---
        const toggle = document.createElement('input');
        toggle.type = 'checkbox';
        toggle.checked = localStorage.getItem('chainAlertEnabled') !== 'false';
        toggle.title = "Toggle alerts on or off";
        toggle.style.transform = 'scale(1.2)';
        toggle.style.cursor = 'pointer';

        const toggleLabel = document.createElement('label');
        toggleLabel.textContent = ' Alerts On';
        toggleLabel.style.color = 'white';
        toggleLabel.style.fontWeight = 'bold';

        toggle.addEventListener('change', () => {
            localStorage.setItem('chainAlertEnabled', toggle.checked);
        });

        const toggleWrapper = document.createElement('div');
        toggleWrapper.style.display = 'flex';
        toggleWrapper.style.alignItems = 'center';
        toggleWrapper.style.gap = '5px';
        toggleWrapper.appendChild(toggle);
        toggleWrapper.appendChild(toggleLabel);

        // Append all to UI
        wrapper.appendChild(label);
        wrapper.appendChild(dropdown);
        wrapper.appendChild(toggleWrapper);
        document.body.appendChild(wrapper);
    }

    function startFlashing() {
        if (flashIntervalId) return;

        flashDiv = document.createElement('div');
        flashDiv.style.position = 'fixed';
        flashDiv.style.top = '0';
        flashDiv.style.left = '0';
        flashDiv.style.width = '100vw';
        flashDiv.style.height = '100vh';
        flashDiv.style.backgroundColor = 'red';
        flashDiv.style.opacity = '0';
        flashDiv.style.zIndex = '9999';
        flashDiv.style.pointerEvents = 'none';
        flashDiv.style.transition = 'opacity 0.5s ease-in-out';

        document.body.appendChild(flashDiv);

        let visible = false;

        flashIntervalId = setInterval(() => {
            visible = !visible;
            flashDiv.style.opacity = visible ? '0.5' : '0';
        }, 1000);
    }

    function stopFlashing() {
        if (flashIntervalId) {
            clearInterval(flashIntervalId);
            flashIntervalId = null;
        }
        if (flashDiv) {
            flashDiv.remove();
            flashDiv = null;
        }
    }

    function triggerAlert() {
        if (!alertedForCurrentThreshold) {
            alert(`Chain timer is below ${alertThresholdInSeconds / 60} minutes!`);
            alertedForCurrentThreshold = true;
        }
        startFlashing();
    }

    function monitorChainTimer() {
        const timerElement = document.querySelector('[class*="bar-timeleft"]');
        if (!timerElement) return;

        const timerText = timerElement.textContent.trim();

        // ✅ Skip if alert is disabled or timer is 00:00
        if (localStorage.getItem('chainAlertEnabled') === 'false' || timerText === '00:00') {
            stopFlashing();
            alertedForCurrentThreshold = false;
            return;
        }

        const [min, sec] = timerText.split(':').map(part => parseInt(part, 10));
        if (isNaN(min) || isNaN(sec)) return;

        const totalTimeInSeconds = min * 60 + sec;

        if (totalTimeInSeconds < alertThresholdInSeconds) {
            triggerAlert();
        } else {
            alertedForCurrentThreshold = false;
            stopFlashing();
        }
    }

    createUI();
    setInterval(monitorChainTimer, 2000);
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址