xd2shuffle

Visual larp: Changes ARS to $ everywhere (bets, balance, everything) - keeps numbers the same

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         xd2shuffle
// @namespace    http://tampermonkey.net/
// @version      7.7.8.1
// @description  Visual larp: Changes ARS to $ everywhere (bets, balance, everything) - keeps numbers the same
// @author       fusi | @loficat on tg | codedfusi on github
// @match        *://*.shuffle.com/*
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function () {
    const processedTextNodes = new WeakSet();
    const processedImages = new WeakSet();

    // Force update a text node
    function updateTextNode(node) {
        if (node.nodeType !== 3 || !node.nodeValue) return false;
        
        let original = node.nodeValue;
        let newValue = original;
        let changed = false;

        // Replace ARS with $ (case insensitive just in case)
        if (newValue.includes("ARS")) {
            newValue = newValue.replace(/ARS/g, "$");
            changed = true;
        }
        
        // Replace lowercase "ars" if it appears
        if (newValue.includes("ars")) {
            newValue = newValue.replace(/ars/g, "$");
            changed = true;
        }

        // Remove space after the new $
        if (changed) {
            newValue = newValue.replace(/\$\s+/g, '$');
        }

        if (changed && newValue !== original) {
            node.nodeValue = newValue;
            return true;
        }
        return false;
    }

    function processTextNode(node) {
        if (node.nodeType === 3 && node.nodeValue && !processedTextNodes.has(node)) {
            if (updateTextNode(node)) {
                processedTextNodes.add(node);
            }
        }
    }

    function processImageElement(el) {
        if (el.nodeType === 1 && el.hasAttribute("src") && !processedImages.has(el)) {
            const src = el.getAttribute("src");
            if (src && src.includes("/icons/fiat/ARS.svg")) {
                el.setAttribute("src", src.replace("/icons/fiat/ARS.svg", "/icons/fiat/USD.svg"));
                processedImages.add(el);
            }
        }
    }

    function walkAndProcess(root) {
        if (!root) return;

        // Process all text nodes
        const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);
        let node;
        while ((node = walker.nextNode())) {
            processTextNode(node);
        }

        // Process all ARS flag images
        const images = root.querySelectorAll('img[src*="/icons/fiat/ARS.svg"]');
        images.forEach(img => processImageElement(img));
    }

    // More aggressive mutation handling
    function onMutation(mutations) {
        let needsFullScan = false;
        
        for (const mutation of mutations) {
            // If attributes changed (like a bet amount updating), scan the target
            if (mutation.type === 'attributes') {
                if (mutation.target.nodeType === 1) {
                    // Re-scan this element and its children
                    walkAndProcess(mutation.target);
                    // Also scan its parent in case the change bubbled
                    if (mutation.target.parentNode) {
                        walkAndProcess(mutation.target.parentNode);
                    }
                }
                needsFullScan = true;
            }
            
            // If child nodes were added, process them
            if (mutation.type === 'childList') {
                for (const addedNode of mutation.addedNodes) {
                    if (addedNode.nodeType === 1) {
                        walkAndProcess(addedNode);
                    } else if (addedNode.nodeType === 3) {
                        processTextNode(addedNode);
                    }
                }
                needsFullScan = true;
            }
            
            // If text itself changed (characterData mutation)
            if (mutation.type === 'characterData') {
                if (mutation.target.nodeType === 3) {
                    // Re-process this text node even if it was processed before
                    const node = mutation.target;
                    if (node.nodeValue && (node.nodeValue.includes("ARS") || node.nodeValue.includes("ars"))) {
                        updateTextNode(node);
                    }
                }
                needsFullScan = true;
            }
        }
        
        // Do a quick partial scan of the body periodically to catch anything missed
        if (needsFullScan) {
            setTimeout(() => {
                // Scan the whole body but skip nodes we've already processed to save performance
                const allTextNodes = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);
                let tn;
                while ((tn = allTextNodes.nextNode())) {
                    if (tn.nodeValue && (tn.nodeValue.includes("ARS") || tn.nodeValue.includes("ars"))) {
                        if (updateTextNode(tn)) {
                            processedTextNodes.add(tn);
                        }
                    }
                }
            }, 100);
        }
    }

    // Start when DOM is ready
    document.addEventListener("DOMContentLoaded", () => {
        walkAndProcess(document.body);

        // Watch for attribute changes (like bet amounts), text changes, AND child lists
        const observer = new MutationObserver(onMutation);
        observer.observe(document.body, {
            childList: true,
            subtree: true,
            attributes: true,      // <-- CRITICAL: catches bet amount updates
            attributeFilter: ['textContent', 'innerHTML', 'value'], // Focus on text-related attributes
            characterData: true    // <-- CRITICAL: catches direct text changes
        });
        
        // Also run every second as a backup (heavy but ensures bets get caught)
        setInterval(() => {
            const allTextNodes = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);
            let tn;
            while ((tn = allTextNodes.nextNode())) {
                if (tn.nodeValue && (tn.nodeValue.includes("ARS") || tn.nodeValue.includes("ars"))) {
                    updateTextNode(tn);
                }
            }
        }, 1000);
    });
})();