Greasy Fork is available in English.
Hack your torn (Kidding)
// ==UserScript==
// @name Hack your Torn War
// @namespace http://tampermonkey.net/
// @version 2.51
// @description Hack your torn (Kidding)
// @author ShAdOwCrEsT [3929345]
// @match https://www.torn.com/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_xmlhttpRequest
// @license GPU AGPLv3
// ==/UserScript==
(function() {
'use strict';
GM_addStyle(`
.glitter-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 9999;
overflow: hidden;
}
.glitter-particle {
position: absolute;
width: 10px;
height: 10px;
opacity: 0.9;
animation: fall linear infinite, twinkle ease-in-out infinite;
}
.glitter-star4 {
background: linear-gradient(45deg, transparent 40%, var(--sparkle-color) 40%, var(--sparkle-color) 60%, transparent 60%),
linear-gradient(-45deg, transparent 40%, var(--sparkle-color) 40%, var(--sparkle-color) 60%, transparent 60%);
}
.glitter-star6 {
clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
background: linear-gradient(135deg, var(--sparkle-light) 0%, var(--sparkle-color) 50%, var(--sparkle-bright) 100%);
}
.glitter-diamond {
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
background: linear-gradient(135deg, var(--sparkle-light) 0%, var(--sparkle-color) 50%, var(--sparkle-bright) 100%);
}
.color-white {
--sparkle-color: #c0c0c0;
--sparkle-light: #ffffff;
--sparkle-bright: #e8e8e8;
filter: drop-shadow(0 0 3px rgba(255, 255, 255, 0.8));
}
.color-yellow {
--sparkle-color: #ffd700;
--sparkle-light: #ffff99;
--sparkle-bright: #ffeb3b;
filter: drop-shadow(0 0 3px rgba(255, 215, 0, 0.8));
}
.color-blue {
--sparkle-color: #4da6ff;
--sparkle-light: #b3d9ff;
--sparkle-bright: #80bfff;
filter: drop-shadow(0 0 3px rgba(77, 166, 255, 0.8));
}
@keyframes fall {
0% {
transform: translateY(-20px) rotate(0deg) scale(1);
opacity: 0;
}
10% {
opacity: 0.9;
}
90% {
opacity: 0.9;
}
100% {
transform: translateY(100vh) rotate(360deg) scale(1);
opacity: 0;
}
}
@keyframes twinkle {
0%, 100% {
opacity: 0.9;
filter: brightness(1);
}
50% {
opacity: 0.5;
filter: brightness(1.5);
}
}
`);
// Initialize settings only once
const SETTINGS_INITIALIZED_KEY = 'settingsInitialized';
if (!GM_getValue(SETTINGS_INITIALIZED_KEY)) {
// First time setup
const soundChoice = confirm('Would you like to enable sound alerts?');
GM_setValue('alertSoundEnabled', soundChoice);
const glitterChoice = confirm('Would you like to enable glitter animation?');
GM_setValue('glitterEnabled', glitterChoice);
GM_setValue('alertTime', 100);
GM_setValue('minChain', 100);
GM_setValue(SETTINGS_INITIALIZED_KEY, true);
}
const alertSoundEnabled = GM_getValue('alertSoundEnabled', true);
const glitterEnabled = GM_getValue('glitterEnabled', true);
const userAlertTime = GM_getValue('alertTime', 100);
const userMinChain = GM_getValue('minChain', 100);
const API_STORAGE_KEY = 'tornApiKey';
const API_URL = 'https://api.torn.com/faction/?selections=chain&key=';
let apiKey = GM_getValue(API_STORAGE_KEY);
function requestApiKey() {
const inputKey = prompt('Enter your Torn API key (only needed once):', '');
if (inputKey && inputKey.trim()) {
GM_setValue(API_STORAGE_KEY, inputKey.trim());
apiKey = inputKey.trim();
console.log('API key saved successfully');
} else {
console.warn('No API key provided');
}
}
if (!apiKey || apiKey === '') {
requestApiKey();
}
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
let beepInterval = null;
let alertTriggered = false;
function playBeep() {
if (!alertSoundEnabled) return;
if (audioContext.state === 'suspended') {
audioContext.resume();
}
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(800, audioContext.currentTime);
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3);
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.3);
}
function startBeeping() {
if (beepInterval) return;
playBeep();
beepInterval = setInterval(() => {
playBeep();
}, 5000);
}
function stopBeeping() {
if (beepInterval) {
clearInterval(beepInterval);
beepInterval = null;
}
}
function createGlitterParticle(container) {
const particle = document.createElement('div');
particle.className = 'glitter-particle';
const shapes = ['glitter-star4', 'glitter-star6', 'glitter-diamond'];
const randomShape = shapes[Math.floor(Math.random() * shapes.length)];
particle.classList.add(randomShape);
const colors = ['color-white', 'color-yellow', 'color-blue'];
const randomColor = colors[Math.floor(Math.random() * colors.length)];
particle.classList.add(randomColor);
const startX = Math.random() * 100;
const duration = 3 + Math.random() * 2;
const delay = Math.random() * 2;
const size = 6 + Math.random() * 8;
const twinkleDuration = 0.5 + Math.random() * 1;
particle.style.left = startX + '%';
particle.style.width = size + 'px';
particle.style.height = size + 'px';
particle.style.animationDuration = `${duration}s, ${twinkleDuration}s`;
particle.style.animationDelay = delay + 's';
container.appendChild(particle);
setTimeout(() => {
if (particle.parentNode) {
particle.remove();
}
}, (duration + delay) * 1000);
}
function createGlitterEffect() {
const container = document.createElement('div');
container.className = 'glitter-container';
document.body.appendChild(container);
const particleCount = 50;
for (let i = 0; i < particleCount; i++) {
setTimeout(() => {
if (document.querySelector('.glitter-container')) {
createGlitterParticle(container);
}
}, i * 100);
}
const regenerateInterval = setInterval(() => {
if (!document.querySelector('.glitter-container')) {
clearInterval(regenerateInterval);
return;
}
createGlitterParticle(container);
}, 100);
container.dataset.regenerateInterval = regenerateInterval;
}
function fetchChainData() {
if (!apiKey || apiKey === '') {
console.warn('No API key set, skipping chain check');
return;
}
GM_xmlhttpRequest({
method: 'GET',
url: API_URL + apiKey,
onload: function(response) {
try {
const data = JSON.parse(response.responseText);
if (data.error) {
console.error('API Error:', data.error);
if (data.error.code === 2) {
// Invalid API key
GM_setValue(API_STORAGE_KEY, '');
apiKey = '';
requestApiKey();
}
return;
}
handleChainData(data.chain);
} catch (error) {
console.error('Failed to parse chain data:', error);
}
},
onerror: function(error) {
console.error('API request failed:', error);
}
});
}
function handleChainData(chain) {
const { current, cooldown, end } = chain;
const currentTime = Math.floor(Date.now() / 1000);
const timeRemaining = end - currentTime;
const inCooldown = cooldown > 0;
if (current > 0 && timeRemaining > 0 && !inCooldown && timeRemaining < userAlertTime) {
triggerGlitterAlert();
} else {
alertTriggered = false;
removeGlitter();
}
}
function triggerGlitterAlert() {
if (alertTriggered) return;
if (glitterEnabled) {
createGlitterEffect();
}
startBeeping();
alertTriggered = true;
}
function removeGlitter() {
const container = document.querySelector('.glitter-container');
if (container) {
const intervalId = container.dataset.regenerateInterval;
if (intervalId) {
clearInterval(parseInt(intervalId));
}
container.remove();
}
stopBeeping();
}
setInterval(fetchChainData, 10000);
fetchChainData();
})();