Greasy Fork

Greasy Fork is available in English.

Slither Full Auto Bot 2025 (Zoom Dezoom enabled)

Detects and avoid enemies, Zoom Dezoom, Automatically collects food strategically and use strategic pathfinding. Enhanced and responsive overlay.

// ==UserScript==
// @name         Slither Full Auto Bot 2025 (Zoom Dezoom enabled)
// @namespace    http://slither.com/io
// @version      1.6
// @description  Detects and avoid enemies, Zoom Dezoom, Automatically collects food strategically and use strategic pathfinding. Enhanced and responsive overlay.
// @author       EliottValette
// @match        http://slither.com/io
// @grant        none
// @license      MIT
// ==/UserScript==

/*
===================================================
Section 1: Utility Functions and Debugging
===================================================
*/

// Custom log function (only displays if "logDebugging" is enabled)
window.log = (...args) => window.logDebugging && console.log(...args);

// Functions to save and load preferences in localStorage
const savePreference = (key, value) => localStorage.setItem(key, value);
const loadPreference = (key, def) => JSON.parse(localStorage.getItem(key)) ?? def;

let Logger = 0;
let IsBotActive = true;
let targetFood = null;
let targetFoodTimestamp = 0;
let blacklistedFoods = {};
let criticDanger = false;

// Ajout des variables et fonctions pour le zoom
window.zoomMultiplier = 1.0;

window.updateZoom = function() {
    window.gsc = window.zoomMultiplier;
    const zoomElement = document.getElementById("bot_zoom_overlay");
    if (zoomElement) {
        zoomElement.textContent = `Zoom: ${window.zoomMultiplier.toFixed(1)} (a to zoom, e to zoom out, z to reset)`;
    }
};

window.recursiveZoomUpdate = function() {
    window.gsc = window.zoomMultiplier;
    requestAnimationFrame(window.recursiveZoomUpdate);
};

window.resetZoom = function() {
    window.zoomMultiplier = 1.0;
    window.updateZoom();
};

window.adjustZoom = function(amount) {
    window.zoomMultiplier = Math.max(0.2, Math.min(3.0, window.zoomMultiplier + amount));
    window.updateZoom();
};

// Add listener to memorize real mouse position
window.mousePos = { x: 0, y: 0 };
document.addEventListener('mousemove', function(e) {
    window.mousePos = { x: e.clientX, y: e.clientY };
});

// Variable to memorize bot target position (the "bot mouse pose")
window.botTargetPos = null;

console.log('Bot Starting');

/*
===================================================
Section 2: Window Object Debug Scan
===================================================
After 5 seconds, scans the window object to find
potential snake objects (presence of xx and yy)
*/
setTimeout(() => {
    for (let key in window) {
        try {
            let val = window[key];
            if (val && typeof val === 'object') {
                // Checks if the object has coordinates
                if ('xx' in val && 'yy' in val) {
                    console.log(`🟢 Snake? -> window.${key}`, val);
                }
                // Checks if the object is an array of objects with coordinates
                if (Array.isArray(val) && val.length > 0 && val[0] && 'xx' in val[0] && 'yy' in val[0]) {
                    console.log(`🍏 Array of objects with coords? -> window.${key}`, val);
                }
            }
        } catch (e) {
            // In case of error, move to next property
        }
    }
}, 5000);

