Emulation's Slither Client

Enhanced Slither.io mod with new features, fixed bot AI, professional UI, and immersive loading screen.

// ==UserScript==
// @name         Emulation's Slither Client
// @namespace    http://slither.com/io
// @version      2.6
// @description  Enhanced Slither.io mod with new features, fixed bot AI, professional UI, and immersive loading screen.
// @author       Emulation12
// @match        http://slither.com/io
// @grant        none
// @license      MIT
// ==/UserScript==  */

/* Utility Functions */
const savePreference = (key, value) => localStorage.setItem(key, JSON.stringify(value));
const loadPreference = (key, def) => JSON.parse(localStorage.getItem(key)) ?? def;

/* State Variables */
let IsBotActive = loadPreference('IsBotActive', true);
let isSpeedBoost = loadPreference('isSpeedBoost', false);
let showEnemyLines = loadPreference('showEnemyLines', true);
let showDangerBar = loadPreference('showDangerBar', true);
let showPlayerGlow = loadPreference('showPlayerGlow', false);
let autoRespawn = loadPreference('autoRespawn', false);
let aggressiveMode = loadPreference('aggressiveMode', false);
let defensiveMode = loadPreference('defensiveMode', false);
let speedModulation = loadPreference('speedModulation', false);
let autoZoom = loadPreference('autoZoom', false);
let enemyTrap = loadPreference('enemyTrap', false);
let showSpeedCooldown = loadPreference('showSpeedCooldown', true);
let showScoreTracker = loadPreference('showScoreTracker', true);
let customColors = loadPreference('customColors', false);
let autoDodge = loadPreference('autoDodge', false);
let menuVisible = false;
let favoriteMods = loadPreference('favoriteMods', []);
let activeTab = 'favorites-tab';
let isMinimized = false;
let targetFood = null;
let targetFoodTimestamp = 0;
let blacklistedFoods = {};
let criticDanger = false;
let lastSpeedBoost = 0;
let speedBoostCooldown = 3000; // 3 seconds cooldown
window.zoomMultiplier = loadPreference('zoomMultiplier', 1.0);
let customLineColor = loadPreference('customLineColor', '#ff0000');
let customMinimapColor = loadPreference('customMinimapColor', '#00ff88');

/* Mod Configuration */
const mods = [
    { id: 'bot', name: 'Bot', category: 'Bot', state: () => IsBotActive, toggle: (state) => { IsBotActive = state; state ? startFoodBot() : stopFoodBot(); savePreference('IsBotActive', state); } },
    { id: 'speedBoost', name: 'Speed Boost', category: 'Bot', state: () => isSpeedBoost, toggle: (state) => { if (Date.now() - lastSpeedBoost > speedBoostCooldown) { isSpeedBoost = state; window.setAcceleration?.(state ? 1 : 0); if (state) lastSpeedBoost = Date.now(); savePreference('isSpeedBoost', state); } } },
    { id: 'autoRespawn', name: 'Auto Respawn', category: 'Bot', state: () => autoRespawn, toggle: (state) => { autoRespawn = state; savePreference('autoRespawn', state); } },
    { id: 'aggressiveMode', name: 'Aggressive Mode', category: 'Bot', state: () => aggressiveMode, toggle: (state) => { aggressiveMode = state; defensiveMode = state ? false : defensiveMode; savePreference('aggressiveMode', state); savePreference('defensiveMode', defensiveMode); refreshTabs(); } },
    { id: 'defensiveMode', name: 'Defensive Mode', category: 'Bot', state: () => defensiveMode, toggle: (state) => { defensiveMode = state; aggressiveMode = state ? false : aggressiveMode; savePreference('defensiveMode', state); savePreference('aggressiveMode', aggressiveMode); refreshTabs(); } },
    { id: 'speedModulation', name: 'Speed Modulation', category: 'Bot', state: () => speedModulation, toggle: (state) => { speedModulation = state; savePreference('speedModulation', state); } },
    { id: 'autoZoom', name: 'Auto Zoom', category: 'Bot', state: () => autoZoom, toggle: (state) => { autoZoom = state; savePreference('autoZoom', state); } },
    { id: 'enemyTrap', name: 'Enemy Trap', category: 'Bot', state: () => enemyTrap, toggle: (state) => { enemyTrap = state; savePreference('enemyTrap', state); } },
    { id: 'autoDodge', name: 'Auto Dodge', category: 'Bot', state: () => autoDodge, toggle: (state) => { autoDodge = state; savePreference('autoDodge', state); } },
    { id: 'enemyLines', name: 'Enemy Lines', category: 'Visuals', state: () => showEnemyLines, toggle: (state) => { showEnemyLines = state; savePreference('showEnemyLines', state); } },
    { id: 'dangerBar', name: 'Danger Bar', category: 'Visuals', state: () => showDangerBar, toggle: (state) => { showDangerBar = state; savePreference('showDangerBar', state); } },
    { id: 'playerGlow', name: 'Player Glow', category: 'Visuals', state: () => showPlayerGlow, toggle: (state) => { showPlayerGlow = state; savePreference('showPlayerGlow', state); } },
    { id: 'showSpeedCooldown', name: 'Speed Cooldown', category: 'Visuals', state: () => showSpeedCooldown, toggle: (state) => { showSpeedCooldown = state; savePreference('showSpeedCooldown', state); } },
    { id: 'showScoreTracker', name: 'Score Tracker', category: 'Visuals', state: () => showScoreTracker, toggle: (state) => { showScoreTracker = state; savePreference('showScoreTracker', state); } },
    { id: 'customColors', name: 'Custom Colors', category: 'Visuals', state: () => customColors, toggle: (state) => { customColors = state; savePreference('customColors', state); } }
];

