Emulation's Slither Client

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

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==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));