DeepCo Recursion Gatekeeper

Hides recursion access unless RC potential meets a user-defined target.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         DeepCo Recursion Gatekeeper
// @namespace    https://deepco.app/
// @version      2026-05-02
// @author       M3P / ChatGPT
// @license      MIT
// @description  Hides recursion access unless RC potential meets a user-defined target.
// @match        https://deepco.app/dig
// @icon         https://www.google.com/s2/favicons?sz=64&domain=deepco.app
// @grant        GM_getValue
// @grant        GM_setValue
// @grant GM_deleteValue
// ==/UserScript==

(() => {
    'use strict';

    const KEY = 'deepco_gatekeeper_v1';

    function parseNumber(str) {
        if (!str) return NaN;
        return Number(
            str
            .replace(/[^\d.,-]/g, '')
            .replace(/,/g, '')
        );
    }

    function getRC() {
        const el = document.querySelector('[data-role="rc-potential"]');
        if (!el) return null;
        return parseNumber(el.textContent);
    }

    function getData() {
        return GM_getValue(KEY, null);
    }

    function setData(obj) {
        GM_setValue(KEY, obj);
    }

    function clearData() {
        GM_deleteValue(KEY);
    }

    function formatDuration(ms) {
        const s = Math.floor(ms / 1000);
        const h = Math.floor(s / 3600);
        const m = Math.floor((s % 3600) / 60);
        return `${h}h ${m}m`;
    }

    function estimateETA(data, current) {
        if (!data || !data.baseRC) return null;

        const elapsed = Date.now() - data.timestamp;
        if (elapsed <= 0) return null;

        const delta = current - data.baseRC;
        if (delta <= 0) return null;

        const rate = delta / elapsed; // RC per ms
        const remaining = data.target - current;

        if (remaining <= 0) return 0;

        const eta = remaining / rate;
        return eta;
    }

    function openDialog() {
        const current = getRC();
        const data = getData();

        let info = '';

        if (data) {
            const elapsed = Date.now() - data.timestamp;
            const eta = estimateETA(data, current);

            info =
`Current target: ${data.target}
Elapsed: ${formatDuration(elapsed)}
ETA: ${eta ? formatDuration(eta) : 'N/A'}

(Leave blank to clear)`;
  } else {
      info = '(Leave blank to cancel)';
  }

    const input = prompt(
        `Set target RC\n\n${info}`,
        data?.target ?? ''
    );

    // User hit cancel → do nothing
    if (input === null) return;

    // Empty input → clear stored data
    if (!input.trim()) {
        clearData();
        render();
        return;
    }

    const parsed = parseNumber(input);

    if (!Number.isFinite(parsed)) {
        alert('Invalid number');
        return;
    }

    setData({
        target: parsed,
        timestamp: Date.now(),
        baseRC: current
    });

    render();
}

    function render() {
        const li = document.querySelector('[data-tutorial-target="sidebarRecursion"]');
        if (!li) return;

        if (document.getElementById('gatekeeper-li')) return;

        const newLi = document.createElement('li');
        newLi.id = 'gatekeeper-li';

        const btn = document.createElement('button');
        btn.className = 'btn btn-ghost btn-sm w-full justify-between gap-2';

        const label = document.createElement('span');
        label.textContent = 'GateKeeper';
        label.className = 'font-semibold tracking-widest uppercase text-xs'

        const value = document.createElement('span');

        const data = getData();
        const current = getRC();

        if (!data) {
            value.textContent = 'UNSET';
            value.className = 'text-primary';
        } else {
            const pct = current / data.target;

            value.textContent = `${(pct * 100).toFixed(1)}%`;

            value.className = pct >= 1 ? 'text-success' : 'text-error';
        }

        btn.appendChild(label);
        btn.appendChild(value);

        btn.addEventListener('click', openDialog);

        newLi.appendChild(btn);

        li.parentNode.insertBefore(newLi, li.nextSibling);
    }

    function blockIfNeeded() {
        const data = getData();
        if (!data) return;

        const current = getRC();
        if (current == null) return;

        if (current >= data.target) return;

        const header = document.querySelector('#recursion-header');
        if (!header) return;

        header.removeAttribute('href');

        header.addEventListener('click', (e) => {
            e.preventDefault();
            showNo();
        });
    }




function showNo() {
    const container = document.createElement('div');

    Object.assign(container.style, {
        position: 'fixed',
        top: '50%',
        left: '50%',
        transform: 'translate(-50%, -50%)',
        padding: '1.5rem 2.25rem',
        borderRadius: '0.75rem',

        // Strong contrast background
        background: 'rgba(0, 0, 0, 0.9)',

        // Visual separation
        boxShadow: '0 16px 60px rgba(0,0,0,0.6)',
        border: '1px solid rgba(255,255,255,0.12)',

        zIndex: 2147483647,
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center'
    });

    const text = document.createElement('span');
    text.textContent = 'NO!';
    text.className = 'gradient-rainbow';

    Object.assign(text.style, {
        fontSize: '2.75rem',
        fontWeight: '800',
        letterSpacing: '0.05em',
        lineHeight: '1'
    });

    container.appendChild(text);
    document.body.appendChild(container);

    // Optional subtle pop-in
    container.animate(
        [
            { transform: 'translate(-50%, -60%) scale(0.85)', opacity: 0 },
            { transform: 'translate(-50%, -50%) scale(1)', opacity: 1 }
        ],
        { duration: 120, easing: 'ease-out' }
    );

    setTimeout(() => container.remove(), 1000);
}

    function observe() {
        const mo = new MutationObserver(() => {
            if (!document.querySelector('[data-role="rc-potential"]')) return;

            render();
            blockIfNeeded();
            mo.disconnect();
        });

        mo.observe(document.body, { childList: true, subtree: true });
    }

    observe();
})();