Converts the sidebar Energy, Nerve, Happy, and Life floating tooltips into a 12-hour format, synced to your local time. While also adding a floating tooltip over the 24Hour format TCT clock, in your local time.
// ==UserScript==
// @name Torn 12-Hour Tooltips
// @namespace Torn12HrEnergyFix
// @version 1.9
// @description Converts the sidebar Energy, Nerve, Happy, and Life floating tooltips into a 12-hour format, synced to your local time. While also adding a floating tooltip over the 24Hour format TCT clock, in your local time.
// @author Nerros
// @license MIT
// @match https://www.torn.com/*
// @match https://torn.com/*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function() {
'use strict';
const energyDateTimeRegex = /(\d{1,2}\.\d{1,2}\.\d{4})\s+(\d{1,2}):(\d{2}):(\d{2})/;
const clockTextRegex = /[A-Za-z]{3}\s+\d{2}:\d{2}:\d{2}\s*-\s*\d{2}\/\d{2}\/\d{2}/;
function getLocalTimeString() {
const now = new Date();
const localTimeString = now.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit', second: '2-digit', hour12: true });
const localDateString = now.toLocaleDateString([], { weekday: 'short', month: '2-digit', day: '2-digit', year: '2-digit' });
return `Local Time: ${localDateString} ${localTimeString}`;
}
function convertTo12Hour(text) {
return text.replace(energyDateTimeRegex, (match, dateStr, h, minutes, seconds) => {
let hours = parseInt(h, 10);
const ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12 || 12;
const formattedHours = String(hours).padStart(2, '0');
return `${dateStr} ${formattedHours}:${minutes}:${seconds} ${ampm}`;
});
}
// Create a single custom floating tooltip element
let customTooltip = null;
function getCustomTooltip() {
if (!customTooltip) {
customTooltip = document.createElement('div');
customTooltip.id = 'torn-local-clock-tooltip';
Object.assign(customTooltip.style, {
position: 'fixed',
backgroundColor: 'rgba(30, 30, 30, 0.95)',
color: '#ffffff',
padding: '6px 10px',
borderRadius: '4px',
fontSize: '12px',
fontFamily: 'Arial, sans-serif',
zIndex: '999999',
pointerEvents: 'none',
boxShadow: '0 2px 8px rgba(0,0,0,0.6)',
display: 'none',
border: '1px solid #444',
whiteSpace: 'nowrap'
});
document.body.appendChild(customTooltip);
}
return customTooltip;
}
// 1. Process Energy Tooltips (12-hour conversion)
function processEnergyTooltips() {
const tooltips = document.querySelectorAll(
'[data-tippy-root], .tippy-box, .tippy-content, .ui-tooltip, [role="tooltip"]'
);
tooltips.forEach((tooltip) => {
if (energyDateTimeRegex.test(tooltip.innerHTML) && !tooltip.dataset.energy12hrDone) {
if (!tooltip.id.includes('torn-local-clock-tooltip')) {
tooltip.dataset.energy12hrDone = 'true';
tooltip.innerHTML = convertTo12Hour(tooltip.innerHTML);
}
}
});
}
// 2. Attach hover listeners for the top-right clock
let activeClockInterval = null;
function processClockHover() {
const candidates = document.querySelectorAll('header *, #user-bar *, [class*="clock" i], [id*="clock" i]');
for (const el of candidates) {
if (clockTextRegex.test(el.textContent)) {
const clockContainer = el.closest('a, button, [class*="clock" i], [id*="clock" i]') || el;
if (!clockContainer.dataset.localClockSetup) {
clockContainer.dataset.localClockSetup = 'true';
// Remove native title attribute to suppress secondary browser popups
clockContainer.removeAttribute('title');
const tooltip = getCustomTooltip();
clockContainer.addEventListener('mouseenter', () => {
clockContainer.removeAttribute('title');
tooltip.textContent = getLocalTimeString();
tooltip.style.display = 'block';
const rect = clockContainer.getBoundingClientRect();
tooltip.style.top = `${rect.bottom + 6}px`;
tooltip.style.left = `${Math.max(10, rect.left + (rect.width / 2) - 80)}px`;
if (!activeClockInterval) {
activeClockInterval = setInterval(() => {
if (tooltip.style.display === 'block') {
tooltip.textContent = getLocalTimeString();
}
}, 1000);
}
});
clockContainer.addEventListener('mouseleave', () => {
tooltip.style.display = 'none';
if (activeClockInterval) {
clearInterval(activeClockInterval);
activeClockInterval = null;
}
});
}
break;
}
}
}
const observer = new MutationObserver(() => {
processEnergyTooltips();
processClockHover();
});
observer.observe(document.body, {
childList: true,
subtree: true
});
processEnergyTooltips();
processClockHover();
})();