Dead Frontier Tooltip DPS Injector

Injects DPS into #infoBox on hover and also into static boxes for exact weapon name matches, caching data in localStorage for 24 hours.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Dead Frontier Tooltip DPS Injector
// @author       ils94
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  Injects DPS into #infoBox on hover and also into static boxes for exact weapon name matches, caching data in localStorage for 24 hours.
// @match        https://fairview.deadfrontier.com/onlinezombiemmo/index.php?page=24
// @match        https://fairview.deadfrontier.com/onlinezombiemmo/index.php?page=25
// @match        https://fairview.deadfrontier.com/onlinezombiemmo/index.php?page=28*
// @match        https://fairview.deadfrontier.com/onlinezombiemmo/index.php?page=35
// @match        https://fairview.deadfrontier.com/onlinezombiemmo/index.php?page=50
// @match        https://fairview.deadfrontier.com/onlinezombiemmo/index.php?page=59
// @match        https://fairview.deadfrontier.com/onlinezombiemmo/index.php?page=82*
// @match        https://fairview.deadfrontier.com/onlinezombiemmo/index.php?page=84
// @license      MIT
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    let dpsData = {};

    function loadDPS() {
        const cacheKey = 'deadFrontierDPSData';
        const timestampKey = 'deadFrontierDPSTimestamp';
        const cacheDuration = 24 * 60 * 60 * 1000;

        const cachedData = localStorage.getItem(cacheKey);
        const cachedTimestamp = localStorage.getItem(timestampKey);

        if (cachedData && cachedTimestamp) {
            const timeElapsed = Date.now() - parseInt(cachedTimestamp, 10);
            if (timeElapsed < cacheDuration) {
                dpsData = JSON.parse(cachedData);
                console.log('[DPS] Loaded', Object.keys(dpsData).length, 'entries from localStorage');
                startWatcher();
                injectDPSIntoStaticBoxes();
                return;
            }
        }

        fetch('https://fairview.deadfrontier.com/onlinezombiemmo/dfdata/damagepersec.php')
            .then(r => r.text())
            .then(text => {
                const regex = /(.+?)\s*:\s*<b>([\d.]+)<\/b>\s*\(<b>([\d.]+)<\/b>\)<br \/>/g;
                let m;
                while ((m = regex.exec(text)) !== null) {
                    const name = m[1].trim();
                    dpsData[name.toLowerCase()] = {
                        name,
                        base: m[2],
                        mod: m[3]
                    };
                }
                localStorage.setItem(cacheKey, JSON.stringify(dpsData));
                localStorage.setItem(timestampKey, Date.now().toString());
                console.log('[DPS] Loaded', Object.keys(dpsData).length, 'entries from server and saved to localStorage');
                startWatcher();
                injectDPSIntoStaticBoxes();
            })
            .catch(err => {
                console.error('[DPS] Failed to load DPS list:', err);
                if (cachedData) {
                    dpsData = JSON.parse(cachedData);
                    console.log('[DPS] Loaded', Object.keys(dpsData).length, 'entries from localStorage (fallback)');
                    startWatcher();
                    injectDPSIntoStaticBoxes();
                }
            });
    }

    function startWatcher() {
        setInterval(() => {
            const box = document.getElementById('infoBox');
            if (!box || box.style.visibility === 'hidden') return;

            const nameEl = box.querySelector('.itemName');
            if (!nameEl) return;

            const weapon = nameEl.textContent.trim();
            const key = weapon.toLowerCase();

            const entry = dpsData[key];
            if (!entry) {
                const old = box.querySelector('.dpsInjected');
                if (old) old.remove();
                const oldDisclaimer = box.querySelector('.dpsDisclaimer');
                if (oldDisclaimer) oldDisclaimer.remove();
                console.log(`[DPS] ✗ ${weapon} (hover, no exact match)`);
                return;
            }

            const old = box.querySelector('.dpsInjected');
            if (old) old.remove();
            const oldDisclaimer = box.querySelector('.dpsDisclaimer');
            if (oldDisclaimer) oldDisclaimer.remove();

            const line = document.createElement('div');
            line.className = 'itemData dpsInjected';
            line.style.color = '#00FF00';
            line.textContent = `DPS: ${entry.base} (Theoretical: ${entry.mod})`;
            box.appendChild(line);

            const disclaimer = document.createElement('div');
            disclaimer.className = 'itemData dpsDisclaimer';
            disclaimer.style.color = '#FFFF00';
            disclaimer.style.fontSize = '0.9em';
            disclaimer.textContent = 'The values may not match what you see in-game.';
            box.appendChild(disclaimer);

            console.log(`[DPS] ✔ ${weapon} (hover)`);
        }, 1000);
    }

    function injectDPSIntoStaticBoxes() {
        const staticBoxes = document.querySelectorAll('.itemName');

        staticBoxes.forEach(nameEl => {
            const parent = nameEl.parentElement;
            if (!parent || parent.querySelector('.dpsInjected')) return;

            const weapon = nameEl.textContent.trim();
            const key = weapon.toLowerCase();

            const entry = dpsData[key];
            if (!entry) {
                console.log(`[DPS] ✗ ${weapon} (static, no exact match)`);
                return;
            }

            const line = document.createElement('div');
            line.className = 'itemData dpsInjected';
            line.style.color = '#00FF00';
            line.textContent = `DPS: ${entry.base} (Theoretical: ${entry.mod})`;
            parent.appendChild(line);

            const disclaimer = document.createElement('div');
            disclaimer.className = 'itemData dpsDisclaimer';
            disclaimer.style.color = '#FFFF00';
            disclaimer.style.fontSize = '0.9em';
            disclaimer.textContent = 'The values may not match what you see in-game.';
            parent.appendChild(disclaimer);

            console.log(`[DPS] ✔ ${weapon} (static)`);
        });
    }

    loadDPS();
})();