Ultra+ Timer

made with much love

目前为 2023-02-22 提交的版本。查看 最新版本

// ==UserScript==
// @name         Ultra+ Timer
// @description  made with much love
// @version      0.0.4
// @author       Cazka#1820
// @match        *://florr.io/*
// @license      MIT
// @namespace    https://gf.qytechs.cn/users/541070
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @run-at       document-end
// ==/UserScript==

const bosses = [
    { name: 'Beetle', spawnedAt: null },
    { name: 'Bubble', spawnedAt: null },
    { name: 'Cactus', spawnedAt: null },
    { name: 'Centipede', spawnedAt: null },
    { name: 'Cockroach', spawnedAt: null },
    { name: 'Crab', spawnedAt: null },
    { name: 'Fly', spawnedAt: null },
    { name: 'Hornet', spawnedAt: null },
    { name: 'Jellyfish', spawnedAt: null },
    { name: 'Leech', spawnedAt: null },
    { name: 'Moth', spawnedAt: null },
    { name: 'Queen Ant', spawnedAt: null },
    { name: 'Queen Fire Ant', spawnedAt: null },
    { name: 'Rock', spawnedAt: null },
    { name: 'Sandstorm', spawnedAt: null },
    { name: 'Shell', spawnedAt: null },
    { name: 'Spider', spawnedAt: null },
];

const menu = document.body.appendChild(document.createElement('div'));
menu.style.padding = '15px';
menu.style.background = '#ffffff3f';
menu.style['border-radius'] = '10px';
menu.style.display = GM_getValue('menuDisplay', 'block');
menu.style.position = 'absolute';
menu.style['pointer-events'] = 'none';
menu.style.bottom = '5px';
menu.style.right = '5px';

loadBosses();
bosses.sort((a, b) => (a.spawnedAt ?? Infinity) - (b.spawnedAt ?? Infinity));

const table = menu.appendChild(document.createElement('table'));
table.style['font-family'] = 'Ubuntu';
table.style['border-collapse'] = 'collapse';
table.style.width = `100%`;

updateTable();
setInterval(updateTable, 5000);

// Tampermonkey menu
GM_registerMenuCommand('Toggle Menu', (event) => {
    const newValue = GM_getValue('menuDisplay', 'block') == 'block' ? 'none' : 'block';
    GM_setValue('menuDisplay', newValue);
    menu.style.display = newValue;
});

// functions
function loadBosses() {
    bosses.forEach((x) => {
        x.spawnedAt = GM_getValue(x.name, null);
    });
}
function updateTable() {
    while (table.rows.length > 0) {
        table.deleteRow(0);
    }

    bosses.sort((a, b) => (a.spawnedAt ?? Infinity) - (b.spawnedAt ?? Infinity));
    bosses.forEach((x) => {
        const minutes = Math.floor((Date.now() - x.spawnedAt) / 1000 / 60);
        if (minutes > 240) {
            x.spawnedAt = null;
        }
    });
    bosses.forEach((x, i) => {
        const tr = table.insertRow();

        // Mob
        const td1 = tr.insertCell();
        if (i !== 0) {
            td1.style['padding-top'] = '5px';
        }
        if (i !== bosses.length - 1) {
            td1.style['padding-bottom'] = '5px';
        }
        td1.style['padding-right'] = '20px';

        td1.appendChild(document.createTextNode(x.name));

        // minutes ago
        const td2 = tr.insertCell();
        if (i !== 0) {
            td2.style['padding-top'] = '5px';
        }
        if (i !== bosses.length - 1) {
            td2.style['padding-bottom'] = '5px';
        }
        td2.style['pointer-events'] = 'auto';
        td2.style.cursor = 'pointer';

        td2.appendChild(document.createTextNode(toTimeSpanString(x.spawnedAt)));

        td2.onclick = (e) => {
            if (e.shiftKey) {
                const input = window.prompt(`Manually set the timer of ${x.name}`);
                if (isNaN(input)) {
                    return;
                }

                x.spawnedAt = Date.now() - input * 60 * 1000;
                updateTable();
                return;
            }
            if (!window.confirm(`Do you really want to reset the timer of ${x.name}?`)) {
                return;
            }
            x.spawnedAt = Date.now();
            GM_setValue(x.name, x.spawnedAt);
            updateTable();
        };
        td2.addEventListener('contextmenu', (e) => e.preventDefault());
    });
}
function toTimeSpanString(timestamp) {
    if (timestamp == null) {
        return 'N/A';
    }

    const seconds = (Date.now() - timestamp) / 1000;
    const minutes = Math.floor(seconds / 60);

    return `${minutes} minute${minutes !== 1 ? 's' : ''} ago`;
}

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址