// ==UserScript==
// @name Factions Deposit Max Minus X
// @author AeC3
// @license MIT
// @version 1.0
// @description Max-minus helper button with configurable amount
// @match *.torn.com/factions.php*
// @namespace https://update.greasyfork.org/scripts/549190/Factions%20Deposit%20Max%20Minus%20X.user.js
// ==/UserScript==
'use strict';
const CONFIG = {
amounts: ['1m', '5m', '10m', '20m', '30m'],
subtractAmount: 100000,
containerClass: 'faction-presets'
};
// Track button states: 0=fill, 1=deposit, 2=confirm
const buttonStates = new Map();
let buttonsAdded = false;
function parseAmount(str) {
return parseInt(str.toLowerCase().replace('m', '000000').replace(/\$/g, ''), 10) || 0;
}
function formatNumber(num) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
function getAvailableCash() {
const cashEl = document.querySelector('.i-have');
return cashEl ? parseInt(cashEl.textContent.replace(/,/g, ''), 10) : 0;
}
function updateButtonAppearance(btn, stage, originalText) {
const stages = [
{ text: originalText, color: '#4CAF50', desc: 'Click to fill' },
{ text: originalText + ' (2/3)', color: '#FF9800', desc: 'Click DEPOSIT' },
{ text: originalText + ' (3/3)', color: '#F44336', desc: 'Click YES' }
];
const stageInfo = stages[stage];
btn.textContent = stageInfo.text;
btn.style.backgroundColor = stageInfo.color;
btn.style.color = 'white';
btn.title = stageInfo.desc;
}
function resetAllButtons() {
buttonStates.forEach((state, btn) => {
buttonStates.set(btn, 0);
const originalText = btn.getAttribute('data-original-text');
btn.textContent = originalText;
btn.style.backgroundColor = '';
btn.style.color = '';
btn.title = 'Click to fill amount';
});
}
function createButton(text, clickHandler) {
const btn = document.createElement('button');
btn.className = 'torn-btn';
btn.style.cssText = 'margin:2px; padding:4px 8px; font-size:11px; cursor:pointer;';
btn.textContent = text;
btn.title = 'Click to fill amount';
btn.setAttribute('data-original-text', text);
btn.addEventListener('click', clickHandler);
buttonStates.set(btn, 0);
return btn;
}
function handlePresetClick(e, amount) {
e.preventDefault();
e.stopPropagation();
// Simple preset - only fills input, resets others
const value = parseAmount(amount);
if (value <= 0) return;
fillInputs(value);
resetAllButtons();
}
function handleMaxClick(e, btn) {
e.preventDefault();
e.stopPropagation();
const currentState = buttonStates.get(btn) || 0;
const originalText = btn.getAttribute('data-original-text');
if (currentState === 0) {
// HUMAN ACTION 1: Fill input only
const available = getAvailableCash();
const value = Math.max(0, available - CONFIG.subtractAmount);
if (value <= 0) {
alert('Insufficient funds for max-minus operation');
return;
}
fillInputs(value);
// Check if button becomes enabled after a longer delay
setTimeout(() => {
const depositCheck = Array.from(document.querySelectorAll('button.torn-btn'))
.find(btn => btn.textContent.trim() === 'DEPOSIT MONEY');
console.log('After 1 second - Deposit button enabled?', !depositCheck?.disabled);
}, 1000);
// Reset other buttons, advance this one
resetAllButtons();
buttonStates.set(btn, 1);
updateButtonAppearance(btn, 1, originalText);
} else if (currentState === 1) {
// HUMAN ACTION 2: Click deposit button only
const depositBtn = Array.from(document.querySelectorAll('button.torn-btn'))
.find(btn => btn.textContent.trim() === 'DEPOSIT MONEY');
if (depositBtn) {
depositBtn.click(); // One action: click deposit
buttonStates.set(btn, 2);
updateButtonAppearance(btn, 2, btn.dataset.originalText);
} else {
alert('DEPOSIT MONEY button not found. Try refreshing the page.');
resetAllButtons();
}
} else if (currentState === 2) {
// HUMAN ACTION 3: Click confirmation only
// Need small delay as confirmation modal loads after deposit
setTimeout(() => {
const confirmBtn = document.querySelector('a.yes.bold.t-blue.h.c-pointer[aria-label*="Yes, I want to deposit"]');
if (confirmBtn && confirmBtn.textContent.trim() === 'Yes') {
confirmBtn.click(); // One action: click confirm
resetAllButtons();
} else {
alert('YES confirmation button not found. You may need to click YES manually.');
resetAllButtons();
}
}, 300);
}
}
function fillInputs(amount) {
const visibleInput = document.querySelector('input.amount.input-money[type="text"]');
const hiddenInput = document.querySelector('input.amount.input-money[type="hidden"]');
if (visibleInput) {
// Clear the field first
visibleInput.value = '';
visibleInput.focus();
// Set the new value
visibleInput.value = amount;
// Fire all the events Torn expects
visibleInput.dispatchEvent(new Event('input', {bubbles: true}));
visibleInput.dispatchEvent(new Event('change', {bubbles: true}));
visibleInput.dispatchEvent(new Event('keyup', {bubbles: true}));
visibleInput.dispatchEvent(new Event('blur', {bubbles: true}));
}
if (hiddenInput) {
hiddenInput.value = amount;
}
// Small delay to ensure validation runs
setTimeout(() => {
if (visibleInput) {
visibleInput.dispatchEvent(new Event('change', {bubbles: true}));
}
}, 50);
}
// Reset button states and cleanup duplicates
function cleanupOnFormChange() {
// Remove any duplicate containers
const containers = document.querySelectorAll(`.${CONFIG.containerClass}`);
if (containers.length > 1) {
// Keep the first one, remove the rest
for (let i = 1; i < containers.length; i++) {
containers[i].remove();
}
}
// Reset button states if form is gone
if (!document.querySelector('form[data-action="donateCash"]')) {
resetAllButtons();
buttonStates.clear();
}
}
function addPresetButtons() {
if (buttonsAdded) return;
const form = document.querySelector('form[data-action="donateCash"]');
const hr = document.querySelector('hr.delimiter-999.m-top10');
if (!form || !hr) return;
const container = document.createElement('div');
container.className = CONFIG.containerClass;
// container.style.cssText = 'margin:5px 0; padding:5px; border:1px solid #ddd; background:#f9f9f9; border-radius:3px;';
// // Add regular preset buttons (single-click fill only)
// CONFIG.amounts.forEach(amount => {
// const btn = createButton(`$${amount}`, (e) => handlePresetClick(e, amount));
// container.appendChild(btn);
// });
// Add max-minus button (3-click flow)
const maxBtn = createButton(`Max-${formatNumber(CONFIG.subtractAmount)}`, (e) => handleMaxClick(e, maxBtn));
maxBtn.style.backgroundColor = '#f39c12';
maxBtn.style.color = 'white';
maxBtn.style.fontWeight = 'bold';
container.appendChild(maxBtn);
// // Add instructions
// const info = document.createElement('div');
// info.style.cssText = 'margin-top:5px; font-size:10px; color:#666; line-height:1.3;';
// info.innerHTML = `
// <strong>3-Click Flow:</strong> Fill → DEPOSIT → YES
// `;
// container.appendChild(info);
hr.parentNode.insertBefore(container, hr.nextSibling);
buttonsAdded = true;
}
// Reset button states when navigating away from donation form
function checkFormVisibility() {
if (!document.querySelector('form[data-action="donateCash"]') && buttonsAdded) {
resetAllButtons();
buttonsAdded = false;
}
}
function initScript() {
addPresetButtons();
const observer = new MutationObserver(() => {
addPresetButtons();
cleanupOnFormChange();
});
observer.observe(document.body, {childList: true, subtree: true});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initScript);
} else {
initScript();
}