Efficiency suite. Monitors Education, Organized Crimes, and Life/Energy waste using persistent settings.
// ==UserScript==
// @name Torn Efficiency Manager
// @namespace http://torn.efficiency
// @version 1.0
// @description Efficiency suite. Monitors Education, Organized Crimes, and Life/Energy waste using persistent settings.
// @author Nicholas_Herr [3863644]
// @license MIT
// @match https://www.torn.com/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
let DEBUG_FORCE_ALL = false;
const getSettings = () => {
const defaults = { edu: true, oc: true, life: true, xanax: true };
const saved = localStorage.getItem('EfficiencySettings');
return saved ? JSON.parse(saved) : defaults;
};
const saveSettings = (settings) => {
localStorage.setItem('EfficiencySettings', JSON.stringify(settings));
};
const CONFIG = {
CHECK_INTERVAL: 15000,
SELECTORS: {
SIDEBAR_MENU: '.toggle-content___BJ9Q9',
STATUS_BAR: 'ul[class*="status-icons"]',
LIFE_BAR: 'a[class*="life"]',
ENERGY_BAR: 'a[class*="energy"]',
EDU_LINK: 'a[href*="sid=education"]',
OC_LINK: 'a[href*="tab=crimes"]',
DRUG_CD: 'li[class*="icon49"]',
MAIN_CONTAINER: '#mainContainer',
ACTUAL_BAR: 'div[class*="progress-line"]:not([class*="timer"])'
},
COLORS: {
RED: "#ff4444", DARK_RED: "#cc0000", ORANGE: "#ffa500",
YELLOW: "#e3af00", GREEN: "#37b24d", GRAY: "#444444"
}
};
const EfficiencyManager = {
getAlerts() {
if (DEBUG_FORCE_ALL) {
return [
{ text: "DEBUG: NO EDUCATION COURSE", color: CONFIG.COLORS.RED, url: "#" },
{ text: "DEBUG: NO ORGANIZED CRIME", color: CONFIG.COLORS.ORANGE, url: "#" },
{ text: "DEBUG: LIFE FULL: MAKE BLOOD BAGS!", color: CONFIG.COLORS.DARK_RED, url: "#" },
{ text: "DEBUG: ENERGY AT 500: TAKE A XANAX!", color: CONFIG.COLORS.GREEN, url: "#" },
{ text: "DEBUG: WASTE WARNING: BURN 50 ENERGY!", color: CONFIG.COLORS.YELLOW, url: "#" }
];
}
const settings = getSettings();
const alerts = [];
const isEduPage = window.location.href.includes('sid=education');
const eduActive = !!document.querySelector(`${CONFIG.SELECTORS.STATUS_BAR} ${CONFIG.SELECTORS.EDU_LINK}`);
const ocActive = !!document.querySelector(`${CONFIG.SELECTORS.STATUS_BAR} ${CONFIG.SELECTORS.OC_LINK}`);
if (settings.edu && !isEduPage && !eduActive) {
alerts.push({ text: "NO EDUCATION COURSE", color: CONFIG.COLORS.RED, url: "/page.php?sid=education" });
}
if (settings.oc && !ocActive) {
alerts.push({ text: "NO ORGANIZED CRIME", color: CONFIG.COLORS.ORANGE, url: "/factions.php?step=your#/tab=crimes" });
}
const lifeBar = document.querySelector(CONFIG.SELECTORS.LIFE_BAR);
const progress = lifeBar?.querySelector(CONFIG.SELECTORS.ACTUAL_BAR);
if (settings.life && progress) {
const healthPct = parseInt(progress.style.width) || 0;
if (healthPct === 100) {
alerts.push({ text: "LIFE FULL: MAKE BLOOD BAGS!", color: CONFIG.COLORS.DARK_RED, url: "/item.php#v=blood" });
} else if (healthPct >= 33) {
alerts.push({ text: `Life ${healthPct}%: You could make bags`, color: CONFIG.COLORS.GRAY, url: "/item.php#v=blood" });
}
}
if (settings.xanax) {
const energyBar = document.querySelector(CONFIG.SELECTORS.ENERGY_BAR);
const energyVal = energyBar?.querySelector('p[class*="bar-value"]')?.textContent || "0/0";
const currentEnergy = parseInt(energyVal.split('/')[0].replace(/[^0-9]/g, '')) || 0;
const onCooldown = !!document.querySelector(CONFIG.SELECTORS.DRUG_CD);
if (!onCooldown && currentEnergy < 1000) {
if (currentEnergy > 750) {
const waste = (currentEnergy + 250) - 1000;
alerts.push({ text: `WASTE WARNING: BURN ${waste} ENERGY!`, color: CONFIG.COLORS.YELLOW, url: "/gym.php" });
} else {
alerts.push({ text: `ENERGY AT ${currentEnergy}: TAKE A XANAX!`, color: CONFIG.COLORS.GREEN, url: "/item.php#v=drugs" });
}
}
}
return alerts;
}
};
const UIManager = {
renderAlerts() {
const alerts = EfficiencyManager.getAlerts();
let container = document.getElementById('torn-efficiency-bar');
if (container) container.remove();
if (alerts.length === 0) return;
container = document.createElement('div');
container.id = 'torn-efficiency-bar';
Object.assign(container.style, { display: 'flex', flexDirection: 'column', width: '100%', zIndex: '999999', position: 'relative', gap: '2px' });
alerts.forEach(alert => {
const div = document.createElement('div');
div.innerHTML = `⚠️ ${alert.text}`;
Object.assign(div.style, { background: alert.color, color: '#fff', textAlign: 'center', padding: '14px', fontWeight: 'bold', fontSize: '14px', cursor: 'pointer', boxShadow: '0 2px 5px rgba(0,0,0,0.1)', textShadow: '1px 1px 2px rgba(0,0,0,0.5)' });
div.onclick = () => { if(alert.url !== "#") window.location.href = alert.url; };
container.appendChild(div);
});
document.querySelector(CONFIG.SELECTORS.MAIN_CONTAINER)?.before(container);
},
injectSettingsMenu() {
const menu = document.querySelector(CONFIG.SELECTORS.SIDEBAR_MENU);
if (!menu || document.getElementById('nav-efficiency-settings')) return;
const settings = getSettings();
const container = document.createElement('div');
container.id = 'nav-efficiency-settings';
container.className = 'area-desktop___bpqAS';
container.style.borderLeft = "4px solid #37b24d";
container.innerHTML = `
<div id="settings-header" style="padding: 10px; cursor: pointer; background: rgba(55, 178, 77, 0.1); display: flex; justify-content: space-between; align-items: center;">
<span style="color: #37b24d; font-size: 11px; font-weight: bold;">EFFICIENCY SETTINGS</span>
<span id="settings-chevron">▼</span>
</div>
<div id="settings-content" style="display: none; padding: 10px; flex-direction: column; gap: 8px; background: rgba(0,0,0,0.2);">
${['edu', 'oc', 'life', 'xanax'].map(key => `
<label style="display: flex; justify-content: space-between; color: #ccc; font-size: 11px; cursor: pointer;">
${key.toUpperCase()} ALERTS
<input type="checkbox" data-key="${key}" ${settings[key] ? 'checked' : ''} style="cursor: pointer;">
</label>
`).join('')}
<button id="debug-show-all" style="margin-top: 5px; background: #444; color: #00ffcc; border: 1px solid #00ffcc; padding: 5px; font-size: 10px; cursor: pointer; font-weight: bold; border-radius: 3px;">
DEBUG: SHOW ALL ALERTS
</button>
<div id="debug-info-tray" style="display: none; margin-top: 10px; padding-top: 10px; border-top: 1px solid #555; text-align: center; flex-direction: column; gap: 10px;">
<a href="https://www.torn.com/profiles.php?XID=3863644" target="_blank" style="color: #37b24d; font-size: 10px; font-weight: bold; text-decoration: none; display: block;">
💸 Support Efficiency Logic?
</a>
<a href="https://www.torn.com/profiles.php?XID=3863644" target="_blank" style="color: #aaa; font-size: 9px; text-decoration: none; display: block; font-style: italic;">
Want a custom script? Message me.
</a>
</div>
</div>
`;
menu.prepend(container);
const header = document.getElementById('settings-header');
const content = document.getElementById('settings-content');
const chevron = document.getElementById('settings-chevron');
const debugBtn = document.getElementById('debug-show-all');
const infoTray = document.getElementById('debug-info-tray');
header.onclick = () => {
const active = content.style.display === 'flex';
content.style.display = active ? 'none' : 'flex';
chevron.style.transform = active ? 'rotate(0deg)' : 'rotate(180deg)';
};
debugBtn.onclick = (e) => {
e.stopPropagation();
DEBUG_FORCE_ALL = !DEBUG_FORCE_ALL;
debugBtn.style.background = DEBUG_FORCE_ALL ? "#00ffcc" : "#444";
debugBtn.style.color = DEBUG_FORCE_ALL ? "#000" : "#00ffcc";
debugBtn.textContent = DEBUG_FORCE_ALL ? "DEBUG: ACTIVE" : "DEBUG: SHOW ALL ALERTS";
infoTray.style.display = DEBUG_FORCE_ALL ? "flex" : "none";
UIManager.renderAlerts();
};
content.onchange = (e) => {
if(e.target.tagName !== "INPUT") return;
const key = e.target.getAttribute('data-key');
const current = getSettings();
current[key] = e.target.checked;
saveSettings(current);
UIManager.renderAlerts();
};
}
};
const run = () => {
UIManager.renderAlerts();
UIManager.injectSettingsMenu();
};
setTimeout(run, 2000);
setInterval(() => UIManager.renderAlerts(), CONFIG.CHECK_INTERVAL);
window.addEventListener('hashchange', () => setTimeout(run, 1000));
new MutationObserver(() => { if (!document.getElementById('nav-efficiency-settings')) UIManager.injectSettingsMenu(); })
.observe(document.body, { childList: true, subtree: true });
})();