/*
===================================================
Section 3: Improved Interface Overlay
===================================================
Creation of a unique container that displays bot status,
coordinates and enemy count in real-time.
*/
(function setupOverlayUI() {
    // Creation of main container with semi-transparent background
    const overlayContainer = document.createElement('div');
    overlayContainer.id = 'bot-overlay-container';
    overlayContainer.style.cssText = `
        position: fixed;
        top: 10px;
        left: 10px;
        background: rgba(0, 0, 0, 0.5);
        padding: 10px;
        border-radius: 5px;
        z-index: 9999;
        font-family: Arial, sans-serif;
        color: #FFF;
        font-size: 14px;
    `;
    document.body.appendChild(overlayContainer);

    // Creation of sub-elements for status, coordinates and enemy count
    const statusDiv = document.createElement('div');
    statusDiv.id = 'bot_status_overlay';
    statusDiv.textContent = 'Status: BOT ON (To Toggle - Press t)';
    overlayContainer.appendChild(statusDiv);

    // Ajout de l'élément de zoom dans le conteneur principal
    const zoomDiv = document.createElement('div');
    zoomDiv.id = 'bot_zoom_overlay';
    zoomDiv.textContent = `Zoom: ${window.zoomMultiplier.toFixed(1)} (a to zoom, e to zoom out, z to reset)`;
    overlayContainer.appendChild(zoomDiv);

    const coordsDiv = document.createElement('div');
    coordsDiv.id = 'bot_coords_overlay';
    coordsDiv.textContent = 'Coords: loading...';
    overlayContainer.appendChild(coordsDiv);

    const enemyDiv = document.createElement('div');
    enemyDiv.id = 'bot_enemies_overlay';
    enemyDiv.textContent = 'Enemies: loading...';
    overlayContainer.appendChild(enemyDiv);

    const nearEnemiesDiv = document.createElement('div');
    nearEnemiesDiv.id = 'bot_enemies_near_overlay';
    nearEnemiesDiv.textContent = 'Enemies (Near): loading...';
    overlayContainer.appendChild(nearEnemiesDiv);

    const midEnemiesDiv = document.createElement('div');
    midEnemiesDiv.id = 'bot_enemies_mid_overlay';
    midEnemiesDiv.textContent = 'Enemies (Mid): loading...';
    overlayContainer.appendChild(midEnemiesDiv);

    const farEnemiesDiv = document.createElement('div');
    farEnemiesDiv.id = 'bot_enemies_far_overlay';
    farEnemiesDiv.textContent = 'Enemies (Far): loading...';
    overlayContainer.appendChild(farEnemiesDiv);

    const criticDangerDiv = document.createElement('div');
    criticDangerDiv.id = 'bot_critic_danger_overlay';
    criticDangerDiv.textContent = 'Danger: loading...';
    overlayContainer.appendChild(criticDangerDiv);

    // Continuous overlay update via requestAnimationFrame
    function updateOverlay() {
        if (window.slither && typeof window.slither.xx === 'number') {
            statusDiv.textContent = IsBotActive ? 'Status: BOT ON (To Turn OFF - Press t)' : 'Status: BOT OFF (To Turn ON - Press t)';
            coordsDiv.textContent = `Coords: ${Math.round(window.slither.xx)} / ${Math.round(window.slither.yy)}`;
            criticDangerDiv.textContent = `Danger: ${criticDanger}`;
        }
        if (Array.isArray(window.slithers) && window.slither) {
            const self = window.slither;
            // Building enemy lists based on distance from their body points
            const nearEnemies = [];
            const midEnemies = [];
            const farEnemies = [];
            window.slithers.forEach(e => {
                if (!e || typeof e.xx !== 'number' || typeof e.yy !== 'number' || e.xx === self.xx)
                    return;
                const bodyPoints = getEnemyBodyPoints(e);
                let minDistance = Infinity;
                let closestPoint = null;
                bodyPoints.forEach(p => {
                    const dx = p.xx - self.xx;
                    const dy = p.yy - self.yy;
                    const dist = Math.sqrt(dx * dx + dy * dy);
                    if (dist < minDistance) {
                        minDistance = dist;
                        closestPoint = p;
                    }
                });
                if (closestPoint) {
                    if (minDistance < 300) {
                        nearEnemies.push({ enemy: e, dist: minDistance, point: closestPoint });
                    } else if (minDistance >= 300 && minDistance <= 700) {
                        midEnemies.push({ enemy: e, dist: minDistance, point: closestPoint });
                    } else if (minDistance > 700) {
                        farEnemies.push({ enemy: e, dist: minDistance, point: closestPoint });
                    }
                }
            });
            enemyDiv.textContent = 'Enemies: ' + window.slithers.length;
            nearEnemiesDiv.textContent = 'Enemies (Near): ' + nearEnemies.map(e => e.enemy.id || `(${Math.round(e.point.xx)},${Math.round(e.point.yy)})`).join(', ');
            midEnemiesDiv.textContent = 'Enemies (Mid): ' + midEnemies.map(e => e.enemy.id || `(${Math.round(e.point.xx)},${Math.round(e.point.yy)})`).join(', ');
            farEnemiesDiv.textContent = 'Enemies (Far): ' + farEnemies.map(e => e.enemy.id || `(${Math.round(e.point.xx)},${Math.round(e.point.yy)})`).join(', ');
        }
        requestAnimationFrame(updateOverlay);
    }
    requestAnimationFrame(updateOverlay);
})();