/* SVG Icons */
const icons = {
    Favorites: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg>`,
    Bot: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 15v5m-3-8h6m-8-4h10a2 2 0 012 2v6a2 2 0 01-2 2H7a2 2 0 01-2-2v-6a2 2 0 012-2zm-3 4h2m14 0h2"/></svg>`,
    Visuals: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>`,
    FavoriteOn: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></svg>`,
    FavoriteOff: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></svg>`
};

/* Zoom Control */
window.updateZoom = () => { window.gsc = window.zoomMultiplier; };
window.adjustZoom = (amount) => {
    window.zoomMultiplier = Math.max(0.2, Math.min(3.0, window.zoomMultiplier + amount));
    window.updateZoom();
    savePreference('zoomMultiplier', window.zoomMultiplier);
};
window.recursiveZoomUpdate = () => {
    window.updateZoom();
    requestAnimationFrame(window.recursiveZoomUpdate);
};
window.recursiveZoomUpdate();

/* Mouse Position */
window.mousePos = { x: 0, y: 0 };
document.addEventListener('mousemove', (e) => { window.mousePos = { x: e.clientX, y: e.clientY }; });
window.botTargetPos = null;

/* Loading Screen */
(function setupLoadingScreen() {
    const style = document.createElement('style');
    style.textContent = `
        @keyframes glitch { 0% { transform: translate(0); } 20% { transform: translate(-2px, 2px); } 40% { transform: translate(-2px, -2px); } 60% { transform: translate(2px, 2px); } 80% { transform: translate(2px, -2px); } 100% { transform: translate(0); } }
        @keyframes matrix { 0% { opacity: 0; transform: translateY(20px); } 50% { opacity: 1; } 100% { opacity: 0; transform: translateY(-20px); } }
        #bot-loading-screen { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: #000; z-index: 10001; display: flex; flex-direction: column; align-items: center; justify-content: center; font-family: 'Courier New', monospace; color: #00ff88; overflow: hidden; }
        #bot-loading-canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
        #bot-loading-content { z-index: 1; text-align: center; }
        #bot-loading-text { font-size: 24px; margin-bottom: 20px; animation: glitch 0.5s infinite alternate; }
        #bot-loading-bar { width: 300px; height: 20px; background: #222; border: 2px solid #00ff88; border-radius: 5px; overflow: hidden; }
        #bot-loading-fill { height: 100%; background: linear-gradient(90deg, #00ff88, #00cc66); width: 0%; transition: width 0.5s ease; }
    `;
    document.head.appendChild(style);

    const loadingScreen = document.createElement('div');
    loadingScreen.id = 'bot-loading-screen';
    document.body.appendChild(loadingScreen);

    const canvas = document.createElement('canvas');
    canvas.id = 'bot-loading-canvas';
    loadingScreen.appendChild(canvas);
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    window.addEventListener('resize', () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; });

    const content = document.createElement('div');
    content.id = 'bot-loading-content';
    loadingScreen.appendChild(content);

    const loadingText = document.createElement('div');
    loadingText.id = 'bot-loading-text';
    loadingText.textContent = 'Initializing Slither Client...';
    content.appendChild(loadingText);

    const loadingBar = document.createElement('div');
    loadingBar.id = 'bot-loading-bar';
    const loadingFill = document.createElement('div');
    loadingFill.id = 'bot-loading-fill';
    loadingBar.appendChild(loadingFill);
    content.appendChild(loadingBar);

    const ctx = canvas.getContext('2d');
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*';
    const fontSize = 14;
    const columns = Math.floor(canvas.width / fontSize);
    const drops = Array(columns).fill(0);

    function drawMatrix() {
        ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = '#00ff88';
        ctx.font = `${fontSize}px 'Courier New'`;
        drops.forEach((y, i) => {
            const text = chars.charAt(Math.floor(Math.random() * chars.length));
            ctx.fillText(text, i * fontSize, y * fontSize);
            if (y * fontSize > canvas.height && Math.random() > 0.975) drops[i] = 0;
            drops[i]++;
        });
    }

    const particles = Array(100).fill().map(() => ({
        x: Math.random() * canvas.width,
        y: Math.random() * canvas.height,
        vx: (Math.random() - 0.5) * 2,
        vy: (Math.random() - 0.5) * 2,
        size: Math.random() * 3 + 1
    }));

    function drawParticles() {
        ctx.fillStyle = 'rgba(0, 255, 136, 0.5)';
        particles.forEach(p => {
            ctx.beginPath();
            ctx.arc(p.x, p.y, p.size, 0, 2 * Math.PI);
            ctx.fill();
            p.x += p.vx;
            p.y += p.vy;
            if (p.x < 0 || p.x > canvas.width) p.vx *= -1;
            if (p.y < 0 || p.y > canvas.height) p.vy *= -1;
        });
    }

    function animateLoading() {
        drawMatrix();
        drawParticles();
        requestAnimationFrame(animateLoading);
    }
    animateLoading();

    const components = [
        { name: 'Core Systems', duration: 600 },
        { name: 'Bot AI', duration: 500 },
        { name: 'Visuals', duration: 400 },
        { name: 'UI', duration: 500 }
    ];

    let index = 0, progress = 0;
    function loadNextComponent() {
        if (index >= components.length) {
            loadingScreen.style.display = 'none';
            initializeUI();
            return;
        }
        loadingText.textContent = `[${index + 1}/${components.length}] Loading ${components[index].name}...`;
        progress += 100 / components.length;
        loadingFill.style.width = `${progress}%`;
        setTimeout(loadNextComponent, components[index].duration);
        index++;
    }
    loadNextComponent();
})();

/* Mod Menu UI */
function initializeUI() {
    const style = document.createElement('style');
    style.textContent = `
        #bot-overlay-container { position: fixed; top: 50px; left: 50px; background: linear-gradient(135deg, #1a1a1a, #2d2d2d); border-radius: 12px; z-index: 10000; font-family: 'Roboto', Arial, sans-serif; color: #e0e0e0; box-shadow: 0 8px 30px rgba(0, 0, 0, 0.7); width: 320px; height: 450px; resize: both; min-width: 280px; min-height: 350px; max-width: 600px; max-height: 700px; overflow: hidden; }
        #bot-overlay-container.minimized { width: 60px; height: 40px; overflow: hidden; }
        #bot-header { background: #111; padding: 10px; font-size: 16px; font-weight: bold; text-align: center; cursor: move; border-bottom: 1px solid #444; display: flex; justify-content: space-between; align-items: center; }
        #bot-sidebar { width: 50px; background: #222; height: 100%; float: left; border-right: 1px solid #444; }
        #bot-sidebar.collapsed { width: 0; overflow: hidden; }
        #bot-content-container { width: calc(100% - 50px); height: 100%; float: left; padding: 10px; overflow-y: auto; background: #1a1a1a; }
        #bot-content-container::-webkit-scrollbar { width: 6px; }
        #bot-content-container::-webkit-scrollbar-track { background: #333; }
        #bot-content-container::-webkit-scrollbar-thumb { background: #00ff88; border-radius: 3px; }
        .tab-button { width: 100%; padding: 10px; background: #222; color: #e0e0e0; border: none; text-align: center; font-size: 13px; cursor: pointer; transition: all 0.3s ease; display: flex; align-items: center; justify-content: center; }
        .tab-button:hover { background: #2a2a2a; }
        .tab-button.active { background: #333; color: #00ff88; }
        .mod-container { display: flex; align-items: center; margin: 5px 0; }
        .mod-button { flex: 1; padding: 6px; background: #ff4d4d; color: #000; border: none; border-radius: 4px; cursor: pointer; transition: all 0.2s ease; font-size: 13px; }
        .mod-button.on { background: #00ff88; }
        .mod-button:hover { filter: brightness(1.2); }
        .favorite-button { padding: 6px; background: #444; color: #e0e0e0; border: none; border-radius: 4px; margin-left: 5px; cursor: pointer; transition: all 0.2s ease; }
        .favorite-button.on { background: #ffd700; color: #000; }
        #bot-search-bar { width: 100%; padding: 6px; margin-bottom: 8px; background: #333; border: 1px solid #444; color: #e0e0e0; border-radius: 4px; font-size: 13px; }
        #bot-danger-bar { position: fixed; top: 50%; right: 10px; width: 15px; height: 150px; background: #333; border-radius: 8px; z-index: 9999; overflow: hidden; transform: translateY(-50%); box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5); }
        #bot-danger-fill { width: 100%; height: 0%; background: green; transition: height 0.3s ease, background 0.3s ease; }
        #bot-speed-cooldown { position: fixed; bottom: 20px; left: 20px; width: 100px; height: 10px; background: #333; border-radius: 5px; z-index: 9999; overflow: hidden; }
        #bot-speed-cooldown-fill { height: 100%; background: #00ff88; width: 0%; transition: width 0.3s ease; }
        #bot-color-picker { margin: 10px 0; }
    `;
    document.head.appendChild(style);

    const tailwindLink = document.createElement('link');
    tailwindLink.href = 'https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css';
    tailwindLink.rel = 'stylesheet';
    document.head.appendChild(tailwindLink);

    const fontLink = document.createElement('link');
    fontLink.href = 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap';
    fontLink.rel = 'stylesheet';
    document.head.appendChild(fontLink);

    const overlayContainer = document.createElement('div');
    overlayContainer.id = 'bot-overlay-container';
    document.body.appendChild(overlayContainer);

    let isDragging = false, xOffset = loadPreference('menuX', 50), yOffset = loadPreference('menuY', 50);
    overlayContainer.style.left = `${xOffset}px`;
    overlayContainer.style.top = `${yOffset}px`;

    const header = document.createElement('div');
    header.id = 'bot-header';
    header.innerHTML = `<span>Slither Client</span><span id="active-tab" class="text-sm text-gray-400">Favorites</span><button id="minimize-btn" class="text-gray-400 hover:text-gray-100">${isMinimized ? '+' : '-'}</button>`;
    overlayContainer.appendChild(header);

    header.addEventListener('mousedown', (e) => {
        isDragging = true;
        xOffset = e.clientX - parseFloat(overlayContainer.style.left);
        yOffset = e.clientY - parseFloat(overlayContainer.style.top);
    });

    document.addEventListener('mousemove', (e) => {
        if (isDragging) {
            e.preventDefault();
            overlayContainer.style.left = `${e.clientX - xOffset}px`;
            overlayContainer.style.top = `${e.clientY - yOffset}px`;
            savePreference('menuX', e.clientX - xOffset);
            savePreference('menuY', e.clientY - yOffset);
        }
    });

    document.addEventListener('mouseup', () => { isDragging = false; });

    const sidebar = document.createElement('div');
    sidebar.id = 'bot-sidebar';
    overlayContainer.appendChild(sidebar);

    const contentContainer = document.createElement('div');
    contentContainer.id = 'bot-content-container';
    overlayContainer.appendChild(contentContainer);

    const tabs = [
        { id: 'favorites-tab', name: 'Favorites', icon: icons.Favorites },
        { id: 'bot-tab', name: 'Bot', icon: icons.Bot },
        { id: 'visuals-tab', name: 'Visuals', icon: icons.Visuals }
    ];

    tabs.forEach(tab => {
        const tabButton = document.createElement('button');
        tabButton.innerHTML = `${tab.icon} ${tab.name}`;
        tabButton.className = `tab-button ${tab.id === activeTab ? 'active' : ''}`;
        tabButton.onclick = () => {
            activeTab = tab.id;
            document.getElementById('active-tab').textContent = tab.name;
            tabs.forEach(t => {
                document.getElementById(t.id).style.display = t.id === tab.id ? 'block' : 'none';
                sidebar.querySelectorAll('.tab-button').forEach(btn => {
                    btn.className = `tab-button ${btn.innerText.includes(t.name) && t.id === tab.id ? 'active' : ''}`;
                });
            });
            refreshTabs();
        };
        sidebar.appendChild(tabButton);

        const tabContent = document.createElement('div');
        tabContent.id = tab.id;
        tabContent.style.display = tab.id === activeTab ? 'block' : 'none';
        contentContainer.appendChild(tabContent);
    });

    const searchBar = document.createElement('input');
    searchBar.id = 'bot-search-bar';
    searchBar.type = 'text';
    searchBar.placeholder = 'Search mods...';
    contentContainer.appendChild(searchBar);

    searchBar.oninput = () => {
        const query = searchBar.value.toLowerCase();
        mods.forEach(mod => {
            const modElement = document.getElementById(`mod-${mod.id}`);
            if (modElement) modElement.style.display = mod.name.toLowerCase().includes(query) ? 'flex' : 'none';
        });
    };

    if (customColors) {
        const colorPicker = document.createElement('div');
        colorPicker.id = 'bot-color-picker';
        colorPicker.innerHTML = `
            <label class="block text-sm mb-1">Line Color: <input type="color" id="line-color" value="${customLineColor}"></label>
            <label class="block text-sm mb-1">Minimap Color: <input type="color" id="minimap-color" value="${customMinimapColor}"></label>
        `;
        contentContainer.appendChild(colorPicker);

        document.getElementById('line-color').addEventListener('input', (e) => {
            customLineColor = e.target.value;
            savePreference('customLineColor', customLineColor);
        });
        document.getElementById('minimap-color').addEventListener('input', (e) => {
            customMinimapColor = e.target.value;
            savePreference('customMinimapColor', customMinimapColor);
        });
    }

    const minimizeBtn = header.querySelector('#minimize-btn');
    minimizeBtn.onclick = () => {
        isMinimized = !isMinimized;
        overlayContainer.className = isMinimized ? 'minimized' : '';
        minimizeBtn.textContent = isMinimized ? '+' : '-';
        contentContainer.style.display = isMinimized ? 'none' : 'block';
        sidebar.className = `bg-gray-800 ${isMinimized ? 'collapsed' : ''}`;
    };

    function refreshTabs() {
        const favoritesTab = document.getElementById('favorites-tab');
        const botTab = document.getElementById('bot-tab');
        const visualsTab = document.getElementById('visuals-tab');

        favoritesTab.innerHTML = botTab.innerHTML = visualsTab.innerHTML = '';

        const filteredMods = favoriteMods.length > 0 ? mods.filter(mod => favoriteMods.includes(mod.id)) : [];
        if (filteredMods.length === 0 && activeTab === 'favorites-tab') {
            favoritesTab.innerHTML = '<div class="text-gray-500 text-center p-5">No favorite mods yet.</div>';
        } else {
            filteredMods.forEach(mod => favoritesTab.appendChild(createModToggle(mod)));
        }

        mods.filter(m => m.category === 'Bot').forEach(mod => botTab.appendChild(createModToggle(mod)));
        mods.filter(m => m.category === 'Visuals').forEach(mod => visualsTab.appendChild(createModToggle(mod)));
    }

    function createModToggle(mod) {
        const container = document.createElement('div');
        container.id = `mod-${mod.id}`;
        container.className = 'mod-container';

        const button = document.createElement('button');
        button.textContent = `${mod.name}: ${mod.state() ? 'ON' : 'OFF'}`;
        button.className = `mod-button ${mod.state() ? 'on' : ''}`;
        button.onclick = () => {
            const newState = !mod.state();
            mod.toggle(newState);
            button.textContent = `${mod.name}: ${newState ? 'ON' : 'OFF'}`;
            button.className = `mod-button ${newState ? 'on' : ''}`;
            document.querySelectorAll(`#mod-${mod.id} .mod-button`).forEach(btn => {
                btn.textContent = `${mod.name}: ${newState ? 'ON' : 'OFF'}`;
                btn.className = `mod-button ${newState ? 'on' : ''}`;
            });
        };

        const favoriteButton = document.createElement('button');
        favoriteButton.innerHTML = favoriteMods.includes(mod.id) ? icons.FavoriteOn : icons.FavoriteOff;
        favoriteButton.className = `favorite-button ${favoriteMods.includes(mod.id) ? 'on' : ''}`;
        favoriteButton.onclick = () => {
            favoriteMods = favoriteMods.includes(mod.id) ? favoriteMods.filter(id => id !== mod.id) : [...favoriteMods, mod.id];
            savePreference('favoriteMods', favoriteMods);
            favoriteButton.innerHTML = favoriteMods.includes(mod.id) ? icons.FavoriteOn : icons.FavoriteOff;
            favoriteButton.className = `favorite-button ${favoriteMods.includes(mod.id) ? 'on' : ''}`;
            refreshTabs();
        };

        container.appendChild(button);
        container.appendChild(favoriteButton);
        return container;
    }

    const dangerBar = document.createElement('div');
    dangerBar.id = 'bot-danger-bar';
    dangerBar.innerHTML = '<div id="bot-danger-fill"></div>';
    document.body.appendChild(dangerBar);

    const speedCooldown = document.createElement('div');
    speedCooldown.id = 'bot-speed-cooldown';
    speedCooldown.innerHTML = '<div id="bot-speed-cooldown-fill"></div>';
    document.body.appendChild(speedCooldown);

    document.addEventListener('keydown', (e) => {
        if (e.key === ';') {
            menuVisible = !menuVisible;
            overlayContainer.style.display = menuVisible && !isMinimized ? 'block' : 'none';
        }
    });

    refreshTabs();
}

/* Minimap and Visuals */
(function setupMinimap() {
    const minimap = document.createElement('canvas');
    minimap.id = 'bot-minimap';
    minimap.width = 200;
    minimap.height = 200;
    minimap.style.cssText = `position: fixed; bottom: 10px; right: 40px; z-index: 9999; border: 2px solid ${customColors ? customMinimapColor : '#00ff88'}; border-radius: 8px; background: rgba(0, 0, 0, 0.6); box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5);`;
    document.body.appendChild(minimap);

    function updateMinimap() {
        const ctx = minimap.getContext('2d');
        ctx.clearRect(0, 0, minimap.width, minimap.height);
        ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
        ctx.fillRect(0, 0, minimap.width, minimap.height);

        if (window.slither?.xx !== undefined) {
            const scale = 0.015, centerX = minimap.width / 2, centerY = minimap.height / 2;

            ctx.fillStyle = customColors ? customMinimapColor : 'green';
            ctx.beginPath();
            ctx.arc(centerX, centerY, 6, 0, 2 * Math.PI);
            ctx.fill();
            if (showPlayerGlow) {
                ctx.shadowBlur = 15;
                ctx.shadowColor = customColors ? customMinimapColor : 'green';
                ctx.fill();
                ctx.shadowBlur = 0;
            }

            if (Array.isArray(window.slithers)) {
                window.slithers.forEach(e => {
                    if (!e || e.xx === window.slither.xx || typeof e.xx !== 'number') return;
                    const dx = (e.xx - window.slither.xx) * scale;
                    const dy = (e.yy - window.slither.yy) * scale;
                    if (Math.abs(dx) < centerX && Math.abs(dy) < centerY) {
                        ctx.fillStyle = 'red';
                        ctx.beginPath();
                        ctx.arc(centerX + dx, centerY + dy, 4, 0, 2 * Math.PI);
                        ctx.fill();
                    }
                });
            }

            if (Array.isArray(window.foods)) {
                window.foods.forEach(f => {
                    if (!f || typeof f.xx !== 'number') return;
                    const dx = (f.xx - window.slither.xx) * scale;
                    const dy = (f.yy - window.slither.yy) * scale;
                    if (Math.abs(dx) < centerX && Math.abs(dy) < centerY) {
                        ctx.fillStyle = 'cyan';
                        ctx.beginPath();
                        ctx.arc(centerX + dx, centerY + dy, 3, 0, 2 * Math.PI);
                        ctx.fill();
                    }
                });
            }

            if (showScoreTracker && window.slither?.l) {
                ctx.fillStyle = '#fff';
                ctx.font = '12px Roboto';
                ctx.fillText(`Score: ${Math.floor(window.slither.l)}`, 10, 20);
                ctx.fillText(`Rank: ${window.rank || 'N/A'}`, 10, 35);
            }
        }
        requestAnimationFrame(updateMinimap);
    }
    updateMinimap();
})();

/* World to Screen Conversion */
const worldToScreen = (xx, yy) => ({
    x: (xx - window.view_xx) * window.gsc + window.mww2,
    y: (yy - window.view_yy) * window.gsc + window.mhh2
});

/* Enemy Processing */
function getEnemyBodyPoints(enemy) {
    const points = [];
    if (enemy?.pts) {
        for (const segment of enemy.pts) {
            if (segment.fxs && segment.fys) {
                for (let i = 0; i < segment.fxs.length; i += Math.max(1, Math.floor(segment.fxs.length / 5))) {
                    const x = segment.xx + segment.fxs[i];
                    const y = segment.yy + segment.fys[i];
                    if (isFinite(x) && isFinite(y)) points.push({ xx: x, yy: y });
                }
            }
        }
    }
    return points;
}

function DangerColor(start, end) {
    const dist = Math.hypot(end.x - start.x, end.y - start.y);
    const dangerRatio = Math.max(0, Math.min(1, (700 - dist) / (700 - 300)));
    const r = Math.floor(255 * dangerRatio), g = Math.floor(255 * (1 - dangerRatio));
    return customColors ? customLineColor : `rgba(${r},${g},0,0.8)`;
}

/* Enemy Lines */
(function updateEnemyLines() {
    let canvas, ctx;
    function initCanvas() {
        canvas = document.createElement('canvas');
        canvas.id = 'bot-line-overlay';
        canvas.style.cssText = `position: fixed; top: 0; left: 0; pointer-events: none; z-index: 9998;`;
        document.body.appendChild(canvas);
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        window.addEventListener('resize', () => {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        });
        ctx = canvas.getContext('2d');
    }

    function update() {
        if (!canvas) initCanvas();
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        if (showEnemyLines && window.slither?.xx !== undefined && Array.isArray(window.slithers)) {
            const selfScreen = worldToScreen(window.slither.xx, window.slither.yy);
            const enemies = window.slithers.filter(e => e && typeof e.xx === 'number' && e.xx !== window.slither.xx).slice(0, 5);
            enemies.forEach(enemy => {
                const bodyPoints = getEnemyBodyPoints(enemy);
                let minDist = Infinity, minPoint = null;
                bodyPoints.forEach(p => {
                    const screenPoint = worldToScreen(p.xx, p.yy);
                    const dist = Math.hypot(screenPoint.x - selfScreen.x, screenPoint.y - selfScreen.y);
                    if (dist < minDist && dist > 0) {
                        minDist = dist;
                        minPoint = screenPoint;
                    }
                });
                if (minPoint) {
                    ctx.beginPath();
                    ctx.moveTo(selfScreen.x, selfScreen.y);
                    ctx.lineTo(minPoint.x, minPoint.y);
                    ctx.strokeStyle = DangerColor(selfScreen, minPoint);
                    ctx.lineWidth = 3;
                    ctx.stroke();
                }
            });
        }
        requestAnimationFrame(update);
    }
    update();
})();

/* Speed Cooldown Indicator */
(function updateSpeedCooldown() {
    function update() {
        if (showSpeedCooldown) {
            const cooldownProgress = Math.min((Date.now() - lastSpeedBoost) / speedBoostCooldown, 1);
            const fill = document.getElementById('bot-speed-cooldown-fill');
            if (fill) fill.style.width = `${cooldownProgress * 100}%`;
        }
        requestAnimationFrame(update);
    }
    update();
})();

/* A* Pathfinding */
function aStarPathfinding(start, goal, obstacles) {
    const gridSize = 50, gridWidth = Math.ceil(10000 / gridSize), gridHeight = Math.ceil(10000 / gridSize);
    const openSet = new Set([`${Math.floor(start.x / gridSize)},${Math.floor(start.y / gridSize)}`]);
    const closedSet = new Set();
    const cameFrom = new Map();
    const gScore = new Map([[openSet.values().next().value, 0]]);
    const fScore = new Map([[openSet.values().next().value, Math.hypot(goal.x - start.x, goal.y - start.y)]]);

    function getNeighbors(node) {
        const [x, y] = node.split(',').map(Number);
        const directions = [[1,0],[-1,0],[0,1],[0,-1],[1,1],[1,-1],[-1,1],[-1,-1]];
        return directions.map(([dx, dy]) => ({ x: x + dx, y: y + dy }))
            .filter(n => n.x >= 0 && n.x < gridWidth && n.y >= 0 && n.y < gridHeight);
    }

    function isObstacle(node) {
        const nodeX = node.x * gridSize + gridSize / 2, nodeY = node.y * gridSize + gridSize / 2;
        return obstacles.some(o => Math.hypot(o.point.xx - nodeX, o.point.yy - nodeY) < 200);
    }

    while (openSet.size) {
        let current = [...openSet].reduce((a, b) => (fScore.get(a) || Infinity) < (fScore.get(b) || Infinity) ? a : b);
        const [cx, cy] = current.split(',').map(Number);
        const currentNode = { x: cx, y: cy };

        if (cx === Math.floor(goal.x / gridSize) && cy === Math.floor(goal.y / gridSize)) {
            const path = [];
            let curr = current;
            while (curr) {
                const [x, y] = curr.split(',').map(Number);
                path.unshift({ x: x * gridSize + gridSize / 2, y: y * gridSize + gridSize / 2 });
                curr = cameFrom.get(curr);
            }
            return path;
        }

        openSet.delete(current);
        closedSet.add(current);

        for (const neighbor of getNeighbors(current)) {
            const neighborStr = `${neighbor.x},${neighbor.y}`;
            if (closedSet.has(neighborStr) || isObstacle(neighbor)) continue;

            const tentativeG = (gScore.get(current) || 0) + Math.hypot((neighbor.x - cx) * gridSize, (neighbor.y - cy) * gridSize);
            if (!openSet.has(neighborStr)) openSet.add(neighborStr);
            else if (tentativeG >= (gScore.get(neighborStr) || Infinity)) continue;

            cameFrom.set(neighborStr, current);
            gScore.set(neighborStr, tentativeG);
            fScore.set(neighborStr, tentativeG + Math.hypot((neighbor.x - goal.x / gridSize) * gridSize, (neighbor.y - goal.y / gridSize) * gridSize));
        }
    }
    return [];
}

/* Bot Logic */
function moveMouseToward(worldX, worldY) {
    if (!window.slither?.xx) return;
    window.botTargetPos = { x: worldX, y: worldY };
    const screenX = (worldX - window.view_xx) * window.gsc + window.mww2;
    const screenY = (worldY - window.view_yy) * window.gsc + window.mhh2;
    if (Math.hypot(screenX - window.mousePos.x, screenY - window.mousePos.y) > 10) {
        window.dispatchEvent(new MouseEvent('mousemove', { clientX: screenX, clientY: screenY, bubbles: true }));
    }
}

let foodBotInterval = null;
function startFoodBot() {
    if (!foodBotInterval) foodBotInterval = setInterval(foodBotUpdate, loadPreference('botSpeed', 20));
}
function stopFoodBot() {
    if (foodBotInterval) {
        clearInterval(foodBotInterval);
        foodBotInterval = null;
    }
}

function foodBotUpdate() {
    if (!window.slither?.xx || !Array.isArray(window.foods)) return;
    const self = window.slither, now = Date.now();
    let dangerLevel = 0, enemyList = [];
    criticDanger = false;

    if (Array.isArray(window.slithers)) {
        window.slithers.forEach(enemy => {
            if (!enemy || enemy.xx === self.xx || typeof enemy.xx !== 'number') return;
            const bodyPoints = getEnemyBodyPoints(enemy);
            if (!bodyPoints.length) return;
            let bestPoint = null, bestDistance = Infinity, bestDx = 0, bestDy = 0;
            bodyPoints.forEach(p => {
                const dx = p.xx - self.xx, dy = p.yy - self.yy, d = Math.hypot(dx, dy);
                if (d < bestDistance) {
                    bestDistance = d;
                    bestPoint = p;
                    bestDx = dx;
                    bestDy = dy;
                }
            });
            if (bestPoint) {
                dangerLevel = Math.max(dangerLevel, bestDistance < 300 ? 1 - bestDistance / 300 : bestDistance < 700 ? 0.5 * (1 - (bestDistance - 300) / 400) : 0);
                if (bestDistance < 300) criticDanger = true;
                enemyList.push({ point: bestPoint, distance: bestDistance, dx: bestDx, dy: bestDy, size: enemy.l || 100, futurePoint: {
                    xx: bestPoint.xx + (enemy.spd || 0) * Math.cos(enemy.ang || 0) * 100,
                    yy: bestPoint.yy + (enemy.spd || 0) * Math.sin(enemy.ang || 0) * 100
                } });
            }
        });
    }

    if (showDangerBar) {
        const fill = document.getElementById('bot-danger-fill');
        if (fill) {
            fill.style.height = `${Math.min(dangerLevel * 100, 100)}%`;
            fill.style.background = `rgb(${Math.floor(255 * dangerLevel)},${Math.floor(255 * (1 - dangerLevel))},0)`;
        }
    }

    if (speedModulation && !isSpeedBoost && targetFood?.sz > 50 && dangerLevel < 0.5 && Date.now() - lastSpeedBoost > speedBoostCooldown) {
        window.setAcceleration?.(1);
        isSpeedBoost = true;
        lastSpeedBoost = Date.now();
        document.querySelectorAll('#mod-speedBoost .mod-button').forEach(btn => {
            btn.textContent = `Speed Boost: ON`;
            btn.className = 'mod-button on';
        });
    } else if (speedModulation && isSpeedBoost && (!targetFood || targetFood.sz <= 50 || dangerLevel >= 0.5)) {
        window.setAcceleration?.(0);
        isSpeedBoost = false;
        document.querySelectorAll('#mod-speedBoost .mod-button').forEach(btn => {
            btn.textContent = `Speed Boost: OFF`;
            btn.className = 'mod-button';
        });
    }

    if (autoZoom) {
        const baseZoom = 1.0, sizeFactor = window.slither?.l ? Math.min(0.5, 500 / window.slither.l) : 0;
        window.zoomMultiplier = Math.max(0.2, Math.min(3.0, baseZoom - sizeFactor + dangerLevel * 0.5));
        window.updateZoom();
        savePreference('zoomMultiplier', window.zoomMultiplier);
    }

    const foods = window.foods.filter(f => f && typeof f.xx === 'number' && !(blacklistedFoods[`${f.xx}_${f.yy}`] && now < blacklistedFoods[`${f.xx}_${f.yy}`]));
    let target = null;

    if (!enemyList.length) {
        target = chooseBestFood(foods);
    } else if (enemyList.some(e => e.distance < 300)) {
        if (autoDodge) {
            let avgX = 0, avgY = 0, totalWeight = 0;
            enemyList.filter(e => e.distance < 300).forEach(e => {
                const weight = 1 / (e.distance + 1e-5);
                avgX += (e.dx / e.distance) * weight;
                avgY += (e.dy / e.distance) * weight;
                totalWeight += weight;
            });
            if (totalWeight > 0) {
                avgX /= totalWeight;
                avgY /= totalWeight;
                const bestDir = { x: -avgX * 200, y: -avgY * 200 };
                if (criticDanger && Math.random() < 0.5) {
                    const angle = Date.now() / 1000 * Math.PI;
                    bestDir.x += Math.cos(angle) * 50;
                    bestDir.y += Math.sin(angle) * 50;
                }
                moveMouseToward(self.xx + bestDir.x, self.yy + bestDir.y);
                targetFood = null;
                return;
            }
        }
    } else if (!aggressiveMode) {
        const closest = enemyList.reduce((a, b) => a.distance < b.distance ? a : b);
        const vecX = self.xx - closest.futurePoint.xx, vecY = self.yy - closest.futurePoint.yy;
        const vecLength = Math.hypot(vecX, vecY);
        const normX = vecLength ? vecX / vecLength : 0, normY = vecLength ? vecY / vecLength : 0;
        const filteredFoods = foods.filter(f => (f.xx - self.xx) * normX + (f.yy - self.yy) * normY > 0);
        target = filteredFoods.length ? chooseBestFood(filteredFoods) : chooseBestFood(foods);
    } else if (enemyTrap && aggressiveMode) {
        const smallEnemies = enemyList.filter(e => e.size < (window.slither.l || 100) && e.distance < 500);
        if (smallEnemies.length) {
            const trapTarget = chooseBestFood(foods.filter(f => {
                return smallEnemies.some(e => Math.hypot(f.xx - e.point.xx, f.yy - e.point.yy) < 200);
            }));
            if (trapTarget) {
                const angle = Date.now() / 1000 * Math.PI;
                const orbitRadius = 100;
                target = {
                    xx: trapTarget.xx + Math.cos(angle) * orbitRadius,
                    yy: trapTarget.yy + Math.sin(angle) * orbitRadius,
                    sz: trapTarget.sz
                };
            } else {
                target = chooseBestFood(foods);
            }
        } else {
            target = chooseBestFood(foods);
        }
    } else {
        target = chooseBestFood(foods);
    }

    if (target && targetFood?.xx === target.xx && target.yy === targetFood.yy && now - targetFoodTimestamp >= 2000) {
        blacklistedFoods[`${targetFood.xx}_${targetFood.yy}`] = now + 2000;
        target = chooseBestFood(foods.filter(f => f.xx !== targetFood.xx || f.yy !== targetFood.yy));
        targetFoodTimestamp = now;
    } else if (target) {
        targetFoodTimestamp = now;
    }

    if (target) {
        const path = aStarPathfinding({ x: self.xx, y: self.yy }, { x: target.xx, y: target.yy }, enemyList);
        moveMouseToward(path[1]?.x || target.xx, path[1]?.y || target.yy);
        targetFood = target;
    }
}

function chooseBestFood(foods) {
    const maxDistance = aggressiveMode ? 1000 : 500;
    let bestTarget = null, bestScore = -Infinity;
    foods.forEach(f => {
        if (!f || typeof f.xx !== 'number') return;
        const dist = Math.hypot(f.xx - window.slither.xx, f.yy - window.slither.yy);
        if (dist > maxDistance) return;
        let dangerScore = 0;
        window.slithers?.forEach(e => {
            if (!e || e.xx === window.slither.xx) return;
            const dx = f.xx - e.xx, dy = f.yy - e.yy, d = Math.hypot(dx, dy);
            if (d < 300) dangerScore -= aggressiveMode ? 500 / (d + 1e-5) : 1000 / (d + 1e-5);
        });
        const score = (f.sz || 1) * (aggressiveMode ? 2 : 1) + dangerScore - dist / (defensiveMode ? 5 : 10);
        if (score > bestScore) {
            bestScore = score;
            bestTarget = f;
        }
    });
    return bestTarget;
}

/* Auto Respawn */
(function checkRespawn() {
    if (autoRespawn && window.dead_mtm && !window.playing) window.play_btn_click?.();
    requestAnimationFrame(checkRespawn);
})();

/* Key Bindings */
document.addEventListener('keydown', (e) => {
    switch (e.key.toLowerCase()) {
        case 't': window.adjustZoom(0.1); break;
        case 'r': window.adjustZoom(-0.1); break;
        case 'y': if (Date.now() - lastSpeedBoost > speedBoostCooldown) toggleSpeedBoost(); break;
    }
});

function toggleSpeedBoost() {
    isSpeedBoost = !isSpeedBoost;
    window.setAcceleration?.(isSpeedBoost ? 1 : 0);
    if (isSpeedBoost) lastSpeedBoost = Date.now();
    savePreference('isSpeedBoost', isSpeedBoost);
    document.querySelectorAll('#mod-speedBoost .mod-button').forEach(btn => {
        btn.textContent = `Speed Boost: ${isSpeedBoost ? 'ON' : 'OFF'}`;
        btn.className = `mod-button ${isSpeedBoost ? 'on' : ''}`;
    });
}

if (IsBotActive) startFoodBot();

document.addEventListener('DOMContentLoaded', () => setTimeout(initializeUI, 100));

QingJ © 2025

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