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.

// ==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();
})();