Greasy Fork is available in English.
Flashes Labyrinth button and timer when about to fail.
// ==UserScript==
// @name Milkywayidle Labyrinth Timer Flasher
// @namespace https://www.milkywayidle.com/
// @version 1.1
// @description Flashes Labyrinth button and timer when about to fail.
// @author SilkyPanda
// @match *://*.milkywayidle.com/*
// @icon https://www.milkywayidle.com/favicon.svg
// @grant none
// @license MIT
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
const FLASH_THRESHOLD_SEC = 20;
const COMBAT_ROOM_DURATION_MS = 120000;
let timeRemainingMs = Infinity;
let isCombatRoom = false;
let combatEndTimeLocal = 0;
let isLabyrinthActive = false;
// Inject Custom CSS
const style = document.createElement('style');
style.innerHTML = `
@keyframes flashTimerRed {
0% { color: #ff3333; text-shadow: 0 0 8px rgba(255, 51, 51, 0.8); }
50% { color: inherit; text-shadow: none; }
100% { color: #ff3333; text-shadow: 0 0 8px rgba(255, 51, 51, 0.8); }
}
.timer-warning-flash {
animation: flashTimerRed 1s infinite !important;
font-weight: bold !important;
}
@keyframes flashNavSubtle {
0% { background-color: rgba(220, 38, 38, 0.35); }
50% { background-color: transparent; }
100% { background-color: rgba(220, 38, 38, 0.35); }
}
.nav-warning-flash {
animation: flashNavSubtle 1s infinite !important;
border-radius: 8px;
}
`;
window.addEventListener('DOMContentLoaded', () => {
document.head.appendChild(style);
});
// Stealth WebSocket Proxy
const OriginalWebSocket = window.WebSocket;
window.WebSocket = new Proxy(OriginalWebSocket, {
construct(target, args) {
const ws = new target(...args);
ws.addEventListener('message', function(event) {
try {
const data = JSON.parse(event.data);
if (data.type === 'labyrinth_room_progress') {
isLabyrinthActive = true;
isCombatRoom = false;
timeRemainingMs = data.timeRemainingMs;
}
else if (data.type === 'new_battle') {
isLabyrinthActive = true;
isCombatRoom = true;
combatEndTimeLocal = Date.now() + COMBAT_ROOM_DURATION_MS;
timeRemainingMs = COMBAT_ROOM_DURATION_MS;
}
else if (data.type === 'actions_updated') {
if (isLabyrinthActive) {
isLabyrinthActive = false;
isCombatRoom = false;
timeRemainingMs = Infinity;
}
}
} catch (e) {}
});
return ws;
}
});
// UI Updater Loop
setInterval(() => {
if (isLabyrinthActive && isCombatRoom) {
timeRemainingMs = combatEndTimeLocal - Date.now();
if (timeRemainingMs < 0) timeRemainingMs = 0;
}
const shouldFlash = isLabyrinthActive && timeRemainingMs <= (FLASH_THRESHOLD_SEC * 1000);
let labButton = null;
const spans = document.querySelectorAll('span[class*="NavigationBar_label"]');
for (let span of spans) {
if (span.textContent.trim() === 'Labyrinth') {
labButton = span.closest('[class*="NavigationBar_navigationLink"]');
break;
}
}
const combatTimer = document.querySelector('[class*="BattlePanel_timeRemaining"]');
const skillTimer = document.querySelector('[class*="LabyrinthPanel_timerDisplay"]');
if (labButton) {
if (shouldFlash) labButton.classList.add('nav-warning-flash');
else labButton.classList.remove('nav-warning-flash');
}
if (combatTimer) {
if (shouldFlash && isCombatRoom) combatTimer.classList.add('timer-warning-flash');
else combatTimer.classList.remove('timer-warning-flash');
}
if (skillTimer) {
if (shouldFlash && !isCombatRoom) skillTimer.classList.add('timer-warning-flash');
else skillTimer.classList.remove('timer-warning-flash');
}
}, 500);
})();