/*
===================================================
Section 4: World to Screen Coordinate Conversion
===================================================
Utility function to convert game coordinates
(in "world") to screen coordinates.
*/
const worldToScreen = (xx, yy) => {
    const mapX = (xx - window.view_xx) * window.gsc + window.mww2;
    const mapY = (yy - window.view_yy) * window.gsc + window.mhh2;
    return { x: mapX, y: mapY };
};

/*
===================================================
Section 5: Enemy Processing
===================================================
Functions to extract enemy body points and
calculate line color based on distance.
*/

// Gets enemy body points by traversing its segments
function getEnemyBodyPoints(enemy) {
    const points = [];
    if (!enemy.pts) return points;

    for (const segment of enemy.pts) {
        if (!segment.fxs || !segment.fys) continue;

        // Sampling: we get about 10% of the segment points
        const step = Math.max(1, Math.floor(segment.fxs.length / 10));
        for (let i = 0; i < segment.fxs.length; i += step) {
            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;
}

// Calculates a color transitioning from red (close) to green (far)
function DangerColor(start, end) {
    const dx = end.x - start.x;
    const dy = end.y - start.y;
    const dist = Math.sqrt(dx * dx + dy * dy);
    const maxDist = 3000; // Maximum distance to fully transition to green
    const dangerRatio = Math.max(0, Math.min(1, 1 - dist / maxDist));
    const r = Math.floor(255 * dangerRatio);
    const g = Math.floor(255 * (1 - dangerRatio));
    return `rgb(${r},${g},0)`;
}

/*
===================================================
Section 6: Drawing Lines to Enemies and Food
===================================================
Two functions to draw lines between the player and:
- Enemies (by choosing the closest point of each enemy)
- Food (with a custom color)
*/
// Draws lines connecting the player to enemies
function drawAllEnemyLines(start, enemyList) {
    let canvas = document.getElementById('bot-line-overlay');
    if (!canvas) {
        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);

        // Resize canvas when window is resized
        window.addEventListener('resize', () => {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        });
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
    }

    const ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // Si le bot est OFF, on trie les ennemis par distance et on garde les 5 plus proches
    let enemiesToDraw = enemyList;
    if (!IsBotActive) {
        enemiesToDraw = enemyList
            .map(enemy => {
                const body_points = getEnemyBodyPoints(enemy);
                let min_dist = Infinity;
                body_points.forEach(p => {
                    const dx = p.xx - window.slither.xx;
                    const dy = p.yy - window.slither.yy;
                    const d = dx * dx + dy * dy;
                    if (d < min_dist) min_dist = d;
                });
                return { enemy, min_dist };
            })
            .sort((a, b) => a.min_dist - b.min_dist)
            .slice(0, 5)
            .map(obj => obj.enemy);
    }

    enemiesToDraw.forEach(enemy => {
        const body_points = getEnemyBodyPoints(enemy);
        let min_dist = Infinity;
        let min_dist_point = null;
        body_points.forEach(p => {
            const screenPoint = worldToScreen(p.xx, p.yy);
            const dx = screenPoint.x - start.x;
            const dy = screenPoint.y - start.y;
            const d = dx * dx + dy * dy;
            if (d < min_dist && d > 0) {
                min_dist = d;
                min_dist_point = screenPoint;
            }
        });
        if (Logger < 100) {
            console.log('min_dist', min_dist);
            Logger++;
        }
        if (min_dist_point) {
            ctx.beginPath();
            ctx.moveTo(start.x, start.y);
            ctx.lineTo(min_dist_point.x, min_dist_point.y);
            ctx.strokeStyle = DangerColor(start, min_dist_point);
            ctx.lineWidth = 1.5;
            ctx.stroke();
        }
    });
}


// Draws lines connecting the player to food particles
function drawAllFoodLines(start, foodList) {
    let canvas = document.getElementById('bot-line-overlay-food');
    if (!canvas) {
        canvas = document.createElement('canvas');
        canvas.id = 'bot-line-overlay-food';
        canvas.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            pointer-events: none;
            z-index: 9997;
        `;
        document.body.appendChild(canvas);

        window.addEventListener('resize', () => {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        });
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
    }

    const ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    foodList.forEach(food => {
        const end = worldToScreen(food.xx, food.yy);
        ctx.beginPath();
        ctx.moveTo(start.x, start.y);
        ctx.lineTo(end.x, end.y);
        ctx.strokeStyle = 'cyan';
        ctx.lineWidth = 1;
        ctx.stroke();
    });
}

/*
===================================================
Section 7: Animation Loop for Line Drawing
===================================================
Uses requestAnimationFrame for smooth animation.
*/
(function updateEnemyLines() {
    function update() {
        if (
            window.slither &&
            window.slither.xx !== undefined &&
            window.view_xx !== undefined &&
            Array.isArray(window.slithers)
        ) {
            const selfScreen = worldToScreen(window.slither.xx, window.slither.yy);
            const validEnemies = window.slithers.filter(e =>
                e &&
                typeof e.xx === 'number' &&
                typeof e.yy === 'number' &&
                window.slither.xx !== e.xx
            );
            drawAllEnemyLines(selfScreen, validEnemies);
        }
        requestAnimationFrame(update);
    }
    requestAnimationFrame(update);
})();

(function updateFoodTargetLine() {
    let canvas = document.getElementById('bot-line-overlay-food');
    if (!canvas) {
        canvas = document.createElement('canvas');
        canvas.id = 'bot-line-overlay-food';
        canvas.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            pointer-events: none;
            z-index: 9997;
        `;
        document.body.appendChild(canvas);
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        window.addEventListener('resize', () => {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        });
    }

    function update() {
        const ctx = canvas.getContext('2d');
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        if (window.slither && typeof window.slither.xx === 'number' && targetFood) {
            const selfScreen = worldToScreen(window.slither.xx, window.slither.yy);
            const end = worldToScreen(targetFood.xx, targetFood.yy);
            ctx.beginPath();
            ctx.moveTo(selfScreen.x, selfScreen.y);
            ctx.lineTo(end.x, end.y);
            ctx.strokeStyle = 'cyan';
            ctx.lineWidth = 1;
            ctx.stroke();
        }
        requestAnimationFrame(update);
    }
    requestAnimationFrame(update);
})();

