Gartic IO Word Collector with Auto Skip

Collects words presented during the game, saves them to a file, and auto-skips

当前为 2025-03-06 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Gartic IO Word Collector with Auto Skip
// @namespace    http://tampermonkey.net/
// @version      2025-03-06
// @description  Collects words presented during the game, saves them to a file, and auto-skips
// @author       anonimbiri
// @license      MIT
// @match        https://gartic.io/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=gartic.io
// @run-at       document-start
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Modify appendChild to intercept and alter the game's script
    Node.prototype.appendChild = new Proxy(Node.prototype.appendChild, {
        apply: function(target, thisArg, argumentsList) {
            const node = argumentsList[0];
            if (node.nodeName.toLowerCase() === 'script' && node.src && node.src.includes('room')) {
                console.log('Hedef script algılandı:', node.src);
                fetch(node.src)
                    .then(response => response.text())
                    .then(scriptContent => {
                    let modifiedContent = scriptContent
                    .replace(
                        'r.created||c?Rt("input",{type:"text",name:"chat",className:"mousetrap",autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",value:i,placeholder:this._lang.chatHere,maxLength:100,enterKeyHint:"send",onChange:this.handleText,ref:this._ref}):Rt("input",{type:"text",name:"chat",className:"mousetrap",autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",value:this._lang.loginChat,maxLength:100,ref:this._ref,disabled:!0})',
                        'Rt("input",{type:"text",name:"chat",className:"mousetrap",autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",value:i,placeholder:this._lang.chatHere,maxLength:100,enterKeyHint:"send",onChange:this.handleText,ref:this._ref})'
                    )
                    .replace(
                        'this._timerAtivo=setInterval((function(){Date.now()-e._ativo>15e4&&(O(Object(f.a)(n.prototype),"emit",e).call(e,"avisoInativo"),e._ativo=Date.now())}),1e3)',
                        'this._timerAtivo=setInterval((function(){Date.now()-e._ativo>15e4&&e.active()}),1e3)'
                    )
                    .replace(
                        'e.unlock()}',
                        'e.unlock();window.game=e;setInterval(()=>{window.game=e},1000);}'
                    );
                    let blob = new Blob([modifiedContent], { type: 'application/javascript' });
                    let blobUrl = URL.createObjectURL(blob);
                    node.src = blobUrl;
                    node.textContent = '';
                    return target.apply(thisArg, [node]);
                })
                    .catch(error => {
                    console.error('Failed to fetch/modify script:', error);
                    return target.apply(thisArg, argumentsList);
                });
                return node;
            }
            return target.apply(thisArg, argumentsList);
        }
    });

    // Define wordList globally on window object
    window.wordList = {
        "custom": [],
        "General (en)": [],
        "General (tr)": [],
        "Anime (en)": []
    };

    // Function to save wordList to a file
    function saveWordListToFile() {
        const theme = window.game && window.game._dadosSala && window.game._dadosSala.tema ? window.game._dadosSala.tema : "custom";
        const words = window.wordList[theme].join('\n');
        const blob = new Blob([words], { type: 'text/plain;charset=utf-8' });
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.download = `${theme}_words.txt`;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(url);
    }

    // Inject UI for the word collector (right side, vertical)
    const collectorHTML = `
        <div id="wordCollector" style="position: fixed; top: 20px; right: 20px; width: 200px; background: rgba(30, 30, 47, 0.9); padding: 15px; border-radius: 8px; color: #fff; z-index: 1000; display: flex; flex-direction: column; gap: 10px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);">
            <h3 style="margin: 0; color: #ff69b4; font-size: 16px; text-align: center;">Word Collector</h3>
            <p style="margin: 0; font-size: 12px; text-align: center;">Collects words and skips turn</p>
            <button id="saveWordsBtn" style="background: #ff69b4; border: none; padding: 8px; border-radius: 5px; color: #1e1e2f; cursor: pointer; font-size: 14px;">Save Words</button>
            <div id="wordCount" style="font-size: 12px; text-align: center;"></div>
        </div>
    `;
    document.body.insertAdjacentHTML('beforeend', collectorHTML);

    // Update word count display
    function updateWordCount() {
        const theme = window.game && window.game._dadosSala && window.game._dadosSala.tema ? window.game._dadosSala.tema : "custom";
        const count = window.wordList[theme].length;
        document.getElementById('wordCount').textContent = `Words (${theme}): ${count}`;
    }

    // Add save button event listener
    document.getElementById('saveWordsBtn').addEventListener('click', () => {
        saveWordListToFile();
    });

    // Check for game object and collect words + auto-skip
    const checkGame = setInterval(() => {
        if (window.game && window.game._socket) {
            clearInterval(checkGame);

            // Collect words when your turn comes (event 16) and auto-skip
            window.game._socket.on(16, (word1, hints1, word2, hints2) => {
                const theme = window.game._dadosSala.tema || "custom";

                // Add words to the appropriate category if not already present
                if (!window.wordList[theme].includes(word1)) {
                    window.wordList[theme].push(word1);
                }
                if (!window.wordList[theme].includes(word2)) {
                    window.wordList[theme].push(word2);
                }

                // Update the word count display
                updateWordCount();

                // Auto-skip after collecting words
                setTimeout(() => {
                    if (window.game && window.game._socket && window.game._codigo) {
                        window.game._socket.emit(25, window.game._codigo);
                    }
                }, 500); // 500ms delay to ensure words are processed
            });

            // Collect the word when a turn ends and the answer is revealed (event 18 - intervalo)
            window.game._socket.on(18, (answer) => {
                if (answer) { // Only collect if answer is provided (not null/undefined)
                    const theme = window.game._dadosSala.tema || "custom";

                    // Add the word if not already present
                    if (!window.wordList[theme].includes(answer)) {
                        window.wordList[theme].push(answer);
                        console.log(`Word gathered at the end of the tour: ${answer}`);
                    }

                    // Update the word count display
                    updateWordCount();
                }
            });

            // Initial word count update
            updateWordCount();
        }
    }, 100);

})();