Torn Attack Timer

Attack timer for Torn with a new button

// ==UserScript==
// @name         Torn Attack Timer
// @namespace    http://tampermonkey.net/
// @version      1.27
// @description  Attack timer for Torn with a new button
// @author       You
// @match        https://www.torn.com/loader.php?sid=attack*
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Check if the URL includes "attackLog"
    if (window.location.href.includes("attackLog")) {
        return; // Exit the script if the URL includes "attackLog"
    }

    // Define the API key storage key
    const apiKeyStorageKey = 'tornApiKey';

    // Create and style div elements
    const coverDiv = createDiv('tornCoverDiv', 'fixed', '25%', '51%', '280px', '400px');
    const infoDiv = createDiv('tornInfoDiv', 'fixed', '12%', '0', '100%', null);

    // Create and style button element
    const newButton = createButton('tornNewButton', 'fixed', coverDiv.style.top, coverDiv.style.left);

    // Initialize script
    initializeScript();

    // Function to create and style a div element
    function createDiv(id, position, top, left, width, height) {
        const div = document.createElement('div');
        div.id = id;
        div.style.position = position;
        div.style.top = top;
        div.style.left = left;
        div.style.backgroundColor = 'black';
        div.style.color = 'white';
        div.style.padding = '10px';
        div.style.zIndex = '9998';
        div.style.width = width;
        div.style.height = height;
        div.style.textAlign = 'center';
        document.body.insertBefore(div, document.body.firstChild);
        return div;
    }

    // Function to create and style a button element
    function createButton(id, position, top, left) {
        const button = document.createElement('button');
        button.id = id;
        button.classList = 'torn-btn';
        button.style.position = position;
        button.style.top = top;
        button.style.left = left;
        button.style.transform = 'translate(80px,350px)';
        button.style.width = '170px';
        button.style.color = 'white';
        button.style.zIndex = '9999';
        button.textContent = 'WAIT for Counter';
        button.disabled = true;
        document.body.insertBefore(button, document.body.firstChild);
        return button;
    }

    // Function to initialize the script
    function initializeScript() {
        const userId = getUserIdFromUrl();
        if (!userId) {
            console.error('User ID not found in the URL.');
            return;
        }

        const apiKey = getApiKey();
        const apiEndpoint = `https://api.torn.com/user/${userId}?selections=basic,personalstats,profile&key=${apiKey}`;
        const apiEndpoint2 = `https://api.torn.com/user/?selections=basic,bars&key=${apiKey}`;

        fetchUser(apiEndpoint2);

        // Store dynamic data in the div for later use
        infoDiv.dataset.apiEndpoint = apiEndpoint;
    }

    // Function to fetch user data
    function fetchUser(apiEndpoint2) {
        GM_xmlhttpRequest({
            method: 'GET',
            url: apiEndpoint2,
            onload: function(response) {
                const data2 = JSON.parse(response.responseText);
                if (data2.status.state === "Okay" && data2.energy.current>=25) {
                    newButton.addEventListener("click", async () => {
                        const url = window.location.href;
                        const x = url.indexOf("ID=");
                        const ID = url.substring(x + 3);
                        const step = `step=startFight&user2ID=${ID}`;
                        await fetch("/loader.php?sid=attackData&mode=json", {
                            method: "POST",
                            headers: {
                                "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
                                "x-requested-with": "XMLHttpRequest",
                            },
                            body: step,
                        });
                    });
                    fetchData(infoDiv.dataset.apiEndpoint, infoDiv, coverDiv);
                } else {
                    endAll();
                }
            }
        });
    }

    // Function to fetch data from the API
    function fetchData(apiEndpoint, infoDiv, coverDiv) {
        const maxRetries = 60;
        let retryCount = 0;

        function fetchWithRetry() {
            GM_xmlhttpRequest({
                method: 'GET',
                url: apiEndpoint,
                onload: function(response) {
                    const data = JSON.parse(response.responseText);
                    displayData(data, infoDiv, coverDiv);
                },
                onerror: function(error) {
                    console.error('API Request Failed', error);
                    if (retryCount < maxRetries) {
                        console.log('Retrying in 1 second...');
                        setTimeout(fetchWithRetry, 1000); // Retry after 1 second
                        retryCount++;
                    } else {
                        alert('API problem - cannot get data from API since 60 seconds - please refresh page');
                    }
                }
            });
        }

        // Start the initial fetch attempt
        fetchWithRetry();
    }

    // Function to display data in the div
    function displayData(data, infoDiv, coverDiv) {
        const currentTime = Math.floor(Date.now() / 1000);
        const timeDifference = calculateTimeDifference(currentTime, data.status.until);
        infoDiv.innerHTML = `<strong style="font-size: 20px;">Hosp-Out: ${timeDifference}</strong>`;
        coverDiv.innerHTML = `
            <div style="text-align: left; margin-bottom: 3%;">Name: ${data.name}</div>
            <div style="text-align: left; margin-bottom: 3%;">ID: ${data.player_id}</div>
            <div style="text-align: left; margin-bottom: 3%;">Level: ${data.level}</div>
            <div style="text-align: left; margin-bottom: 3%;">Age: ${data.age}</div>
            <div style="text-align: left;margin-bottom: 6%;">Status: ${data.status.state}</div>
            <div style="text-align: left; margin-bottom: 3%;">Attacks Won: ${data.personalstats.attackswon}</div>
            <div style="text-align: left; margin-bottom: 3%;">Time Played: ${data.personalstats.useractivity.toLocaleString('en-US')}</div>
            <div style="text-align: left; margin-bottom: 3%;">Best Damage: ${data.personalstats.bestdamage}</div>
            <div style="text-align: left; margin-bottom: 3%;">Highest Level Beaten: ${data.personalstats.highestbeaten}</div>
            <div style="text-align: left; margin-bottom: 3%;">Stat Enhancers Used: ${data.personalstats.statenhancersused}</div>
            <div style="text-align: left; margin-bottom: 3%;">Networth: ${data.personalstats.networth}</div>
            <div style="text-align: left; margin-bottom: 3%;">Xanax Used: ${data.personalstats.xantaken}</div>
            <div style="text-align: left; margin-bottom: 3%;">Energy Drink Used: ${data.personalstats.energydrinkused}</div>
            <div style="text-align: left; margin-bottom: 3%;">Energy Refills: ${data.personalstats.refills}</div>
        `;
        if (data.status.until <= currentTime) {
            newButton.disabled = false;
            newButton.textContent = 'ATTACK';
            newButton.style.color = 'red';
            newButton.style.zIndex = '100000';
        } else {
            setTimeout(() => fetchData(infoDiv.dataset.apiEndpoint, infoDiv, coverDiv), 1000);
        }
    }

    // Function to end the script
    function endAll() {
        coverDiv.style.display = 'none';
        infoDiv.style.display = 'none';
        newButton.style.display = 'none';
    }

    // Function to get the API key
    function getApiKey() {
        
        let apiKey = GM_getValue(apiKeyStorageKey);
        alert ("API key= "+apiKey)
        if (!apiKey) {
            apiKey = prompt('Enter your Torn API key:');
            GM_setValue(apiKeyStorageKey, apiKey);
        }
        return apiKey;
    }

    // Function to get the user ID from the URL
    function getUserIdFromUrl() {
        const userIdMatch = window.location.href.match(/user2ID=(\d+)/);
        return userIdMatch ? userIdMatch[1] : null;
    }

    // Function to calculate time difference between two timestamps in HH:mm:ss format
    function calculateTimeDifference(currentTime, targetTime) {
        const timeDifference = Math.max(targetTime - currentTime, 0); // Ensure non-negative value
        const hours = Math.floor(timeDifference / 3600);
        const minutes = Math.floor((timeDifference % 3600) / 60);
        const seconds = timeDifference % 60;
        return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
    }
})();