/*
===================================================
Section 8: Line between Snake and Real Mouse
===================================================
Draws a magenta line between the snake and the real mouse position.
*/
(function updateMouseLine() {
    let canvas = document.getElementById('bot-line-mouse');
    if (!canvas) {
        canvas = document.createElement('canvas');
        canvas.id = 'bot-line-mouse';
        canvas.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            pointer-events: none;
            z-index: 9996;
        `;
        document.body.appendChild(canvas);
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        window.addEventListener('resize', () => {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        });
    }
    function update() {
        const ctx = canvas.getContext('2d');
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        if (window.slither && typeof window.slither.xx === 'number' && window.mousePos) {
            const selfScreen = worldToScreen(window.slither.xx, window.slither.yy);
            ctx.beginPath();
            ctx.moveTo(selfScreen.x, selfScreen.y);
            ctx.lineTo(window.mousePos.x, window.mousePos.y);
            ctx.strokeStyle = 'magenta';
            ctx.lineWidth = 2;
            ctx.stroke();
        }
        requestAnimationFrame(update);
    }
    requestAnimationFrame(update);
})();

/*
===================================================
Section 9: Line between Snake and Bot Mouse Position
===================================================
Draws a yellow line between the snake and the bot's target position.
*/
(function updateBotMouseLine() {
    let canvas = document.getElementById('bot-line-botmouse');
    if (!canvas) {
        canvas = document.createElement('canvas');
        canvas.id = 'bot-line-botmouse';
        canvas.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            pointer-events: none;
            z-index: 9995;
        `;
        document.body.appendChild(canvas);
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        window.addEventListener('resize', () => {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        });
    }
    function update() {
        const ctx = canvas.getContext('2d');
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        if (window.slither && typeof window.slither.xx === 'number' && window.botTargetPos) {
            const selfScreen = worldToScreen(window.slither.xx, window.slither.yy);
            const targetScreen = worldToScreen(window.botTargetPos.x, window.botTargetPos.y);
            ctx.beginPath();
            ctx.moveTo(selfScreen.x, selfScreen.y);
            ctx.lineTo(targetScreen.x, targetScreen.y);
            ctx.strokeStyle = 'yellow';
            ctx.lineWidth = 2;
            ctx.stroke();
        }
        requestAnimationFrame(update);
    }
    requestAnimationFrame(update);
})();

