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);

})();