// ==UserScript==
// @name Ultra+ Timer
// @description made with much love
// @version 0.0.2
// @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, 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 = () => {
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);
if (minutes > 180) {
return 'N/A';
}
return `${minutes} minute${minutes !== 1 ? 's' : ''} ago`;
}