/*
===================================================
Section 10: FoodBot - Automatic Movement Towards Food
===================================================
Detects the closest enemy and chooses a food particle
located in the opposite direction to move the mouse (and thus the snake).
*/

// Simulates a mouse movement event towards a given position in the world
function moveMouseToward(worldX, worldY) {
    // Updates the bot's target position
    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;

    const event = new MouseEvent('mousemove', {
        clientX: screenX,
        clientY: screenY,
        bubbles: true
    });
    window.dispatchEvent(event);
}

// Declare a variable for the FoodBot interval
let foodBotInterval = null;

// The function containing the FoodBot update code
function foodBotUpdate() {
    if (
        window.slither &&
        typeof window.slither.xx === 'number' &&
        Array.isArray(window.foods)
    ) {
        const self = window.slither;
        const now = Date.now();

        // Building the list of enemies with their closest body point
        let enemyList = [];
        if (Array.isArray(window.slithers)) {
            window.slithers.forEach(enemy => {
                if (!enemy || typeof enemy.xx !== 'number' || typeof enemy.yy !== 'number' || enemy.xx === self.xx)
                    return;
                const bodyPoints = getEnemyBodyPoints(enemy);
                if (bodyPoints.length === 0) return;
                let bestPoint = null;
                let bestDistance = Infinity;
                let bestDx = 0, bestDy = 0;
                bodyPoints.forEach(p => {
                    const dx = p.xx - self.xx;
                    const dy = p.yy - self.yy;
                    const d = Math.sqrt(dx * dx + dy * dy);
                    if (d < bestDistance) {
                        bestDistance = d;
                        bestPoint = p;
                        bestDx = dx;
                        bestDy = dy;
                    }
                });
                if (bestPoint) {
                    enemyList.push({ point: bestPoint, distance: bestDistance, dx: bestDx, dy: bestDy });
                }
            });
        }

        // Utility function to choose the best food in SAFE mode
        // This targets foods with the largest size and high local density (grouping)
        function chooseBestFood(foods) {
            // D'abord, filtrer les nourritures pour ne garder que celles à moins de 100 pixels du joueur
            const maxPlayerDistance = 300;
            const nearbyFoods = foods.filter(f => {
                if (!f || typeof f.xx !== 'number' || typeof f.yy !== 'number') return false;
                const dx = f.xx - self.xx;
                const dy = f.yy - self.yy;
                const d = Math.sqrt(dx * dx + dy * dy);
                return d <= maxPlayerDistance;
            });

            // Si aucune nourriture à proximité, retourner null
            if (nearbyFoods.length === 0) return null;

            let bestFood = null;
            let bestScore = -Infinity;
            const groupRadius = 60; // rayon pour déterminer le groupement

            nearbyFoods.forEach(f => {
                if (!f || typeof f.xx !== 'number' || typeof f.yy !== 'number' || typeof f.sz !== 'number') return;
                let groupCount = 0;

                // Compter combien d'autres nourritures sont proches de celle-ci
                nearbyFoods.forEach(other => {
                    if (other === f) return;
                    const dx = other.xx - f.xx;
                    const dy = other.yy - f.yy;
                    const d = Math.sqrt(dx * dx + dy * dy);
                    if (d < groupRadius) {
                        groupCount++;
                        groupCount += 1/(d+1e-5) * 100;
                    }
                });

                const score = f.sz + groupCount; // combine taille et densité
                if (score > bestScore) {
                    bestScore = score;
                    bestFood = f;
                }
            });

            return bestFood;
        }

        // Filter the food list to exclude blacklisted ones
        let availableFoods = window.foods.filter(f => {
            return (
                f &&
                typeof f.xx === 'number' &&
                typeof f.yy === 'number' &&
                !(blacklistedFoods[`${f.xx}_${f.yy}`] && now < blacklistedFoods[`${f.xx}_${f.yy}`])
            );
        });

        let target = null;

        if (enemyList.length === 0) {
            // No nearby enemies (safe mode): target food with highest value (size + grouping)
            target = chooseBestFood(availableFoods);
        } else {
            // Separate enemies by distance
            const enemiesWithin300 = enemyList.filter(e => e.distance < 300);
            const enemiesBetween300And700 = enemyList.filter(e => e.distance >= 300 && e.distance <= 700);
            // Case 3: If there are one or more enemies in the <300 range, run away
            if (enemiesWithin300.length > 0) {
                let totalWeight = 0;
                let avgX = 0;
                let avgY = 0;

                enemiesWithin300.forEach(e => {
                    const weight = 1 / (e.distance + 1e-5); // Closer = more weight
                    const normX = e.dx / e.distance;
                    const normY = e.dy / e.distance;
                    avgX += normX * weight;
                    avgY += normY * weight;
                    totalWeight += weight;
                });

                if (totalWeight > 0) {
                    avgX /= totalWeight;
                    avgY /= totalWeight;
                }

                const scale = 150;
                const runAwayX = self.xx - avgX * scale;
                const runAwayY = self.yy - avgY * scale;
                moveMouseToward(runAwayX, runAwayY);
                targetFood = null;
                return;
            }

            // Case 2: No critical enemies (<300) but at least one between 300 and 700
            if (enemiesBetween300And700.length > 0) {
                enemiesBetween300And700.sort((a, b) => a.distance - b.distance);
                const closest = enemiesBetween300And700[0];
                // Calculate opposite vector from enemy body point
                const vecX = self.xx - closest.point.xx;
                const vecY = self.yy - closest.point.yy;
                const vecLength = Math.sqrt(vecX * vecX + vecY * vecY);
                const normX = vecLength ? vecX / vecLength : 0;
                const normY = vecLength ? vecY / vecLength : 0;
                // Only keep foods in the opposite direction
                const filteredFoods = availableFoods.filter(f => {
                    const foodVecX = f.xx - self.xx;
                    const foodVecY = f.yy - self.yy;
                    const dot = foodVecX * normX + foodVecY * normY;
                    return dot > 0;
                });
                target = filteredFoods.length ? chooseBestFood(filteredFoods) : chooseBestFood(availableFoods);
            } else {
                // Case 1: All enemies are beyond 700: choose nearest food
                target = chooseBestFood(availableFoods);
            }
        }

        // Blacklist mechanism if the same target is aimed at for more than 2 seconds
        if (
            target &&
            targetFood &&
            target.xx === targetFood.xx &&
            target.yy === targetFood.yy
        ) {
            if (now - targetFoodTimestamp >= 2000) {
                const key = `${targetFood.xx}_${targetFood.yy}`;
                blacklistedFoods[key] = now + 2000;
                const alternatives = availableFoods.filter(
                    f => !(f.xx === targetFood.xx && f.yy === targetFood.yy)
                );
                if (alternatives.length > 0) {
                    target = chooseBestFood(alternatives);
                    targetFoodTimestamp = now;
                } else {
                    target = null;
                }
            }
        } else {
            targetFoodTimestamp = now;
        }

        if (target) {
            moveMouseToward(target.xx, target.yy);
            targetFood = target;
        }
    }
}

// Start FoodBot by launching the setInterval
function startFoodBot() {
    if (!foodBotInterval) {
        foodBotInterval = setInterval(foodBotUpdate, 20);
    }
}

// Stop FoodBot
function stopFoodBot() {
    if (foodBotInterval) {
        clearInterval(foodBotInterval);
        foodBotInterval = null;
    }
}

// On startup, if bot is enabled, launch FoodBot
if (IsBotActive) {
    startFoodBot();

    // Initialise Zoom overlay
    window.recursiveZoomUpdate();
}

// Modifier le gestionnaire d'événements de touches pour ajouter les commandes de zoom
document.addEventListener('keydown', (e) => {
    // Here we use the "t" key to toggle the bot (you can modify according to your needs)
    if (e.key.toLowerCase() === 't') {
        IsBotActive = !IsBotActive;
        if (IsBotActive) {
            startFoodBot();
        } else {
            stopFoodBot();
        }
    }

    // Ajout des touches pour le zoom
    if (e.key.toLowerCase() === 'a') {
        window.adjustZoom(0.1);
    } else if (e.key.toLowerCase() === 'e') {
        window.adjustZoom(-0.1);
    } else if (e.key.toLowerCase() === 'z') {
        window.resetZoom();
    }
});