Hack your Torn War

Hack your torn (Kidding)

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Hack your Torn War
// @namespace    http://tampermonkey.net/
// @version      2.51
// @description  Hack your torn (Kidding)
// @author       ShAdOwCrEsT [3929345]
// @match        https://www.torn.com/*
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_xmlhttpRequest
// @license      GPU AGPLv3
// ==/UserScript==

(function() {
    'use strict';

    GM_addStyle(`
        .glitter-container {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 9999;
            overflow: hidden;
        }

        .glitter-particle {
            position: absolute;
            width: 10px;
            height: 10px;
            opacity: 0.9;
            animation: fall linear infinite, twinkle ease-in-out infinite;
        }

        .glitter-star4 {
            background: linear-gradient(45deg, transparent 40%, var(--sparkle-color) 40%, var(--sparkle-color) 60%, transparent 60%),
                        linear-gradient(-45deg, transparent 40%, var(--sparkle-color) 40%, var(--sparkle-color) 60%, transparent 60%);
        }

        .glitter-star6 {
            clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
            background: linear-gradient(135deg, var(--sparkle-light) 0%, var(--sparkle-color) 50%, var(--sparkle-bright) 100%);
        }

        .glitter-diamond {
            clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
            background: linear-gradient(135deg, var(--sparkle-light) 0%, var(--sparkle-color) 50%, var(--sparkle-bright) 100%);
        }

        .color-white {
            --sparkle-color: #c0c0c0;
            --sparkle-light: #ffffff;
            --sparkle-bright: #e8e8e8;
            filter: drop-shadow(0 0 3px rgba(255, 255, 255, 0.8));
        }

        .color-yellow {
            --sparkle-color: #ffd700;
            --sparkle-light: #ffff99;
            --sparkle-bright: #ffeb3b;
            filter: drop-shadow(0 0 3px rgba(255, 215, 0, 0.8));
        }

        .color-blue {
            --sparkle-color: #4da6ff;
            --sparkle-light: #b3d9ff;
            --sparkle-bright: #80bfff;
            filter: drop-shadow(0 0 3px rgba(77, 166, 255, 0.8));
        }

        @keyframes fall {
            0% {
                transform: translateY(-20px) rotate(0deg) scale(1);
                opacity: 0;
            }
            10% {
                opacity: 0.9;
            }
            90% {
                opacity: 0.9;
            }
            100% {
                transform: translateY(100vh) rotate(360deg) scale(1);
                opacity: 0;
            }
        }

        @keyframes twinkle {
            0%, 100% {
                opacity: 0.9;
                filter: brightness(1);
            }
            50% {
                opacity: 0.5;
                filter: brightness(1.5);
            }
        }
    `);

    // Initialize settings only once
    const SETTINGS_INITIALIZED_KEY = 'settingsInitialized';

    if (!GM_getValue(SETTINGS_INITIALIZED_KEY)) {
        // First time setup
        const soundChoice = confirm('Would you like to enable sound alerts?');
        GM_setValue('alertSoundEnabled', soundChoice);

        const glitterChoice = confirm('Would you like to enable glitter animation?');
        GM_setValue('glitterEnabled', glitterChoice);

        GM_setValue('alertTime', 100);
        GM_setValue('minChain', 100);

        GM_setValue(SETTINGS_INITIALIZED_KEY, true);
    }

    const alertSoundEnabled = GM_getValue('alertSoundEnabled', true);
    const glitterEnabled = GM_getValue('glitterEnabled', true);
    const userAlertTime = GM_getValue('alertTime', 100);
    const userMinChain = GM_getValue('minChain', 100);

    const API_STORAGE_KEY = 'tornApiKey';
    const API_URL = 'https://api.torn.com/faction/?selections=chain&key=';
    let apiKey = GM_getValue(API_STORAGE_KEY);

    function requestApiKey() {
        const inputKey = prompt('Enter your Torn API key (only needed once):', '');
        if (inputKey && inputKey.trim()) {
            GM_setValue(API_STORAGE_KEY, inputKey.trim());
            apiKey = inputKey.trim();
            console.log('API key saved successfully');
        } else {
            console.warn('No API key provided');
        }
    }

    if (!apiKey || apiKey === '') {
        requestApiKey();
    }

    const audioContext = new (window.AudioContext || window.webkitAudioContext)();
    let beepInterval = null;
    let alertTriggered = false;

    function playBeep() {
        if (!alertSoundEnabled) return;

        if (audioContext.state === 'suspended') {
            audioContext.resume();
        }

        const oscillator = audioContext.createOscillator();
        const gainNode = audioContext.createGain();

        oscillator.type = 'sine';
        oscillator.frequency.setValueAtTime(800, audioContext.currentTime);

        gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
        gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3);

        oscillator.connect(gainNode);
        gainNode.connect(audioContext.destination);

        oscillator.start(audioContext.currentTime);
        oscillator.stop(audioContext.currentTime + 0.3);
    }

    function startBeeping() {
        if (beepInterval) return;

        playBeep();
        beepInterval = setInterval(() => {
            playBeep();
        }, 5000);
    }

    function stopBeeping() {
        if (beepInterval) {
            clearInterval(beepInterval);
            beepInterval = null;
        }
    }

    function createGlitterParticle(container) {
        const particle = document.createElement('div');
        particle.className = 'glitter-particle';

        const shapes = ['glitter-star4', 'glitter-star6', 'glitter-diamond'];
        const randomShape = shapes[Math.floor(Math.random() * shapes.length)];
        particle.classList.add(randomShape);

        const colors = ['color-white', 'color-yellow', 'color-blue'];
        const randomColor = colors[Math.floor(Math.random() * colors.length)];
        particle.classList.add(randomColor);

        const startX = Math.random() * 100;
        const duration = 3 + Math.random() * 2;
        const delay = Math.random() * 2;
        const size = 6 + Math.random() * 8;
        const twinkleDuration = 0.5 + Math.random() * 1;

        particle.style.left = startX + '%';
        particle.style.width = size + 'px';
        particle.style.height = size + 'px';
        particle.style.animationDuration = `${duration}s, ${twinkleDuration}s`;
        particle.style.animationDelay = delay + 's';

        container.appendChild(particle);

        setTimeout(() => {
            if (particle.parentNode) {
                particle.remove();
            }
        }, (duration + delay) * 1000);
    }

    function createGlitterEffect() {
        const container = document.createElement('div');
        container.className = 'glitter-container';
        document.body.appendChild(container);

        const particleCount = 50;
        for (let i = 0; i < particleCount; i++) {
            setTimeout(() => {
                if (document.querySelector('.glitter-container')) {
                    createGlitterParticle(container);
                }
            }, i * 100);
        }

        const regenerateInterval = setInterval(() => {
            if (!document.querySelector('.glitter-container')) {
                clearInterval(regenerateInterval);
                return;
            }
            createGlitterParticle(container);
        }, 100);

        container.dataset.regenerateInterval = regenerateInterval;
    }

    function fetchChainData() {
        if (!apiKey || apiKey === '') {
            console.warn('No API key set, skipping chain check');
            return;
        }

        GM_xmlhttpRequest({
            method: 'GET',
            url: API_URL + apiKey,
            onload: function(response) {
                try {
                    const data = JSON.parse(response.responseText);
                    if (data.error) {
                        console.error('API Error:', data.error);
                        if (data.error.code === 2) {
                            // Invalid API key
                            GM_setValue(API_STORAGE_KEY, '');
                            apiKey = '';
                            requestApiKey();
                        }
                        return;
                    }
                    handleChainData(data.chain);
                } catch (error) {
                    console.error('Failed to parse chain data:', error);
                }
            },
            onerror: function(error) {
                console.error('API request failed:', error);
            }
        });
    }

    function handleChainData(chain) {
        const { current, cooldown, end } = chain;
        const currentTime = Math.floor(Date.now() / 1000);
        const timeRemaining = end - currentTime;
        const inCooldown = cooldown > 0;

        if (current > 0 && timeRemaining > 0 && !inCooldown && timeRemaining < userAlertTime) {
            triggerGlitterAlert();
        } else {
            alertTriggered = false;
            removeGlitter();
        }
    }

    function triggerGlitterAlert() {
        if (alertTriggered) return;

        if (glitterEnabled) {
            createGlitterEffect();
        }

        startBeeping();

        alertTriggered = true;
    }

    function removeGlitter() {
        const container = document.querySelector('.glitter-container');
        if (container) {
            const intervalId = container.dataset.regenerateInterval;
            if (intervalId) {
                clearInterval(parseInt(intervalId));
            }
            container.remove();
        }
        stopBeeping();
    }

    setInterval(fetchChainData, 10000);
    fetchChainData();
})();