Show NPC Time Til Next Level at Loader

Shows the time til the next level for NPCs at the attack loader page. Uses https://api.lzpt.io/loot to get the data. Also modifies tab title, disable by modifying IF_UPDATE_TAB_TITLE to false.

当前为 2024-12-05 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Show NPC Time Til Next Level at Loader
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Shows the time til the next level for NPCs at the attack loader page. Uses https://api.lzpt.io/loot to get the data. Also modifies tab title, disable by modifying IF_UPDATE_TAB_TITLE to false.
// @author       Hesper [2924630]
// @include      https://www.torn.com/loader.php?sid=attack&user2ID=*
// @grant        GM.xmlHttpRequest
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // Displays time remaining until the next level in the tab title.
    // Set to false to disable
    const IF_UPDATE_TAB_TITLE = true;

    const validIDs = [10, 20, 21, 4, 19, 15, 17];

    // Function to fetch JSON data
    function fetchData() {
        return new Promise((resolve, reject) => {
            GM.xmlHttpRequest({
                method: 'GET',
                url: 'https://api.lzpt.io/loot',
                onload: function(response) {
                    if (response.status >= 200 && response.status < 300) {
                        try {
                            const data = JSON.parse(response.responseText);
                            resolve(data);
                        } catch (e) {
                            reject(e);
                        }
                    } else {
                        reject(new Error(`HTTP error! status: ${response.status}`));
                    }
                },
                onerror: function(err) {
                    reject(err);
                }
            });
        });
    }

    function calculateTimeRemaining(currentTime, hospOutTime) {
        const levelTimes = [0, 30, 90, 210, 450]; // Minutes after hosp_out for each level
        let currentLevel = 0;
        let timeRemaining = 0;

        if (currentTime < hospOutTime) {
            timeRemaining = hospOutTime - currentTime;
        } else {
            for (let level = 1; level <= 5; level++) {
                const targetTime = hospOutTime + levelTimes[level - 1] * 60; // Convert minutes to seconds
                timeRemaining = targetTime - currentTime;
                if (timeRemaining > 0) {
                    currentLevel = level;
                    break;
                }
            }
        }

        return { currentLevel, timeRemaining: timeRemaining > 0 ? timeRemaining : 0 };
    }

    function formatTime(seconds) {
        const minutes = Math.floor(seconds / 60);
        const hours = Math.floor(minutes / 60);
        const remainingMinutes = minutes % 60;
        const remainingSeconds = seconds % 60;
        if (hours === 0) {
            if (remainingMinutes === 0) {
                return `${remainingSeconds}s`;
            }
            return `${remainingMinutes}m ${remainingSeconds}s`;
        }
        return `${hours}h ${remainingMinutes}m ${remainingSeconds}s`;
    }

    function updateDiv(npc, currentTime) {

        const hospOutTime = npc.hosp_out;
        const { currentLevel, timeRemaining } = calculateTimeRemaining(currentTime, hospOutTime);
        let level = currentLevel;

        const targetDiv = document.querySelector('.titleContainer___QrlWP');
        if (targetDiv) {
            let newDiv = document.querySelector('#npc-level-info');
            if (!newDiv) {
                newDiv = document.createElement('div');
                newDiv.id = 'npc-level-info';
                newDiv.style.marginTop = '15px';
                newDiv.style.marginRight = '10px';
                newDiv.style.textAlign = 'right';
                newDiv.style.fontSize = '1em';
                newDiv.style.lineHeight = '1.2em';

                targetDiv.parentNode.insertBefore(newDiv, targetDiv.nextSibling);
            }
            if (level < 5) {
                newDiv.innerHTML = `Currently <b>Level ${level}</b><br />Time til Level ${level + 1}: <b>${formatTime(timeRemaining)}</b>`;
                if (IF_UPDATE_TAB_TITLE) document.title = `${formatTime(timeRemaining)} til Level ${level + 1} - ${npc.name}`;
            } else {
                newDiv.innerHTML = `Currently <b>Level ${level}</b>`;
                if (IF_UPDATE_TAB_TITLE) document.title = `Level ${level} -  ${npc.name}`;
            }
        }
    }

    async function startUpdating(user2ID) {
        // Check if the user2ID is valid
        const npcData = await fetchData();
        const npc = npcData.npcs[user2ID];
        if (!npc) return;

        // Start updating the timer every second
        setInterval(() => {
            const currentTime = Math.floor(Date.now() / 1000);
            updateDiv(npc, currentTime);
        }, 1000);
    }

    window.addEventListener('load', () => {
        // check if the user2ID is valid
        const user2ID = parseInt(new URLSearchParams(window.location.search).get('user2ID'), 10);
        if (validIDs.includes(user2ID)) {
            startUpdating(user2ID);
        }
    });
})();