Safe Fold

Requires a double click to fold when checking is available. Prevents accidental folds.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name         Safe Fold
// @namespace    torn.poker.safefold
// @version      1.1
// @description  Requires a double click to fold when checking is available. Prevents accidental folds.
// @author       HopesG
// @match        https://www.torn.com/*
// @grant        none
// @run-at       document-end
// @license      All rights reserved
// ==/UserScript==

(function () {
'use strict';

/* ---------- page check ---------- */

function isPokerPage() {
    return document.body && document.body.dataset.page && document.body.dataset.page.includes('holdem');
}

/* ---------- helpers ---------- */

function getText(el) {
    return (el.innerText || el.textContent || '').replace(/\s+/g, ' ').trim().toLowerCase();
}

function isVisible(el) {
    return !!(el && el.offsetParent !== null);
}

function canCheck() {
    // Look for any visible button that is check or check/fold
    return Array.from(document.querySelectorAll('button')).some(btn => {
        if (!isVisible(btn)) return false;
        const text = getText(btn);
        return text === 'check' || text === 'check / fold' || text === 'call any / check';
    });
}

function findFoldButtons() {
    return Array.from(document.querySelectorAll('button')).filter(btn => {
        return isVisible(btn) && getText(btn) === 'fold';
    });
}

/* ---------- style ---------- */

const STYLE_ID = 'tp-safefold-style';

function injectStyle() {
    if (document.getElementById(STYLE_ID)) return;
    const style = document.createElement('style');
    style.id = STYLE_ID;
    style.textContent = `
    .tp-fold-armed {
        background: linear-gradient(180deg, #ffb347 0%, #cc6600 100%) !important;
        box-shadow:
            inset 0 1px 0 rgba(255,255,255,.20),
            0 0 0 2px rgba(255,160,50,.50),
            0 0 14px rgba(255,140,0,.45) !important;
        animation: tpFoldPulse .4s ease-in-out infinite alternate !important;
        transition: none !important;
    }

    .tp-fold-armed::after {
        content: "Click again to fold";
        position: absolute;
        bottom: calc(100% + 8px);
        left: 50%;
        transform: translateX(-50%);
        background: rgba(20, 10, 0, 0.92);
        color: #ffcc88;
        font-size: 12px;
        font-weight: 600;
        padding: 5px 10px;
        border-radius: 8px;
        white-space: nowrap;
        pointer-events: none;
        box-shadow: 0 2px 8px rgba(0,0,0,.5);
        border: 1px solid rgba(255,160,50,.35);
        z-index: 99999;
    }

    .tp-fold-armed::before {
        /* override the button shine from Colorful Poker if present */
        opacity: 0 !important;
    }

    @keyframes tpFoldPulse {
        from { filter: brightness(1.00); }
        to   { filter: brightness(1.15); }
    }
    `;
    document.head.appendChild(style);
}

/* ---------- core logic ---------- */

const armed = new WeakMap(); // btn → timeout id
const intercepted = new WeakSet();

function armButton(btn) {
    // Already armed — this is the confirmation click, let it through
    if (armed.has(btn)) {
        clearTimeout(armed.get(btn));
        armed.delete(btn);
        btn.classList.remove('tp-fold-armed');
        // Don't block — the real click fires naturally
        return true;
    }

    // First click — arm it
    btn.classList.add('tp-fold-armed');
    const timer = setTimeout(() => {
        btn.classList.remove('tp-fold-armed');
        armed.delete(btn);
    }, 2000);
    armed.set(btn, timer);
    return false; // block this click
}

function interceptFoldButton(btn) {
    if (intercepted.has(btn)) return;
    intercepted.add(btn);

    btn.addEventListener('click', (e) => {
        // Only intercept when check is available
        if (!canCheck()) return;

        // If already armed, let the click through (confirmation)
        if (armed.has(btn)) {
            clearTimeout(armed.get(btn));
            armed.delete(btn);
            btn.classList.remove('tp-fold-armed');
            return; // allow
        }

        // First click — block and arm
        e.preventDefault();
        e.stopImmediatePropagation();
        armButton(btn);
    }, true); // capture phase so we beat Torn's handler
}

/* ---------- main loop ---------- */

function run() {
    if (!isPokerPage()) return;
    injectStyle();
    findFoldButtons().forEach(interceptFoldButton);
}

setInterval(run, 700);

})();