TriX Executor for Territorial.io

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

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

// ==UserScript==
// @name         TriX Executor for Territorial.io
// @namespace    Violentmonkey Scripts
// @version      20.0
// @description  Fixes sidebar navigation. A command-based executor with a loadable "Auto-Join & Play" 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 ---
    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;

    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();
        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) { return logToHistory("Auto-Join & Play script is already running.", 'error'); }
            logToHistory("Executing Auto-Join & Play script...", 'success');
            executeAutoJoinAndPlayScript();
            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-radius: 8px 8px 0 0;"><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 & NAVIGATION ---

    function setupCommandPrompt() {
        const input = document.getElementById('trix-cmd-input'), 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 setupSidebarNavigation() {
        const buttons = document.querySelectorAll('.trix-nav-button');
        buttons.forEach(button => {
            button.addEventListener('click', () => {
                buttons.forEach(btn => btn.classList.remove('active'));
                button.classList.add('active');
                const pageId = `trix-page-${button.dataset.page}`;
                document.querySelectorAll('.trix-page').forEach(page => {
                    // **THE FIX IS HERE:** Apply the correct display style for each specific page.
                    if (page.id === pageId) {
                        page.style.display = (page.id === 'trix-page-cmd') ? 'flex' : 'block';
                    } else {
                        page.style.display = 'none';
                    }
                });
            });
        });
    }

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

    function executeAutoJoinAndPlayScript() {
        autoJoinScriptExecuted = true;
        const legacyBaseNames = [ '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, isLegacySpammingActive = false, legacySpaceSpamIntervalId = null;
        let isLegacyArmed = sessionStorage.getItem('territorialAutoStartArmed') === 'true';

        createLegacyDashboard();
        updateLegacyDashboardStatus(`Auto-start ${isLegacyArmed ? 'ARMED' : 'DISARMED'}.`);

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

        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.'); }

        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) { 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 > 599 || 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或关注我们的公众号极客氢云获取最新地址