TriX Executor for Territorial.io

A command-based executor with a loadable "Auto-Join & Play" featured script module.

当前为 2025-07-01 提交的版本,查看 最新版本

// ==UserScript==
// @name         TriX Executor for Territorial.io
// @namespace    Violentmonkey Scripts
// @version      19.0
// @description  A command-based executor with a loadable "Auto-Join & Play" featured script module.
// @author       Assistant
// @match        https://territorial.io/*
// @match        https://*.croxyproxy.com/*territorial.io*
// @match        https://*/*?__cpo=*
// @grant        none
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // --- Configuration: Random Username Parts (Shared by all modules) ---
    const baseNames = [
        'Strategist', 'Ironclad', 'Vanguard', 'Tactician', 'Swiftstrike', 'Commander', 'Sentinel', 'Echo', 'Shadow', 'Apex',
        'Overwatch', 'Pioneer', 'Horizon', 'Maverick', 'Pathfinder', 'Siege', 'Rampart', 'Nexus', 'Warden', 'Beacon',
        'Vengeance', 'Fury', 'Razor', 'Annihilator', 'Slayer', 'Berserker', 'Havoc', 'Destroyer', 'Venom', 'Overlord',
        'Executioner', 'Dominator', 'Reaper', 'Conqueror', 'Thunder', 'Juggernaut', 'Warlord', 'Avalanche', 'Brutal',
        'Phantom', 'Specter', 'Cipher', 'Rogue', 'Enigma', 'Obscure', 'Whisper', 'Nomad', 'Drifter', 'Wanderer', 'Cryptic',
        'Illusionist', 'Abyss', 'Void', 'Stalker', 'Wraith', 'Shade', 'Mirage', 'Eclipse', 'Pixel', 'Ninja', 'Quasar',
        'Goblin', 'Sparky', 'Unicorn', 'GummyBear', 'Captain', 'Phoenix', 'Fuzzy', 'Whiz', 'Zoom', 'Giggle', 'Panda',
        'Retro', 'Waffle', 'Disco', 'Cosmic', 'Jellyfish', 'BubbleGum', 'Player', 'Gamer', 'Pro', 'Warrior', 'Legend',
        'Elite', 'Ace', 'Ruler', 'Master', 'Chief', 'Hunter', 'Zealot', 'Crusader', 'Guardian', 'Knight', 'Baron',
        'Duke', 'King', 'Queen', 'Aegis', 'Alpha', 'Amazon', 'Ambush', 'Android', 'Apollo', 'Arcane', 'Archer',
        'Arctic', 'Argon', 'Argus', 'Ares', 'Armada', 'Arrow', 'Artillery', 'Asgard', 'Ash', 'Assassin', 'Asteroid',
        'Astra', 'Atlas', 'Atom', 'Aurora', 'Avatar', 'Avenger', 'Axiom', 'Azrael', 'Azure', 'Ballista', 'Bandit',
        'Banshee', 'Barbarian', 'Barrage', 'Basilisk', 'Bastion', 'Battalion', 'Bear', 'Behemoth', 'Biscuit', 'Blackout',
        'Blade', 'Blaster', 'Blaze', 'Blitz', 'Blizzard', 'Blockade', 'Bolt', 'Bomber', 'Boop', 'Borealis', 'Breaker',
        'Brigade', 'Bullet', 'Button', 'Cabal', 'Cadet', 'Caliber', 'Canyon', 'Cascade', 'Cataclysm', 'Catalyst', 'Catapult',
        'Cavalry', 'Centurion', 'Cerberus', 'Chaos', 'Charger', 'Chimera', 'Cinder', 'Citadel', 'Cleric', 'Cliff', 'Cobra'
    ];

    // --- State Variables ---
    let trixAutomationRunning = false;
    let trixSpammingActive = false;
    let trixSpaceSpamIntervalId = null;
    let autoJoinScriptExecuted = false; // Prevents executing the featured script multiple times

    // Stop immediately if this isn't a territorial.io page.
    if (!isTerritorialPage()) return;


    // --- UI CREATION AND MANAGEMENT ---

    function createExecutorUI() {
        const executor = document.createElement('div');
        executor.id = 'trix-executor';
        Object.assign(executor.style, {
            position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)',
            width: '550px', height: '400px', backgroundColor: '#1e1e1e', border: '1px solid #444',
            borderRadius: '5px', zIndex: '100000', display: 'flex', flexDirection: 'column',
            boxShadow: '0 0 15px rgba(0,0,0,0.5)', fontFamily: 'Consolas, "Courier New", monospace'
        });
        const header = document.createElement('div');
        header.id = 'trix-header';
        header.innerHTML = `<img src="https://i.postimg.cc/pVhYV8kL/image.png" style="height: 20px; margin-right: 10px; vertical-align: middle;"> TriX`;
        Object.assign(header.style, {
            backgroundColor: '#111', color: 'white', padding: '8px',
            cursor: 'move', borderTopLeftRadius: '5px', borderTopRightRadius: '5px'
        });
        const body = document.createElement('div');
        Object.assign(body.style, { display: 'flex', flexGrow: '1', overflow: 'hidden' });
        const sidebar = document.createElement('div');
        Object.assign(sidebar.style, {
            width: '160px', backgroundColor: '#252526', padding: '10px 0', borderRight: '1px solid #444'
        });
        sidebar.innerHTML = `
            <button class="trix-nav-button active" data-page="cmd">Command Prompt</button>
            <button class="trix-nav-button" data-page="scripts">Featured Scripts</button>
        `;
        const content = document.createElement('div');
        Object.assign(content.style, { flexGrow: '1', display: 'flex', flexDirection: 'column' });
        const cmdPage = document.createElement('div');
        cmdPage.id = 'trix-page-cmd';
        cmdPage.className = 'trix-page';
        Object.assign(cmdPage.style, { display: 'flex', flexDirection: 'column', height: '100%' });
        cmdPage.innerHTML = `
            <div id="trix-history" style="flex-grow: 1; padding: 10px; overflow-y: auto; font-size: 13px;"></div>
            <div style="display: flex; border-top: 1px solid #444;">
                <input type="text" id="trix-cmd-input" placeholder="Type a command..." style="flex-grow: 1; background: #333; border: none; color: white; padding: 8px; outline: none;">
                <button id="trix-send-btn" style="background: #0e639c; color: white; border: none; padding: 0 15px; cursor: pointer;">Send</button>
            </div>`;
        const scriptsPage = document.createElement('div');
        scriptsPage.id = 'trix-page-scripts';
        scriptsPage.className = 'trix-page';
        Object.assign(scriptsPage.style, { display: 'none', padding: '15px', overflowY: 'auto' });

        content.appendChild(cmdPage);
        content.appendChild(scriptsPage);
        body.appendChild(sidebar);
        body.appendChild(content);
        executor.appendChild(header);
        executor.appendChild(body);
        document.body.appendChild(executor);

        const style = document.createElement('style');
        style.textContent = `
            .trix-nav-button { background: none; border: none; color: #ccc; display: block; width: 100%; text-align: left; padding: 10px 15px; cursor: pointer; font-family: inherit; font-size: 14px; }
            .trix-nav-button:hover { background: #333; }
            .trix-nav-button.active { background: #0e639c; color: white; }
            #trix-history .trix-log { margin-bottom: 5px; }
            #trix-history .trix-error { color: #f44336; }
            #trix-history .trix-success { color: #4CAF50; }
            .featured-script-card { background-color: #2a2d2e; border: 1px solid #444; border-radius: 4px; padding: 15px; display: flex; align-items: center; gap: 15px; }
            .featured-script-card img { width: 64px; height: 64px; border-radius: 4px; }
            .featured-script-card .info p { margin: 5px 0 10px; font-size: 13px; color: #ccc; }
            .featured-script-card button { background: #4CAF50; color: white; border: none; padding: 8px 12px; border-radius: 4px; cursor: pointer; }
            .featured-script-card button:disabled { background: #555; cursor: not-allowed; }
        `;
        document.head.appendChild(style);

        makeDraggable(executor, header);
        setupCommandPrompt();
        setupSidebarNavigation();
        populateFeaturedScripts(); // New function call
        logToHistory("Welcome to TriX Executor. Type /help for commands.");
    }

    function populateFeaturedScripts() {
        const container = document.getElementById('trix-page-scripts');
        const scriptCard = document.createElement('div');
        scriptCard.className = 'featured-script-card';
        scriptCard.innerHTML = `
            <img src="https://i.postimg.cc/P5w5PX9Z/image.png" alt="Script Logo">
            <div class="info">
                <h3>Auto-Join & Play</h3>
                <p>Loads a full-featured script with F-key controls, multi-tab "arming", and its own status dashboard.</p>
                <button id="execute-auto-join">Execute</button>
            </div>
        `;
        container.appendChild(scriptCard);

        const executeButton = document.getElementById('execute-auto-join');
        executeButton.addEventListener('click', () => {
            if (autoJoinScriptExecuted) {
                logToHistory("Auto-Join & Play script is already running.", 'error');
                return;
            }
            logToHistory("Executing Auto-Join & Play script...", 'success');
            executeAutoJoinAndPlayScript(); // The main event!
            executeButton.textContent = 'Executed ✔';
            executeButton.disabled = true;
        });
    }

    function createStatusDashboard(id, title) {
        if (document.getElementById(id)) return;
        const dashboard = document.createElement('div');
        dashboard.id = id;
        Object.assign(dashboard.style, {
            position: 'fixed', top: '20px', left: '20px', zIndex: '99999', display: 'none',
            backgroundColor: 'rgba(0, 0, 0, 0.75)', color: 'white',
            border: '1px solid #888', borderRadius: '8px',
            fontFamily: 'sans-serif', fontSize: '14px', minWidth: '280px', userSelect: 'none'
        });
        dashboard.innerHTML = `
            <div id="${id}-header" style="padding: 8px 12px; background-color: #333; cursor: move; border-top-left-radius: 8px; border-top-right-radius: 8px;">
                <strong>${title}</strong>
            </div>
            <div style="padding: 12px;"><strong>Status:</strong> <span id="${id}-text">Idle</span></div>
        `;
        document.body.appendChild(dashboard);
        makeDraggable(dashboard, dashboard.querySelector(`#${id}-header`));
    }


    // --- COMMAND PROMPT HANDLING ---

    function setupCommandPrompt() {
        const input = document.getElementById('trix-cmd-input');
        const sendBtn = document.getElementById('trix-send-btn');
        const handler = () => { if (input.value.trim()) { handleCommand(input.value); input.value = ''; } };
        input.addEventListener('keydown', (e) => { if (e.key === 'Enter') handler(); });
        sendBtn.addEventListener('click', handler);
    }

    function handleCommand(command) {
        logToHistory(`> ${command}`);
        const [cmd, ...args] = command.trim().toLowerCase().split(' ');
        const dashboard = document.getElementById('trix-status-dashboard');

        if (cmd === '/auto-join') {
            if (trixAutomationRunning) return logToHistory("Auto-Join sequence is already running.", 'error');
            if(dashboard) dashboard.style.display = 'block';
            trixAutomationRunning = true;
            startTrixAutomation();
        } else if (cmd === '/spam') {
            if (trixSpammingActive) return logToHistory("Spam is already active.", 'error');
            const interval = parseTimeInterval(args[0]);
            if (interval) { logToHistory(`Starting space spam every ${args[0]}.`, 'success'); startTrixSpaceSpam(interval); }
            else { logToHistory("Invalid time interval. Use format like '5s' or '2min'.", 'error'); }
        } else if (cmd === '/stop') {
             if(trixSpammingActive) { stopTrixSpaceSpam(); logToHistory("Spam stopped.", 'success'); }
             else { logToHistory("Nothing to stop.", 'error'); }
        } else if (cmd === '/help') {
            logToHistory("Available Commands:");
            logToHistory("/auto-join - Starts the simple join sequence.");
            logToHistory("/spam [interval] - Starts space spam (e.g., /spam 5s).");
            logToHistory("/stop - Stops the space spam.");
        } else { logToHistory(`Unknown command: ${cmd}`, 'error'); }
    }

    // --- TriX EXECUTOR AUTOMATION ---

    function startTrixAutomation() {
        logToHistory("Starting simple automation sequence...", 'success');
        updateStatus('trix-status-dashboard', 'Running sequence...');
        autoFillUsername().then(() => waitForElementAndClick(findMultiplayerButton, "'Multiplayer' button"))
            .then(() => waitForElementAndClick(findReadyButton, "'Ready' button"))
            .then(() => {
                trixAutomationRunning = false;
                updateStatus('trix-status-dashboard', 'Sequence Complete.');
                logToHistory("Simple Auto-Join complete!", 'success');
            })
            .catch(error => { trixAutomationRunning = false; updateStatus('trix-status-dashboard', 'Error!'); logToHistory(error.message, 'error'); });
    }

    function startTrixSpaceSpam(intervalMs) {
        if (trixSpammingActive) return;
        trixSpammingActive = true;
        updateStatus('trix-status-dashboard', `Spamming Space key every ${intervalMs / 1000}s...`);
        trixSpaceSpamIntervalId = setInterval(() => { document.dispatchEvent(new KeyboardEvent('keydown', { 'key': ' ', 'code': 'Space', 'keyCode': 32, 'bubbles': true })); }, intervalMs);
    }
    function stopTrixSpaceSpam() {
        if (!trixSpammingActive) return;
        clearInterval(trixSpaceSpamIntervalId);
        trixSpammingActive = false;
        updateStatus('trix-status-dashboard', 'Spam Stopped. Idle.');
    }


    // --- FEATURED SCRIPT: Auto-Join & Play ---
    // This entire block is a self-contained module that only runs when called.

    function executeAutoJoinAndPlayScript() {
        autoJoinScriptExecuted = true;
        const legacyBaseNames = [ // The massive list for this module
            'Abyss', 'Ace', 'Aegis', 'Agent', 'Algorithm', 'Alpha', 'Alpine', 'Amazon', 'Ambush', 'Android', 'Annihilator',
            'Apex', 'Apollo', 'Arcane', 'Archer', 'Arctic', 'Argon', 'Argus', 'Ares', 'Armada', 'Arrow', 'Artillery', 'Asgard',
            'Ash', 'Assassin', 'Asteroid', 'Astra', 'Atlas', 'Atom', 'Aurora', 'Avalanche', 'Avatar', 'Avenger', 'Axiom',
            'Azrael', 'Azure', 'Ballista', 'Bandit', 'Banshee', 'Barbarian', 'Baron', 'Barrage', 'Basilisk', 'Bastion', 'Battalion',
            'Beacon', 'Bear', 'Behemoth', 'Berserker', 'Biscuit', 'Blackout', 'Blade', 'Blaster', 'Blaze', 'Blitz', 'Blizzard',
            'Blockade', 'Bolt', 'Bomber', 'Boop', 'Borealis', 'Breaker', 'Brigade', 'Brutal', 'BubbleGum', 'Bullet', 'Button',
            'Cabal', 'Cadet', 'Caliber', 'Canyon', 'Captain', 'Cascade', 'Cataclysm', 'Catalyst', 'Catapult', 'Cavalry', 'Centurion',
            'Cerberus', 'Chaos', 'Charger', 'Chief', 'Chimera', 'Cinder', 'Cipher', 'Citadel', 'Cleric', 'Cliff', 'Cobra', 'Colonel',
            'Colossus', 'Comet', 'Commander', 'Commando', 'Conqueror', 'Constellation', 'Cosmic', 'Cougar', 'Coyote', 'Crash', 'Crater',
            'Creek', 'Crescent', 'Crossbow', 'Crown', 'Crucible', 'Crusader', 'Cryptic', 'Crystal', 'Curse', 'Cyber', 'Cyclone', 'Cyclops',
            'Daemon', 'Dagger', 'Deadeye', 'Deathwish', 'Decoy', 'Delta', 'Demon', 'Desert', 'Desolator', 'Destroyer', 'Diablo', 'Diamond',
            'Digger', 'Disco', 'Doodle', 'Doomsday', 'Dozer', 'Draco', 'Dragon', 'Drifter', 'Droid', 'Druid', 'Duke', 'Dune', 'Dust', 'Dynamite',
            'Dynamo', 'Dynasty', 'Eagle', 'Earthquake', 'Echo', 'Eclipse', 'Edict', 'Einherjar', 'Elder', 'Element', 'Elite', 'Elysium',
            'Ember', 'Emperor', 'Empire', 'Enforcer', 'Enigma', 'Entity', 'Envoy', 'Eon', 'Epoch', 'Era', 'Eruption', 'Eternal', 'Everest',
            'Executioner', 'Exile', 'Exodus', 'Factor', 'Falcon', 'Famine', 'Fang', 'Faze', 'Fenrir', 'Firewall', 'Fissure', 'Flame',
            'Flash', 'Flux', 'Forerunner', 'Forest', 'Forge', 'Fortress', 'Fox', 'Fragment', 'Frenzy', 'Frost', 'Fury', 'Fuse',
            'Fusion', 'Fuzzy', 'Gadget', 'Gale', 'Gamma', 'Gamer', 'Gargoyle', 'Garrison', 'Gauntlet', 'Geist', 'General', 'Genesis',
            'Ghost', 'Giant', 'Giggle', 'Glacier', 'Gladiator', 'Glitch', 'Gloom', 'Gnasher', 'Goblin', 'Golem', 'Goliath', 'Gorgon',
            'Granite', 'Gravity', 'Gremlin', 'Griffin', 'Grim', 'Grizzly', 'Groove', 'Guardian', 'Guerilla', 'Gully', 'GummyBear',
            'Gunner', 'Hades', 'Hailstorm', 'Hammer', 'Harbinger', 'Harpy', 'Havoc', 'Hawk', 'Hazard', 'Haze', 'Headhunter',
            'Hellfire', 'Hellion', 'Herald', 'Hermes', 'Hero', 'Hex', 'Hive', 'Horizon', 'Hornet', 'Hunter', 'Hurricane', 'Husk',
            'Hydra', 'Hyperion', 'Ice', 'Icarus', 'Icon', 'Ifrit', 'Illusionist', 'Impact', 'Impulse', 'Incendiary', 'Inferno',
            'Infinity', 'Infantry', 'Inquisitor', 'Ion', 'Iron', 'Ironclad', 'Jaguar', 'Javelin', 'Jawbreaker', 'Jellyfish', 'Jester',
            'Jet', 'Jinx', 'Jotun', 'Juggernaut', 'Jungle', 'Juno', 'Jupiter', 'Kaiser', 'Kami', 'Karma', 'Kestrel', 'King', 'Kismet',
            'Knight', 'Kodiak', 'Kraken', 'Kyrie', 'Labyrinth', 'Lagoon', 'Lancer', 'Landslide', 'Laser', 'Lava', 'Legacy',
            'Legend', 'Legion', 'Leopard', 'Leviathan', 'Lightning', 'Lion', 'Lizard', 'Locus', 'Lotus', 'Lumberjack', 'Luna', 'Lynx'
        ];
        let isLegacyAutomationRunning = false;
        let isLegacySpammingActive = false;
        let legacySpaceSpamIntervalId = null;
        let isLegacyArmed = sessionStorage.getItem('territorialAutoStartArmed') === 'true';

        // --- Create this module's UI ---
        const dashboardId = 'legacy-dashboard';
        createLegacyDashboard();
        updateLegacyDashboardStatus(`Auto-start ${isLegacyArmed ? 'ARMED' : 'DISARMED'}.`);

        // --- Add this module's event listeners ---
        document.addEventListener('keydown', (event) => {
            if (event.key === 'F6') { event.preventDefault(); toggleLegacyManualSequence(); }
            if (event.key === 'F7') { event.preventDefault(); toggleLegacyArmedState(); }
        });
        document.addEventListener('visibilitychange', () => {
            if (document.visibilityState === 'visible' && isLegacyArmed && !isLegacyAutomationRunning && !isLegacySpammingActive) {
                isLegacyAutomationRunning = true; startLegacyAutomation();
            }
        });

        // --- All the logic for this module, namespaced with "Legacy" ---
        function toggleLegacyManualSequence() {
            if (isLegacySpammingActive) { stopLegacySpaceSpam(); }
            else if (!isLegacyAutomationRunning) { isLegacyAutomationRunning = true; startLegacyAutomation(); }
        }
        function toggleLegacyArmedState() {
            isLegacyArmed = !isLegacyArmed;
            sessionStorage.setItem('territorialAutoStartArmed', isLegacyArmed);
            updateLegacyDashboardStatus(`Auto-start ${isLegacyArmed ? 'ARMED' : 'DISARMED'}.`);
        }
        function startLegacyAutomation() {
            updateLegacyDashboardStatus('Running sequence...');
            autoFillUsername(legacyBaseNames)
                .then(() => waitForElementAndClick(findMultiplayerButton, "'Multiplayer' button"))
                .then(() => waitForElementAndClick(findReadyButton, "'Ready' button"))
                .then(() => { isLegacyAutomationRunning = false; startLegacySpaceSpam(); })
                .catch(error => { isLegacyAutomationRunning = false; updateLegacyDashboardStatus('Error!'); logToHistory(error.message, 'error'); });
        }
        function startLegacySpaceSpam() {
            if (isLegacySpammingActive) return;
            isLegacySpammingActive = true;
            updateLegacyDashboardStatus('Spamming Space key every 5s...');
            legacySpaceSpamIntervalId = setInterval(() => { document.dispatchEvent(new KeyboardEvent('keydown', { 'key': ' ', 'code': 'Space', 'keyCode': 32, 'bubbles': true })); }, 5000);
        }
        function stopLegacySpaceSpam() {
            if (!isLegacySpammingActive) return;
            clearInterval(legacySpaceSpamIntervalId);
            isLegacySpammingActive = false;
            updateLegacyDashboardStatus('Idle.');
        }

        // --- UI for this module ---
        function createLegacyDashboard() {
            const dashboard = document.createElement('div');
            Object.assign(dashboard.style, {
                position: 'fixed', top: '150px', left: '20px', zIndex: '99998',
                backgroundColor: 'rgba(0, 0, 0, 0.75)', color: 'white', border: '1px solid #888', borderRadius: '8px',
                fontFamily: 'sans-serif', fontSize: '14px', minWidth: '280px', userSelect: 'none'
            });
            const header = document.createElement('div');
            Object.assign(header.style, { padding: '8px 12px', backgroundColor: '#333', cursor: 'move', borderRadius: '8px 8px 0 0', display: 'flex', justifyContent: 'space-between' });
            header.innerHTML = '<strong>Legacy Auto-Play</strong>';
            const content = document.createElement('div');
            content.innerHTML = `<ul style="margin: 12px 0 12px 20px; padding: 0; list-style-type: '» ';">
                <li><code>F7</code> to arm/disarm auto-start.</li>
                <li><code>F6</code> to start/stop script.</li>
                <li><strong>Status:</strong> <span id="legacy-dashboard-status">Idle</span></li>
            </ul>`;
            dashboard.appendChild(header);
            dashboard.appendChild(content);
            document.body.appendChild(dashboard);
            makeDraggable(dashboard, header);
        }
        function updateLegacyDashboardStatus(text) {
            const el = document.getElementById('legacy-dashboard-status');
            if (el) el.textContent = text;
        }
    }


    // --- SHARED UTILITY FUNCTIONS ---

    function autoFillUsername(nameList = baseNames) { // Can be called with a specific list
        return new Promise((resolve, reject) => {
            waitForElement(findUsernameInput, 'Username Input Field').then(nameInput => {
                const username = nameList[Math.floor(Math.random() * nameList.length)];
                updateStatus('trix-status-dashboard', `Setting name: ${username}`);
                nameInput.value = username;
                nameInput.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));
                nameInput.focus();
                nameInput.blur();
                setTimeout(resolve, 200);
            }).catch(reject);
        });
    }

    function logToHistory(message, type = 'log') {
        const history = document.getElementById('trix-history');
        if (!history) return;
        const entry = document.createElement('div');
        entry.className = `trix-${type}`;
        entry.textContent = message;
        history.appendChild(entry);
        history.scrollTop = history.scrollHeight;
    }

    function updateStatus(dashboardId, text) {
        const textEl = document.getElementById(`${dashboardId}-text`);
        if (textEl) textEl.innerText = text;
    }

    function parseTimeInterval(timeString) {
        if (!timeString) return null;
        const match = timeString.match(/^(\d+)(s|min)$/);
        if (!match) return null;
        let seconds = parseInt(match[1], 10);
        if (match[2] === 'min') { seconds *= 60; }
        return (seconds > (9 * 60 + 59) || seconds <= 0) ? null : seconds * 1000;
    }

    function makeDraggable(element, handle) {
        let isDragging = false, offsetX, offsetY;
        handle.onmousedown = (e) => {
            isDragging = true;
            offsetX = e.clientX - element.offsetLeft;
            offsetY = e.clientY - element.offsetTop;
            document.onmousemove = (e) => { if (isDragging) { element.style.left = `${e.clientX - offsetX}px`; element.style.top = `${e.clientY - offsetY}px`; } };
            document.onmouseup = () => { isDragging = false; document.onmousemove = document.onmouseup = null; };
        };
    }

    function isTerritorialPage() {
        const href = window.location.href;
        if (href.includes('territorial.io')) return true;
        if (href.includes('?__cpo=')) { try { return atob(new URLSearchParams(window.location.search).get('__cpo')).includes('territorial.io'); } catch (e) { return false; } }
        return false;
    }

    function waitForElement(findFunction, description) {
        return new Promise((resolve, reject) => {
            let attempts = 0, maxAttempts = 75;
            const interval = setInterval(() => {
                if (attempts++ >= maxAttempts) { clearInterval(interval); reject(new Error(`Timed out: ${description}`)); return; }
                const element = findFunction();
                if (element) { clearInterval(interval); resolve(element); }
            }, 200);
        });
    }

    function waitForElementAndClick(findFunction, description) {
        return waitForElement(findFunction, description).then(element => element.click());
    }

    const findUsernameInput = () => document.getElementById('input0');
    const findMultiplayerButton = () => Array.from(document.querySelectorAll('button')).find(btn => btn.innerText.includes('Multiplayer'));
    const findReadyButton = () => Array.from(document.querySelectorAll('button')).find(btn => btn.innerText.trim().startsWith('Ready'));


    // --- INITIALIZER ---
    function initialize() {
        waitForElement(findUsernameInput, "Game UI to load")
            .then(() => {
                console.log("[TriX] Executor Loaded.");
                createExecutorUI();
                createStatusDashboard('trix-status-dashboard', 'TriX Automation Status');
            })
            .catch(error => { console.error("[TriX] Could not initialize, game UI did not load in time.", error); });
    }

    initialize();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址