Assists in tracking users in Russian Roulette in Torn.
目前為
// ==UserScript==
// @name Torn Russian Roulette Helper
// @namespace http://tampermonkey.net/
// @version 1.4
// @description Assists in tracking users in Russian Roulette in Torn.
// @author ErrorNullTag
// @match https://www.torn.com/*
// @grant GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @license GPU AGPLv3
// ==/UserScript==
(function() {
'use strict';
if (!window.location.href.includes("russianRoulette")) return;
let API_KEY = GM_getValue("API_KEY", ""); // Try to retrieve the API key from storage
// If API key is not set, ask the user for it
if (!API_KEY) {
API_KEY = window.prompt("Please enter your API key:", "");
// If the user provides a value, save it for future use
if (API_KEY) {
GM_setValue("API_KEY", API_KEY);
} else {
// If the user cancels the prompt or provides an empty value, reject the promise
return Promise.reject("API key is required.");
}
}
let betAmount = "N/A";
function attack() {
let api = API_KEY;
let url = window.location.href;
if(url.includes("sid=attack"))
{
url = new URL(url);
let attackId = url.searchParams.get("user2ID");
console.log(`https://api.torn.com/user/${attackId}?selections=profile,personalstats&key=${api}`);
fetch(`https://api.torn.com/user/${attackId}?selections=profile,personalstats&key=${api}`)
.then(function(response) {
if (response.status !== 200) {
console.log(`fetch error ${response.status}`);
return;
}
response.json().then(function(data) {
let joinBtn = $("button:contains(\"Start fight\"), button:contains(\"Join fight\")").closest("button");
if($(joinBtn).length) {
$(joinBtn).after(`
<div id='attackInfo'>
<br />Attacks: <font color='green'>[W] ${parseInt(data.personalstats.attackswon) || 0}</font> <font color='red'>[L] ${parseInt(data.personalstats.attackslost) || 0}</font>
<br />Defends: <font color='green'>[W] ${parseInt(data.personalstats.defendswon) || 0}</font> <font color='red'>[L] ${parseInt(data.personalstats.defendslost) || 0}</font>
<br />Drugs: ${parseInt(data.personalstats.drugsused) || 0} used (${parseInt(data.personalstats.xantaken) || 0} xan)
<br />Consumables: ${parseInt(data.personalstats.consumablesused) || 0} used
<br />Refills: ${parseInt(data.personalstats.refills) || 0} used
<br />Networth: $${data.personalstats.networth.toLocaleString("en")}
<br />Last action: ${data.last_action.relative}
<br />Faction: <a href='https://www.torn.com/factions.php?step=profile&ID=${data.faction.faction_id}'>${data.faction.faction_name}</a>
</div>`);
}
}).catch((err) => { console.log(err); });
}).catch(function(err) {
console.log(`fetch error ${err}`);
});
}
}
// attack(); // Call the attack function at the start
const BLACKLIST_DURATION = 60 * 1000;
const blacklist = new Map();
function isBlacklisted(userId) {
if (blacklist.has(userId)) {
if (Date.now() - blacklist.get(userId) < BLACKLIST_DURATION) {
return true;
} else {
blacklist.delete(userId); // Remove the user from blacklist after the duration
}
}
return false;
}
function getBetAmountFromElement(userStatusWrap) {
const betAmountElement = userStatusWrap.querySelector('.betBlock___wz9ED.columnItem___hnwxL');
console.log("Bet Amount Element:", betAmountElement); // Debugging log
if (betAmountElement) {
const betText = betAmountElement.textContent;
console.log("Bet Text:", betText); // Debugging log
const betMatches = betText.match(/\$(\d{1,3}(?:,\d{3})*)(?!\d)/g);
console.log("Bet Matches:", betMatches); // Debugging log
if (betMatches && betMatches.length) {
const mainBet = betMatches[0].replace('$', '');
return mainBet;
}
}
return "N/A"; // Return "N/A" if nothing matches
}
async function fetchUserData(userId) {
if (isBlacklisted(userId)) {
return {
username: idList.get(userId).username, // Added username
level: idList.get(userId).level,
healthStatus: 'Blacklisted'
};
}
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: `https://api.torn.com/user/${userId}?selections=profile&key=${API_KEY}`,
onload: function(response) {
try {
const data = JSON.parse(response.responseText);
if (data.status && data.status.state) {
if (data.status.state === 'Hospital') {
blacklist.set(userId, Date.now()); // Blacklist the user
resolve({
username: data.name, // Fetch the username
level: data.level,
healthStatus: 'Blacklisted'
});
} else {
resolve({
...data,
username: data.name, // Fetch the username
healthStatus: data.status.state
});
}
} else {
resolve({
...data,
username: data.name, // Fetch the username
healthStatus: 'Error: Status unavailable or missing'
});
}
} catch (error) {
console.error('Error parsing user data:', error);
reject(error);
}
},
onerror: function(error) {
console.error('Error fetching user data:', error);
reject(error);
}
});
});
}
function isMobile() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
function initBox() {
const updateBoxDimensions = () => {
if (isMobile()) {
// If on mobile
box.style.width = '100%'; // Full width
box.style.height = '60vh'; // 60% of viewport height
} else {
// If on desktop
let width = window.innerWidth * 0.2; // 20% of window width
let maxHeight = window.innerHeight * 0.5; // 50% of window height
box.style.width = `${width}px`;
box.style.maxHeight = `${maxHeight}px`;
}
}
box.style.overflowY = 'scroll';
box.style.background = 'black';
box.style.color = 'green';
box.style.marginTop = '10px'; // Provide spacing from the games list
box.style.padding = '10px';
box.style.border = '2px solid green';
box.innerHTML = '<div style="font-size: 20px; color: gold;">Phantom Scripting</div><br>';
// Finding the main content container
const contentWrapper = document.querySelector('.content-wrapper[role="main"]');
if (contentWrapper) {
contentWrapper.appendChild(box); // Append the box to the end of the container
} else {
// If for some reason the main container isn't found, the box will be added to the body
document.body.appendChild(box);
}
// Call the update function initially
updateBoxDimensions();
// Adjust dimensions when window is resized
window.addEventListener('resize', updateBoxDimensions);
}
const box = document.createElement('div');
initBox();
const idList = new Map();
function refreshBox() {
while (box.firstChild && box.childElementCount > 1) {
box.lastChild.remove();
}
if (!idList.size) {
box.innerHTML += 'No Users Found';
return;
}
idList.forEach((data, userId) => {
const username = data.username || 'N/A';
const healthStatus = data.healthStatus || 'Error: Unable to retrieve status';
const level = data.level !== undefined ? data.level : 'N/A';
const betAmount = data.betAmount !== "N/A" ? data.betAmount : `<span style="color:red;">${data.betAmount}</span>`;
const entry = document.createElement('div');
entry.style.marginBottom = '10px';
if (healthStatus === 'Blacklisted') {
entry.style.color = 'red'; // Set the color to red if the user is blacklisted
}
entry.innerHTML = `<strong>Username:</strong> ${username}<br><strong>ID:</strong> ${userId}<br><strong>Level:</strong> ${level}<br><strong>Health Status:</strong> ${healthStatus}<br><strong>Bet Amount:</strong> ${betAmount}`;
if (!data.isPresent) {
const mugBtn = document.createElement('button');
mugBtn.innerText = 'Mug';
mugBtn.style.backgroundColor = 'green';
mugBtn.style.marginLeft = '10px';
mugBtn.addEventListener('click', () => {
fetchUserData(userId)
.then(userData => {
idList.set(userId, {
...userData,
isPresent: true,
lastSeen: Date.now()
});
refreshBox();
window.location.href = `https://www.torn.com/loader.php?sid=attack&user2ID=${userId}`;
})
.catch(error => {
console.error('Error fetching user data:', error);
});
});
entry.appendChild(mugBtn);
}
box.appendChild(entry);
});
}
function formatCurrency(amount) {
return `$${Number(amount).toLocaleString('en-US')}`;
}
function monitorChanges() {
const userInfoWraps = document.querySelectorAll('.userStatusWrap___ljSJG');
const currentTime = Date.now();
if (!userInfoWraps.length) {
setTimeout(monitorChanges, 2000);
return;
}
const newIDs = new Set();
userInfoWraps.forEach(userStatusWrap => {
const userId = userStatusWrap.getAttribute('id').split('_')[0];
// Extract bet amount from sibling element with aria-label attribute
let betAmount = "N/A";
const betElement = userStatusWrap.closest('.row___CHcax').querySelector('.betBlock___wz9ED');
if (betElement) {
const betAriaLabel = betElement.getAttribute('aria-label');
const betMatch = betAriaLabel.match(/Bet amount: (\d+)/);
if (betMatch && betMatch[1]) {
betAmount = formatCurrency(betMatch[1]);
}
}
if (userId && !idList.has(userId)) {
idList.set(userId, { isPresent: true, lastSeen: currentTime, betAmount });
fetchUserData(userId)
.then(userData => {
idList.set(userId, {
isPresent: true,
...userData,
lastSeen: currentTime,
betAmount
});
refreshBox();
})
.catch(error => {
console.error('Error fetching user data:', error);
});
} else if (idList.has(userId)) {
idList.get(userId).lastSeen = currentTime;
if (betAmount !== "N/A") idList.get(userId).betAmount = betAmount;
}
newIDs.add(userId);
});
idList.forEach((data, userId) => {
if (!newIDs.has(userId) && data.isPresent) {
data.isPresent = false;
data.leftTime = currentTime;
}
});
removeLeftUsers(currentTime);
setTimeout(monitorChanges, 2000);
}
function removeLeftUsers(currentTime) {
const THIRTY_SECONDS = 30 * 1000;
const leftUsers = [];
idList.forEach((data, userId) => {
if (!data.isPresent && (currentTime - data.leftTime) > THIRTY_SECONDS) {
leftUsers.push(userId);
}
});
leftUsers.forEach(userId => {
idList.delete(userId);
});
refreshBox();
}
monitorChanges();
})();