NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Revivable + Last Action
// @namespace http://tampermonkey.net/
// @version 1.2.2
// @description Shows if a user is revivable + last action on Torn loader (Use a public key)
// @author Brother [2590792]
// @match https://www.torn.com/page.php?sid=attack*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @connect api.torn.com
// @license AGPL-3.0-only
// @downloadURL https://update.greasyfork.org/scripts/573635/Revivable%20%2B%20Last%20Action.user.js
// @updateURL https://update.greasyfork.org/scripts/573635/Revivable%20%2B%20Last%20Action.meta.js
// ==/UserScript==
(function () {
'use strict';
function getQueryParam(name, url) {
const u = new URL(url || window.location.href);
return u.searchParams.get(name);
}
async function gmGet(key, fallback) {
if (typeof GM_getValue === 'function') return GM_getValue(key) ?? fallback;
return localStorage.getItem(key) ?? fallback;
}
async function gmSet(key, value) {
if (typeof GM_setValue === 'function') return GM_setValue(key, value);
return localStorage.setItem(key, value);
}
function tornApiRequest(url) {
return new Promise((resolve, reject) => {
if (typeof GM_xmlhttpRequest === 'function') {
GM_xmlhttpRequest({
method: 'GET',
url,
responseType: 'json',
onload: resp => resolve(resp.response || JSON.parse(resp.responseText)),
onerror: reject
});
} else {
fetch(url).then(r => r.json()).then(resolve).catch(reject);
}
});
}
const user2ID = getQueryParam('user2ID');
if (!user2ID) return;
// Create label
const label = document.createElement('div');
label.innerHTML = '<div id="revivable">Loading...</div><div id="lastaction" style="font-size:13px;opacity:0.85">...</div>';
label.style.position = 'fixed';
label.style.zIndex = '999999';
label.style.fontSize = '16px';
label.style.fontWeight = 'bold';
label.style.cursor = 'move';
label.style.padding = '6px 10px';
label.style.borderRadius = '6px';
label.style.background = 'rgba(0,0,0,0.5)';
label.style.color = '#fff';
label.style.lineHeight = '1.3em';
label.style.textAlign = 'center'; // <-- Center alignment here
label.style.minWidth = '140px'; // helps centering look nicer
document.body.appendChild(label);
const elRevivable = label.querySelector('#revivable');
const elLastAction = label.querySelector('#lastaction');
// Load saved position
(async () => {
const pos = await gmGet('revive_label_pos', null);
if (pos) {
try {
const { x, y } = JSON.parse(pos);
label.style.left = x + 'px';
label.style.top = y + 'px';
} catch { }
} else {
label.style.left = '20px';
label.style.top = '80px';
}
})();
// Make draggable
label.onmousedown = function (e) {
e.preventDefault();
let shiftX = e.clientX - label.getBoundingClientRect().left;
let shiftY = e.clientY - label.getBoundingClientRect().top;
function moveAt(pageX, pageY) {
label.style.left = pageX - shiftX + 'px';
label.style.top = pageY - shiftY + 'px';
}
function onMouseMove(e) {
moveAt(e.pageX, e.pageY);
}
document.addEventListener('mousemove', onMouseMove);
document.onmouseup = async function () {
document.removeEventListener('mousemove', onMouseMove);
document.onmouseup = null;
await gmSet('revive_label_pos', JSON.stringify({
x: parseInt(label.style.left),
y: parseInt(label.style.top)
}));
};
};
label.ondragstart = () => false;
// API key
async function getApiKey() {
let key = await gmGet('torn_api_key', null);
if (!key) {
key = prompt('Enter your Torn API key:');
if (key) await gmSet('torn_api_key', key.trim());
}
return key;
}
async function updateStatus() {
const apiKey = await getApiKey();
if (!apiKey) {
elRevivable.textContent = 'No API key';
elRevivable.style.color = 'orange';
elLastAction.textContent = '';
return;
}
const url = `https://api.torn.com/user/${user2ID}?selections=profile&key=${apiKey}`;
try {
const data = await tornApiRequest(url);
if (data.error) {
elRevivable.textContent = 'API error';
elRevivable.style.color = 'orange';
elLastAction.textContent = '';
return;
}
if (data.revivable === 1) {
elRevivable.textContent = 'Revivable';
elRevivable.style.color = 'lime';
} else {
elRevivable.textContent = 'Non-revivable';
elRevivable.style.color = 'red';
}
if (data.last_action && data.last_action.relative) {
elLastAction.textContent = 'Last action: ' + data.last_action.relative;
} else {
elLastAction.textContent = '';
}
} catch (err) {
console.error(err);
elRevivable.textContent = 'Request failed';
elRevivable.style.color = 'orange';
elLastAction.textContent = '';
}
}
updateStatus();
})();