Nurbo Mod

Auto Insta etc Shift=InstaNormal R=ReverseInsta Space=BoostSpike 2nd click Fast Break B=4Traps-Boost C=4Spikes ,=AntiTrap / M=AutoMills F=Trap-BoostPad V=Spike N=Mill g=Teleport-Turret / AutoBiomeHat Esc=Menu AutoHeal AutoGG

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         Nurbo Mod
// @namespace    http://youtube.com
// @version      1.5.6.2
// @description  Auto Insta etc  Shift=InstaNormal   R=ReverseInsta   Space=BoostSpike  2nd click Fast Break    B=4Traps-Boost   C=4Spikes     ,=AntiTrap / M=AutoMills   F=Trap-BoostPad    V=Spike N=Mill  g=Teleport-Turret / AutoBiomeHat  Esc=Menu  AutoHeal AutoGG 
// @icon         https://static.wikia.nocookie.net/moom/images/7/70/Cookie.png/revision/latest?cb=20190223141839
// @author       Nurbo Mod
// @match        *://moomoo.io/*
// @match        *://*.moomoo.io/*
// @match        *://sandbox.moomoo.io/*
// @match        *://dev.moomoo.io/*
// @grant        none
// @require      https://update.greasyfork.org/scripts/423602/1005014/msgpack.js
// @require      https://update.greasyfork.org/scripts/480301/1322984/CowJS.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/fontfaceobserver.standalone.min.js
// @license      MIT
// ==/UserScript==

//Utility
(function () {
    'use strict';

    let ws;
    const msgpack5 = window.msgpack;

    let boostType, spikeType, turretType = null, windmillType = null, foodType;
    let width, height, mouseX, mouseY;
    let myPlayer = {
        id: null, x: null, y: null, dir: null, object: null,
        weapon: null, clan: null, isLeader: null,
        hat: null, accessory: null, isSkull: null,
        health: 100
    };
    let myPlayeroldx, myPlayeroldy;
    let automillx = 10, automilly = 10;
    let walkmillhaha = false;
    const keysPressed = {};
    const placementIntervals = {};
    let gInterval = null;

    let autoaim = false; // Автоаим ВЫКЛЮЧЕН по умолчанию
    let nearestEnemy = null, nearestEnemyAngle = 0, enemiesNear = [];

    let gameTick = 0, lastDamageTick = 0, damageTimes = 0, shame = 0, shameTime = 0, HP = 100;
    let anti = true;
    let hitBack = false;
    let primary = null;

    // Auto Insta variables - КАК В x-RedDragon Client
    let autoInstaEnabled = false;
    let autoInstaDistance = 200;
    let autoInstaCooldown = 2000;
    let lastAutoInstaTime = 0;
    let autoInstaCheckInterval = null;

    // Auto Spike Surround variables
    let autoSpikeSurroundEnabled = false;
    let spikeSurroundDistance = 50;
    let lastSpikeSurroundTime = 0;
    let spikeSurroundCooldown = 3000;

    // Menu variables
    let menuOpen = false;
    let menuElement = null;
    let menuBtn = null;

    // АВТОХИЛ - ВСЕГДА ВКЛЮЧЕН
    let autoHealEnabled = true;

    function addNamePrefix() {
        const input = document.querySelector('#nameInput');
        if (input && !input.value.trim().startsWith('n-')) {
            input.value = 'n-' + input.value.trim();
        }
    }

    window.addEventListener('load', () => {
        addNamePrefix();
        const input = document.querySelector('#nameInput');
        if (input) {
            input.addEventListener('input', () => {
                input.value = 'n-' + input.value.replace(/^n-+/i, '');
            });

            input.addEventListener('blur', () => {
                if (!input.value.startsWith('n-')) {
                    input.value = 'n-' + input.value;
                }
            });
        }
    });

    function storeEquip(id, index) {
        doNewSend(["c", [0, id, index]]);
    }

    const cvs = document.getElementById("gameCanvas");
    if (!cvs) return;

    cvs.addEventListener("mousemove", e => {
        mouseX = e.clientX;
        mouseY = e.clientY;
        width = e.target.clientWidth;
        height = e.target.clientHeight;
    });

    function doNewSend(sender) {
        if (ws && msgpack5) ws.send(new Uint8Array(Array.from(msgpack5.encode(sender))));
    }

    function place(id, angle = Math.atan2(mouseY - height / 2, mouseX - width / 2)) {
        if (id == null) return;
        doNewSend(["z", [id, null]]);
        doNewSend(["F", [1, angle]]);
        doNewSend(["F", [0, angle]]);
        doNewSend(["z", [myPlayer.weapon, true]]);
    }

    // ФУНКЦИЯ АВТОХИЛА ДЛЯ ГЛАВНОГО ИГРОКА
    function healMainPlayer(currentHealth) {
    if (!autoHealEnabled || currentHealth >= 100) return; // Не хилим если здоровье 100 или больше

    let timeout = 115;
    if (currentHealth <= 60) { // Быстрый хил только при очень низком здоровье (≤60)
        timeout = 1;
    };

    setTimeout(() => {
        if (!ws || ws.readyState !== WebSocket.OPEN) return;

        // Используем яблоко (item 0)
        doNewSend(["z", [0, null]]);
        doNewSend(["F", [1, null]]);
        doNewSend(["F", [0, null]]);
        doNewSend(["z", [myPlayer.weapon, true]]);

        // Если здоровье очень низкое (≤60), используем печеньку (item 1) сразу
        if (currentHealth <= 60) {
            setTimeout(() => {
                doNewSend(["z", [1, null]]);
                doNewSend(["F", [1, null]]);
                doNewSend(["F", [0, null]]);
                doNewSend(["z", [myPlayer.weapon, true]]);
            }, 50);
        }
    }, timeout);
}

    function isVisible(el) {
        return el && el.offsetParent !== null;
    }

    function updateItems() {
        for (let i = 31; i < 33; i++) if (isVisible(document.getElementById("actionBarItem" + i))) boostType = i - 16;
        for (let i = 22; i < 26; i++) if (isVisible(document.getElementById("actionBarItem" + i))) spikeType = i - 16;
        for (let i = 26; i <= 28; i++) if (isVisible(document.getElementById("actionBarItem" + i))) windmillType = i - 16;
        for (let i = 33; i <= 38; i++) if (i !== 36 && isVisible(document.getElementById("actionBarItem" + i))) turretType = i - 16;
        for (let i = 16; i <= 18; i++) if (isVisible(document.getElementById("actionBarItem" + i))) foodType = i - 16;
    }
    setInterval(updateItems, 250);

    function toRad(degrees) {
        return degrees * 0.01745329251;
    }

    function getSecondaryWeaponIndex() {
        for (let i = 9; i <= 15; i++) {
            if (isVisible(document.getElementById("actionBarItem" + i)) && i !== myPlayer.weapon) {
                return i;
            }
        }
        return myPlayer.weapon;
    }

    function startPlacingStructure(key, itemId) {
        if (!placementIntervals[key]) placementIntervals[key] = setInterval(() => place(itemId), 50);
    }
    function stopPlacingStructure(key) {
        clearInterval(placementIntervals[key]);
        delete placementIntervals[key];
    }

    function performGSequence() {
        if (!nearestEnemy) return;

        const dx = myPlayer.x - nearestEnemy[1];
        const dy = myPlayer.y - nearestEnemy[2];
        const distance = Math.sqrt(dx * dx + dy * dy);

        doNewSend(["9", [nearestEnemyAngle]]);

        place(spikeType, nearestEnemyAngle + Math.PI / 2);
        place(spikeType, nearestEnemyAngle - Math.PI / 2);

        if (distance <= 150) {
            place(spikeType, nearestEnemyAngle - Math.PI / 4);
            place(spikeType, nearestEnemyAngle + Math.PI / 4);
        }

        place(boostType, nearestEnemyAngle);
    }

    function performBPlacement() {
        const base = myPlayer.dir;
        place(boostType, base);
        place(boostType, base + Math.PI / 2);
        place(boostType, base - Math.PI / 2);
        place(boostType, base + Math.PI);
    }

    function placeFourSpikesUp() {
        const firstAngle = -Math.PI / 2;
        place(spikeType, firstAngle);
        place(spikeType, firstAngle + toRad(90));
        place(spikeType, firstAngle + toRad(180));
        place(spikeType, firstAngle + toRad(270));
    }

    function performSpikeSurround() {
        if (!nearestEnemy || !autoSpikeSurroundEnabled) return;

        const currentTime = Date.now();
        if (currentTime - lastSpikeSurroundTime < spikeSurroundCooldown) return;

        const dx = myPlayer.x - nearestEnemy[1];
        const dy = myPlayer.y - nearestEnemy[2];
        const distance = Math.sqrt(dx * dx + dy * dy);

        if (distance <= spikeSurroundDistance) {
            const enemyAngle = nearestEnemyAngle;
            place(spikeType, enemyAngle);
            place(spikeType, enemyAngle + Math.PI / 2);
            place(spikeType, enemyAngle + Math.PI);
            place(spikeType, enemyAngle + 3 * Math.PI / 2);

            lastSpikeSurroundTime = Date.now();
        }
    }

    function performNormalInsta() {
        if (!nearestEnemy) return;

        storeEquip(0, 1);
        setTimeout(() => {
            const wasAutoaim = autoaim;
            autoaim = true;
            const primary = myPlayer.weapon;
            const secondary = getSecondaryWeaponIndex();

            doNewSend(["c", [0, 7, 0]]);
            doNewSend(["z", [primary, true]]);
            doNewSend(["F", [1]]);
            setTimeout(() => doNewSend(["F", [0]]), 25);

            setTimeout(() => {
                doNewSend(["c", [0, 53, 0]]);
                doNewSend(["z", [secondary, true]]);
                doNewSend(["F", [1]]);
                setTimeout(() => doNewSend(["F", [0]]), 25);

                setTimeout(() => {
                    doNewSend(["c", [0, 6, 0]]);
                    doNewSend(["z", [primary, true]]);
                    doNewSend(["z", [primary, true]]);
                    autoaim = wasAutoaim;

                    setTimeout(() => {
                        storeEquip(11, 1);

                        if (secondary === 15) {
                            doNewSend(["z", [secondary, true]]);
                            setTimeout(() => doNewSend(["z", [primary, true]]), 1900);
                        } else if (secondary === 12) {
                            doNewSend(["z", [secondary, true]]);
                            setTimeout(() => doNewSend(["z", [primary, true]]), 1000);
                        } else if (secondary === 13) {
                            doNewSend(["z", [secondary, true]]);
                            setTimeout(() => doNewSend(["z", [primary, true]]), 400);
                        }
                    }, 170);
                }, 120);
            }, 120);
        }, 120);
    }

    function performReverseInsta() {
        if (!nearestEnemy) return;

        storeEquip(0, 1);
        setTimeout(() => {
            const wasAutoaim = autoaim;
            autoaim = true;
            const primary = myPlayer.weapon;
            const secondary = getSecondaryWeaponIndex();

            doNewSend(["z", [secondary, true]]);
            doNewSend(["z", [secondary, true]]);

            doNewSend(["c", [0, 53, 0]]);
            doNewSend(["F", [1]]);
            setTimeout(() => doNewSend(["F", [0]]), 20);

            setTimeout(() => {
                doNewSend(["z", [primary, true]]);
                doNewSend(["c", [0, 7, 0]]);
                doNewSend(["F", [1]]);
                setTimeout(() => doNewSend(["F", [0]]), 20);
            }, 80);

            setTimeout(() => {
                doNewSend(["z", [primary, true]]);
                doNewSend(["z", [primary, true]]);
                doNewSend(["c", [0, 6, 0]]);
                storeEquip(11, 1);
                autoaim = wasAutoaim;

                setTimeout(() => {
                    if (secondary === 15) {
                        doNewSend(["z", [secondary, true]]);
                        setTimeout(() => doNewSend(["z", [primary, true]]), 1000);
                    } else if (secondary === 12) {
                        doNewSend(["z", [secondary, true]]);
                        setTimeout(() => doNewSend(["z", [primary, true]]), 700);
                    } else if (secondary === 13) {
                        doNewSend(["z", [secondary, true]]);
                        setTimeout(() => doNewSend(["z", [primary, true]]), 300);
                    }
                }, 150);
            }, 400);
        }, 100);
    }

    function checkAndPerformAutoInsta() {
        if (!autoInstaEnabled || !nearestEnemy || myPlayer.health < 50) return;

        const currentTime = Date.now();
        if (currentTime - lastAutoInstaTime < autoInstaCooldown) return;

        const dx = myPlayer.x - nearestEnemy[1];
        const dy = myPlayer.y - nearestEnemy[2];
        const distance = Math.sqrt(dx * dx + dy * dy);

        if (distance <= autoInstaDistance) {
            performNormalInsta();
            lastAutoInstaTime = Date.now();
            doNewSend(["6", ["Auto-Insta активирована!"]]);
        }
    }

    function toggleAutoInsta() {
        autoInstaEnabled = !autoInstaEnabled;
        if (autoInstaEnabled) {
            if (!autoInstaCheckInterval) {
                autoInstaCheckInterval = setInterval(checkAndPerformAutoInsta, 1000);
            }
            doNewSend(["6", ["Auto-Insta: ON (расстояние: " + autoInstaDistance + ")"]]);
        } else {
            if (autoInstaCheckInterval) {
                clearInterval(autoInstaCheckInterval);
                autoInstaCheckInterval = null;
            }
            doNewSend(["6", ["Auto-Insta: OFF"]]);
        }
        updateMenu();
    }

    function toggleAutoSpikeSurround() {
        autoSpikeSurroundEnabled = !autoSpikeSurroundEnabled;
        doNewSend(["6", ["AS " + (autoSpikeSurroundEnabled ?'hehe' : 'off')]]);
        updateMenu();
    }

    // ВАЖНО: Исправленная функция toggleAimMode
    function toggleAimMode() {
        autoaim = !autoaim;

        if (autoaim) {
            doNewSend(["6", ["AutoAim: ON (следит за врагом)"]]);
        } else {
            doNewSend(["6", ["AutoAim: OFF (курсор мыши)"]]);
            // Возвращаем направление взгляда к курсору мыши при выключении
            const angle = Math.atan2(mouseY - height / 2, mouseX - width / 2);
            doNewSend(["D", [angle]]);
        }
        updateMenu();
    }

    // ФУНКЦИЯ ПЕРЕКЛЮЧЕНИЯ АВТОХИЛА
    function toggleAutoHeal() {
        autoHealEnabled = !autoHealEnabled;
        doNewSend(["6", ["AutoHeal: " + (autoHealEnabled ? "ON" : "OFF")]]);
        updateMenu();
    }

    // Функция для обновления направления взгляда
    function updateAimDirection() {
        if (autoaim && nearestEnemy) {
            // Автоаим включен и есть враг - следим за ним
            doNewSend(["D", [nearestEnemyAngle]]);
        } else if (!autoaim) {
            // Автоаим выключен - нормальное управление мышью
            const angle = Math.atan2(mouseY - height / 2, mouseX - width / 2);
            doNewSend(["D", [angle]]);
        }
        // Если autoaim включен, но врага нет - ничего не делаем
    }

    // Заменяем старый интервал автоаима
    setInterval(updateAimDirection, 10);

    // Функции для меню
    function createMenu() {
        if (document.getElementById('nurbo-mod-menu')) return;

        menuElement = document.createElement('div');
        menuElement.id = 'nurbo-mod-menu';
        menuElement.style.cssText = `
            position: fixed;
            top: 50px;
            left: 10px;
            background: rgba(0, 0, 0, 0.95);
            color: white;
            padding: 12px;
            border-radius: 8px;
            z-index: 9999;
            font-family: 'Segoe UI', Arial, sans-serif;
            font-size: 13px;
            min-width: 280px;
            display: none;
            border: 2px solid #00ff00;
        `;

        document.body.appendChild(menuElement);
        updateMenu();
    }

    function updateMenu() {
        if (!menuElement) return;

        menuElement.innerHTML = '';

        const titleBar = document.createElement('div');
        titleBar.style.cssText = 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;';

        const title = document.createElement('div');
        title.textContent = '⚡ Nurbo Mod v1.5.6.2';
        title.style.cssText = 'font-size: 14px; font-weight: bold; color: #00ff00;';

        const closeBtn = document.createElement('button');
        closeBtn.textContent = '✖';
        closeBtn.style.cssText = `
            background: #ff3333;
            color: white;
            border: none;
            border-radius: 3px;
            width: 22px;
            height: 22px;
            cursor: pointer;
            font-size: 11px;
            padding: 0;
        `;
        closeBtn.onclick = () => toggleMenu();

        titleBar.appendChild(title);
        titleBar.appendChild(closeBtn);
        menuElement.appendChild(titleBar);

        const togglesGrid = document.createElement('div');
        togglesGrid.style.cssText = 'display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin-bottom: 15px;';

        const toggleSettings = [
            { name: 'Auto Insta', value: autoInstaEnabled, toggle: toggleAutoInsta, key: 'P' },
            { name: 'Auto Spike', value: autoSpikeSurroundEnabled, toggle: toggleAutoSpikeSurround, key: 'U' },
            { name: 'Auto Aim', value: autoaim, toggle: toggleAimMode, key: 'O' },
            { name: 'Auto Heal', value: autoHealEnabled, toggle: toggleAutoHeal, key: 'H' },
        ];

        toggleSettings.forEach(setting => {
            const toggleItem = document.createElement('div');
            toggleItem.style.cssText = 'display: flex; justify-content: space-between; align-items: center;';

            const label = document.createElement('span');
            label.textContent = setting.name;
            label.style.cssText = 'color: #cccccc; font-size: 12px;';

            const toggleBtn = document.createElement('button');
            toggleBtn.textContent = setting.value ? 'ON' : 'OFF';
            toggleBtn.style.cssText = `
                background: ${setting.value ? '#00aa00' : '#550000'};
                color: white;
                border: none;
                border-radius: 3px;
                padding: 2px 10px;
                cursor: pointer;
                font-size: 11px;
                font-weight: bold;
                min-width: 40px;
            `;
            toggleBtn.onclick = setting.toggle;

            const keyHint = document.createElement('span');
            keyHint.textContent = setting.key;
            keyHint.style.cssText = 'color: #00ff00; font-size: 10px; margin-left: 5px;';

            toggleItem.appendChild(label);
            const rightSide = document.createElement('div');
            rightSide.style.cssText = 'display: flex; align-items: center;';
            rightSide.appendChild(toggleBtn);
            rightSide.appendChild(keyHint);
            toggleItem.appendChild(rightSide);

            togglesGrid.appendChild(toggleItem);
        });

        menuElement.appendChild(togglesGrid);

        // Settings section - ОСТАВИМ ВОЗМОЖНОСТЬ РЕГУЛИРОВКИ ДИСТАНЦИИ
        const controlsTitle = document.createElement('div');
        controlsTitle.textContent = 'Settings:';
        controlsTitle.style.cssText = 'color: #00ffff; font-weight: bold; font-size: 12px; margin: 10px 0 5px 0; border-top: 1px solid #333; padding-top: 8px;';
        menuElement.appendChild(controlsTitle);

        const createSlider = (labelText, value, min, max, step, onChange, keyText = '') => {
            const container = document.createElement('div');
            container.style.cssText = 'margin: 6px 0;';

            const labelRow = document.createElement('div');
            labelRow.style.cssText = 'display: flex; justify-content: space-between; margin-bottom: 3px;';

            const label = document.createElement('span');
            label.textContent = labelText;
            label.style.cssText = 'color: #aaaaaa; font-size: 11px;';

            const valueDisplay = document.createElement('span');
            valueDisplay.textContent = value + 'px';
            valueDisplay.style.cssText = 'color: #ffff00; font-size: 11px; font-weight: bold;';

            labelRow.appendChild(label);
            labelRow.appendChild(valueDisplay);
            container.appendChild(labelRow);

            const slider = document.createElement('input');
            slider.type = 'range';
            slider.min = min;
            slider.max = max;
            slider.step = step;
            slider.value = value;
            slider.style.cssText = 'width: 100%; height: 4px; margin: 2px 0;';

            slider.oninput = () => {
                valueDisplay.textContent = slider.value + 'px';
                onChange(parseInt(slider.value));
            };

            container.appendChild(slider);

            if (keyText) {
                const keyInfo = document.createElement('div');
                keyInfo.textContent = keyText;
                keyInfo.style.cssText = 'color: #00aa00; font-size: 9px; text-align: right; margin-top: 2px;';
                container.appendChild(keyInfo);
            }

            return container;
        };

        // Добавляем слайдер для дистанции авто-инсты
        menuElement.appendChild(createSlider(
            'Auto Insta Distance',
            autoInstaDistance,
            100,
            500,
            50,
            (val) => {
                autoInstaDistance = val;
                doNewSend(["6", ["Auto-Insta расстояние: " + val + "px"]]);
                updateMenu();
            },
            '[ ] to adjust'
        ));

        // Fixed distances info
        const fixedDistances = document.createElement('div');
        fixedDistances.style.cssText = 'margin-top: 10px; font-size: 10px; color: #888888;';
        fixedDistances.innerHTML = `
            <div>Auto Spike: ${spikeSurroundDistance}px</div>
        `;
        menuElement.appendChild(fixedDistances);

        // Hotkeys in compact view
        const hotkeysTitle = document.createElement('div');
        hotkeysTitle.textContent = 'Hotkeys:';
        hotkeysTitle.style.cssText = 'color: #ffaa00; font-weight: bold; font-size: 12px; margin: 12px 0 5px 0; border-top: 1px solid #333; padding-top: 8px;';
        menuElement.appendChild(hotkeysTitle);

        const hotkeysGrid = document.createElement('div');
        hotkeysGrid.style.cssText = 'display: grid; grid-template-columns: repeat(2, 1fr); gap: 5px; font-size: 10px;';

        const hotkeys = [
            'Shift - Insta',
            'R - Reverse Insta',
            'Space - Boost+Spike',
            'B - 4 Traps',
            'C - 4 Spikes',
            ', - AntiTrap',
            'F - Trap/Boost',
            'V - Spike',
            'N - Mill',
            '[ ] - AutoDist',
            'ESC - Menu',
            '[L] - Send Alt',
           ' [,] - Delete Alts',
'[Z] - Repel Alts Away From Cursor'
        ];

        hotkeys.forEach(hotkey => {
            const item = document.createElement('div');
            item.textContent = hotkey;
            item.style.cssText = 'color: #cccccc; font-size: 10px; padding: 2px 4px; background: rgba(255,255,255,0.05); border-radius: 3px;';
            hotkeysGrid.appendChild(item);
        });

        menuElement.appendChild(hotkeysGrid);
    }

    function toggleMenu() {
        menuOpen = !menuOpen;
        if (menuElement) {
            menuElement.style.display = menuOpen ? 'block' : 'none';
        }
        if (menuBtn) {
            menuBtn.textContent = menuOpen ? '✖' : '⚙️';
            menuBtn.style.background = menuOpen ? 'rgba(100, 0, 0, 0.9)' : 'rgba(0, 0, 0, 0.9)';
        }
    }

    document.addEventListener("keydown", e => {
        if (document.activeElement.id.toLowerCase() === 'chatbox') return;
        const k = e.key.toLowerCase();
        if (keysPressed[k]) return;
        keysPressed[k] = true;

        //=== INSTAKILL NORMAL === (ТОЧНО КАК В x-RedDragon Client)
        if (e.keyCode == 16 && document.activeElement.id.toLowerCase() !== "chatbox") {
            storeEquip(0, 1);
            setTimeout(() => {
                autoaim = true;
                const primary = myPlayer.weapon;
                const secondary = getSecondaryWeaponIndex();

                doNewSend(["c", [0, 7, 0]]);
                doNewSend(["z", [primary, true]]);
                doNewSend(["F", [1]]);
                setTimeout(() => doNewSend(["F", [0]]), 25);

                setTimeout(() => {
                    doNewSend(["c", [0, 53, 0]]);
                    doNewSend(["z", [secondary, true]]);
                    doNewSend(["F", [1]]);
                    setTimeout(() => doNewSend(["F", [0]]), 25);

                    setTimeout(() => {
                        doNewSend(["c", [0, 6, 0]]);
                        doNewSend(["z", [primary, true]]);
                        doNewSend(["z", [primary, true]]);
                        autoaim = false;

                        setTimeout(() => {
                            storeEquip(11, 1);

                            if (secondary === 15) {
                                doNewSend(["z", [secondary, true]]);
                                setTimeout(() => doNewSend(["z", [primary, true]]), 1500);
                            } else if (secondary === 12) {
                                doNewSend(["z", [secondary, true]]);
                                setTimeout(() => doNewSend(["z", [primary, true]]), 1000);
                            } else if (secondary === 13) {
                                doNewSend(["z", [secondary, true]]);
                                setTimeout(() => doNewSend(["z", [primary, true]]), 400);
                            }
                        }, 170);
                    }, 120);
                }, 120);
            }, 120);
        }

        //=== INSTAKILL REVERSO ===
        if (e.keyCode == 82 && document.activeElement.id.toLowerCase() !== "chatbox") {
            performReverseInsta();
        }

        //=== BOOST SPIKE (Space) ===
        if (e.keyCode == 32 && document.activeElement.id.toLowerCase() !== "chatbox") {
            if (!nearestEnemy) return;

            // Быстрый буст+спайк
            doNewSend(["9", [nearestEnemyAngle]]);
            place(boostType, nearestEnemyAngle);
            place(spikeType, nearestEnemyAngle + Math.PI / 4);
            place(spikeType, nearestEnemyAngle - Math.PI / 4);

            if (!gInterval) {
                gInterval = setInterval(() => {
                    if (nearestEnemy) {
                        doNewSend(["9", [nearestEnemyAngle]]);
                        place(boostType, nearestEnemyAngle);
                    }
                }, 80);
            }
        }

        //=== AUTO INSTA TOGGLE ===
        if (k === 'p') {
            toggleAutoInsta();
        }

        //=== AUTO SPIKE SURROUND TOGGLE ===
        if (k === 'u') {
            toggleAutoSpikeSurround();
        }

        //=== AUTO HEAL TOGGLE ===
        if (k === 'h') {
            toggleAutoHeal();
        }

        //=== MENU TOGGLE ===
        if (e.keyCode === 27) {
            toggleMenu();
        }
           if (k === 'o') {
            toggleAimMode();
        }

        //=== AUTO INSTA DISTANCE CONTROL === (ТОЧНО КАК В x-RedDragon Client)
        if (k === '[' && autoInstaEnabled) {
            autoInstaDistance = Math.max(100, autoInstaDistance - 50);
            doNewSend(["6", ["Auto-Insta расстояние: " + autoInstaDistance]]);
            updateMenu();
        }
        if (k === ']' && autoInstaEnabled) {
            autoInstaDistance = Math.min(500, autoInstaDistance + 50);
            doNewSend(["6", ["Auto-Insta расстояние: " + autoInstaDistance]]);
            updateMenu();
        }

        //=== SPIKE DISTANCE CONTROL ===
        if (k === '.' && autoSpikeSurroundEnabled) {
            spikeSurroundDistance = Math.max(30, spikeSurroundDistance - 10);
            doNewSend(["6", ["Auto Spike расстояние: " + spikeSurroundDistance]]);
            updateMenu();
        }
        if (k === '/' && autoSpikeSurroundEnabled) {
            spikeSurroundDistance = Math.min(100, spikeSurroundDistance + 10);
            doNewSend(["6", ["Auto Spike расстояние: " + spikeSurroundDistance]]);
            updateMenu();
        }

        if (k === 'm') {
            walkmillhaha = !walkmillhaha;
            doNewSend(["6", ["Auto Mills: " + (walkmillhaha ? "ON" : "OFF")]]);
            updateMenu();
        }
        if (k === 'f') startPlacingStructure(k, boostType);
        if (k === 'v') startPlacingStructure(k, spikeType);
        if (k === 'n') startPlacingStructure(k, windmillType);
        if (k === 'g') startPlacingStructure(k, turretType);

        if (k === 'b') performBPlacement();
        if (k === 'c') placeFourSpikesUp();
    });

    document.addEventListener("keyup", e => {
        const k = e.key.toLowerCase();
        keysPressed[k] = false;
        stopPlacingStructure(k);

        if (e.keyCode == 32 && gInterval) { // Space released
            clearInterval(gInterval);
            gInterval = null;

            if (nearestEnemy) {
                doNewSend(["9", [myPlayer.dir]]);
                place(spikeType, nearestEnemyAngle - Math.PI / 4);
                place(spikeType, nearestEnemyAngle + Math.PI / 4);
            }
        }
    });

    if (!WebSocket.prototype.__originalSend) {
        WebSocket.prototype.__originalSend = WebSocket.prototype.send;
        WebSocket.prototype.send = function (data) {
            if (!ws) {
                ws = this;
                document.ws = this;
                ws.addEventListener("message", handleMessage);
            }
            return this.__originalSend(data);
        };
    }

    function handleMessage(m) {
        let temp = msgpack5.decode(new Uint8Array(m.data));
        let data = (temp.length > 1) ? [temp[0], ...temp[1]] : temp;
        if (!data) return;

        if (data[0] === "C" && myPlayer.id == null) myPlayer.id = data[1];

        if (data[0] === "a") {
            for (let i = 0; i < data[1].length / 13; i++) {
                let obj = data[1].slice(13 * i, 13 * i + 13);
                if (obj[0] === myPlayer.id) {
                    [myPlayer.x, myPlayer.y, myPlayer.dir, myPlayer.object, myPlayer.weapon,
                        , myPlayer.clan, myPlayer.isLeader, myPlayer.hat, myPlayer.accessory,
                        myPlayer.isSkull] = [obj[1], obj[2], obj[3], obj[4],
                        obj[5], obj[7], obj[8], obj[9], obj[10], obj[11]];
                } else enemiesNear.push(obj);
            }

            if (enemiesNear.length > 0) {
                nearestEnemy = enemiesNear.sort(
                    (a, b) => Math.hypot(a[1] - myPlayer.x, a[2] - myPlayer.y) - Math.hypot(b[1] - myPlayer.x, b[2] - myPlayer.y)
                )[0];
                nearestEnemyAngle = Math.atan2(nearestEnemy[2] - myPlayer.y, nearestEnemy[1] - myPlayer.x);

                if (autoSpikeSurroundEnabled) {
                    performSpikeSurround();
                }
            } else nearestEnemy = null;

            enemiesNear = [];

            if (automillx === false) automillx = myPlayer.x;
            if (automilly === false) automilly = myPlayer.y;

            if (myPlayeroldy !== myPlayer.y || myPlayeroldx !== myPlayer.x) {
                if (walkmillhaha) {
                    if (Math.sqrt(Math.pow(myPlayer.y - automilly, 2) + Math.pow(myPlayer.x - automillx, 2)) > 100) {
                        let angle = Math.atan2(myPlayeroldy - myPlayer.y, myPlayeroldx - myPlayer.x);
                        place(windmillType, angle + toRad(78));
                        place(windmillType, angle - toRad(78));
                        place(windmillType, angle);
                        doNewSend(["D", [Math.atan2(mouseY - height / 2, mouseX - width / 2)]]);
                        automillx = myPlayer.x;
                        automilly = myPlayer.y;
                    }
                }
                myPlayeroldx = myPlayer.x;
                myPlayeroldy = myPlayer.y;
            }
        }

        if (data[0] === "O" && data[1] === myPlayer.id) {
            gameTick = 0;
            lastDamageTick = 0;
            shame = 0;
            HP = 100;
            shameTime = 0;
            myPlayer.health = data[2];

           
          
        }
    }

    setInterval(() => {
        if (autoaim && nearestEnemy) doNewSend(["D", [nearestEnemyAngle]]);
    }, 10);

    // 🧠 Anti-Rotación
    Object.defineProperty(Object.prototype, "turnSpeed", {
        get() { return 0; },
        set(_) {},
        configurable: true
    });

    // === AUTO GG ===
    let prevKillCount = 0;

    function initAutoGG() {
        const killCounter = document.getElementById("killCounter");
        if (!killCounter) {
            setTimeout(initAutoGG, 500);
            return;
        }

        const observer = new MutationObserver(() => {
            const count = parseInt(killCounter.innerText, 10) || 0;
            if (count > prevKillCount) {
                prevKillCount = count;
                doNewSend(["6", ["Nurbo mod gg"]]);
                setTimeout(() => {
                    doNewSend(["6", [``]]);
                }, 1000);
            }
        });

        observer.observe(killCounter, { childList: true, characterData: true, subtree: true });
    }

    initAutoGG();

    // === FASTBREAK ===
    let rightClickAttackInterval = null;
    let rightClickHeld = false;
    let isPlacingStructure = false;
    let attackPausedForPlacement = false;

    function ensureCorrectWeapon() {
        const primary = myPlayer.weapon;
        const secondary = getSecondaryWeaponIndex();

        let correctWeapon = (secondary === 10) ? secondary : primary;

        if (myPlayer.weapon !== correctWeapon) {
            doNewSend(["z", [correctWeapon, true]]);
        }
    }

    function startAttackLoop() {
        if (rightClickAttackInterval) return;

        rightClickAttackInterval = setInterval(() => {
            ensureCorrectWeapon();
            doNewSend(["c", [0, 40, 0]]);
            doNewSend(["F", [1]]);
            setTimeout(() => doNewSend(["F", [0]]), 8);
        }, 50);
    }

    function stopAttackLoop() {
        clearInterval(rightClickAttackInterval);
        rightClickAttackInterval = null;
    }

    document.addEventListener("mousedown", function (e) {
        if (e.button === 2 && !rightClickHeld) {
            rightClickHeld = true;
            doNewSend(["c", [0, 40, 0]]);

            setTimeout(() => {
                if (rightClickHeld && !isPlacingStructure) {
                    startAttackLoop();
                }
            }, 50);
        }
    });

    document.addEventListener("mouseup", function (e) {
        if (e.button === 2 && rightClickHeld) {
            rightClickHeld = false;
            stopAttackLoop();
            doNewSend(["F", [0]]);
            setTimeout(() => doNewSend(["c", [0, 6, 0]]), 80);
        }
    });

    const originalPlace = place;
    place = function (...args) {
        isPlacingStructure = true;

        if (rightClickAttackInterval) {
            attackPausedForPlacement = true;
            stopAttackLoop();
        }

        originalPlace.apply(this, args);

        setTimeout(() => {
            isPlacingStructure = false;
            if (rightClickHeld && attackPausedForPlacement) {
                attackPausedForPlacement = false;
                startAttackLoop();
            }
        }, 80);
    };

    const oldStoreEquip = window.storeEquip;
    window.storeEquip = function (id, slot) {
        oldStoreEquip.apply(this, arguments);

        if (rightClickHeld) {
            ensureCorrectWeapon();
        }
    };

    const oldEquipWeapon = window.equipWeapon;
    window.equipWeapon = function (id) {
        oldEquipWeapon.apply(this, arguments);

        if (rightClickHeld) {
            ensureCorrectWeapon();
        }
    };

    // 🎩 AutoBiomeHatController
    function autoBiomeHatController() {
        let normalHat = 12;
        let currentHat = null;
        let overridePause = false;
        let resumeTimeout = null;
        const movementKeys = new Set();
        const overrideKeys = new Set([16, "r", " "]);

        function setHat(id) {
            if (id !== currentHat && myPlayer && myPlayer.id != null) {
                currentHat = id;
                doNewSend(["c", [0, id, 0]]);

                let accessoryId = null;
                if (id === 6) {
                    accessoryId = 0;
                } else if ([15, 31, 12].includes(id)) {
                    accessoryId = 11;
                }

                if (accessoryId !== null) {
                    [30, 60, 90].forEach(delay => {
                        setTimeout(() => {
                            storeEquip(accessoryId, 1);
                        }, delay);
                    });
                }
            }
        }

        function updateBiomeHat() {
            if (!myPlayer || typeof myPlayer.y !== "number") return;
            if (myPlayer.y < 2400) normalHat = 15;
            else if (myPlayer.y > 6850 && myPlayer.y < 7550) normalHat = 31;
            else normalHat = 12;
        }

        function updateHatLogic() {
            if (overridePause) return;
            updateBiomeHat();
            if (movementKeys.size > 0) {
                setHat(normalHat);
            } else {
                setHat(6);
            }
        }

        function pauseOverride() {
            overridePause = true;
            if (resumeTimeout) clearTimeout(resumeTimeout);
        }

        function resumeOverride() {
            if (resumeTimeout) clearTimeout(resumeTimeout);
            resumeTimeout = setTimeout(() => {
                overridePause = false;
                updateHatLogic();
            }, 300);
        }

        document.addEventListener("keydown", e => {
            const key = e.key.toLowerCase();
            if (["w", "a", "s", "d", "arrowup", "arrowdown", "arrowleft", "arrowright"].includes(key)) {
                if (!movementKeys.has(key)) {
                    movementKeys.add(key);
                    updateHatLogic();
                }
            }
            if (overrideKeys.has(key)) pauseOverride();
        });

        document.addEventListener("keyup", e => {
            const key = e.key.toLowerCase();
            if (movementKeys.delete(key)) updateHatLogic();
            if (overrideKeys.has(key)) resumeOverride();
        });

        document.addEventListener("mousedown", e => {
            if (e.button === 0 || e.button === 2) pauseOverride();
        });

        document.addEventListener("mouseup", e => {
            if (e.button === 0 || e.button === 2) resumeOverride();
        });

        setInterval(() => {
            if (!overridePause) updateHatLogic();
        }, 200);
    }

    autoBiomeHatController();

    // === ANTI TRAP ===
    let antiTrap = false;
    let intrap = false;
    let trapAngle = null;
    let trapId = null;

    document.addEventListener("keydown", e => {
        if (document.activeElement.id.toLowerCase() === 'chatbox') return;
        if (e.key === ",") {
            antiTrap = !antiTrap;
            doNewSend(["6", ["AntiTrap: " + (antiTrap ? "ON" : "OFF")]]);
        }
    });

    function handleTrapData(node) {
        for (let i = 0; i < node[1].length / 8; i++) {
            let obj = node[1].slice(8 * i, 8 * i + 8);
            if (obj[6] === 15 && obj[7] !== myPlayer.id && obj[7] !== myPlayer.clan) {
                let dx = obj[1] - myPlayer.x;
                let dy = obj[2] - myPlayer.y;
                let dist = Math.sqrt(dx * dx + dy * dy);
                if (dist < 90) {
                    intrap = true;
                    trapAngle = Math.atan2(dy, dx);
                    trapId = obj[0];

                }
            }
        }
    }

    const oldHandleMessage = handleMessage;
    handleMessage = function (m) {
        let temp = msgpack5.decode(new Uint8Array(m.data));
        let data = (temp.length > 1) ? [temp[0], ...temp[1]] : temp;
        if (!data) return;

        if (data[0] === "H") handleTrapData(data);

        if (data[0] === "Q" && intrap && trapId === data[1]) {
            intrap = false;
            trapId = null;
            setTimeout(() => doNewSend(["c", [0, 6, 0]]), 80);

        }

        oldHandleMessage(m);
    };

    function hookEquipFunctions() {
        if (typeof window.storeEquip === "function" && typeof window.equipWeapon === "function") {
            const oldStoreEquip = window.storeEquip;
            window.storeEquip = function (id, slot) {
                const result = oldStoreEquip.apply(this, arguments);
                if (antiTrap && intrap) ensureCorrectWeapon();
                return result;
            };

            const oldEquipWeapon = window.equipWeapon;
            window.equipWeapon = function (id) {
                const result = oldEquipWeapon.apply(this, arguments);
                if (antiTrap && intrap) ensureCorrectWeapon();
                return result;
            };
        } else {
            setTimeout(hookEquipFunctions, 100);
        }
    }
    hookEquipFunctions();

    setInterval(() => {
        if (!antiTrap || !intrap) return;
        if (!ws || ws.readyState !== WebSocket.OPEN) return;

        let oppositeAngle = trapAngle + Math.PI;
        place(spikeType, oppositeAngle);
        ensureCorrectWeapon();

        doNewSend(["D", [trapAngle]]);
        doNewSend(["c", [0, 40, 0]]);
        doNewSend(["F", [1, trapAngle]]);
        setTimeout(() => doNewSend(["F", [0, trapAngle]]), 12);
    }, 250);

    // Create menu on load
    setTimeout(() => {
        if (document.getElementById('nurbo-mod-menu-btn')) return;

        createMenu();

        // Add menu button
        menuBtn = document.createElement('button');
        menuBtn.id = 'nurbo-mod-menu-btn';
        menuBtn.textContent = '⚙️';
        menuBtn.style.cssText = `
            position: fixed;
            top: 10px;
            left: 10px;
            background: rgba(0, 0, 0, 0.9);
            color: #00ff00;
            border: 1px solid #00ff00;
            border-radius: 4px;
            width: 30px;
            height: 30px;
            font-size: 16px;
            cursor: pointer;
            z-index: 9998;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 0 8px rgba(0, 255, 0, 0.3);
            transition: all 0.2s;
            padding: 0;
        `;
        menuBtn.onmouseover = () => {
            menuBtn.style.background = 'rgba(0, 80, 0, 0.9)';
            menuBtn.style.transform = 'scale(1.05)';
        };
        menuBtn.onmouseout = () => {
            menuBtn.style.background = menuOpen ? 'rgba(100, 0, 0, 0.9)' : 'rgba(0, 0, 0, 0.9)';
            menuBtn.style.transform = 'scale(1)';
        };
        menuBtn.onclick = () => toggleMenu();
        document.body.appendChild(menuBtn);
    }, 1500);
})();

// Остальные части скрипта (WeaponReloadPrediction, HealBarsBuildings, AutoVerifity, AutoReloadWeb) остаются без изменений
//WeaponReloadPrediction
(function () {
	"use strict";

	let ws;
	const msgpack = window.msgpack;

	WebSocket.prototype._send = WebSocket.prototype.send;
	WebSocket.prototype.send = function (m) {
		if (!ws) {
			ws = this;
			window.ws = this;
		}
		this._send(m);
	};

	function modifyCanvasRenderingContext2D() {
		if (CanvasRenderingContext2D.prototype.roundRect) {
			CanvasRenderingContext2D.prototype.roundRect = function (x, y, w, h) {
				this.beginPath();
				this.rect(x, y, w, h);
				this.closePath();
				return this;
			};
		}
	}

	if (window.jQuery) {
		$(document).ready(modifyCanvasRenderingContext2D);
	} else {
		window.addEventListener("load", modifyCanvasRenderingContext2D);
	}

	window.Cow.setCodec(msgpack);

	window.Cow.addRender("global", () => {
		const ctx = window.Cow.renderer.context;

		const hbWidth = window.config?.healthBarWidth ?? 50;
		const hbPad = window.config?.healthBarPad ?? 5;
		const nameY = window.config?.nameY ?? 0;

		const width = hbWidth / 2 - hbPad / 2;
		const height = 14;

		window.Cow.playersManager.eachVisible(player => {
			if (!player || !player.alive) return;

			const yOffset = player.renderY + player.scale + nameY - 5;

			const primaryReload = player.reloads?.primary
				? Math.min(player.reloads.primary.count / player.reloads.primary.max, 1)
				: 0;

			const secondaryReload = player.reloads?.secondary
				? Math.min(player.reloads.secondary.count / player.reloads.secondary.max, 1)
				: 0;

			const barColor = player.isAlly ? "#8ecc51" : "#cc5151";

			ctx.save();

			ctx.fillStyle = "#3d3f42";
			ctx.fillRect(
				player.renderX - width * 1.19 - width - hbPad,
				yOffset - height / 2,
				2 * width + 2 * hbPad,
				height
			);

			ctx.fillStyle = barColor;
			ctx.fillRect(
				player.renderX - width * 1.19 - width,
				yOffset - height / 2 + hbPad,
				2 * width * primaryReload,
				height - 2 * hbPad
			);

			ctx.fillStyle = "#3d3f42";
			ctx.fillRect(
				player.renderX + width * 1.19 - width - hbPad,
				yOffset - height / 2,
				2 * width + 2 * hbPad,
				height
			);

			ctx.fillStyle = barColor;
			ctx.fillRect(
				player.renderX + width * 1.19 - width,
				yOffset - height / 2 + hbPad,
				2 * width * secondaryReload,
				height - 2 * hbPad
			);

			ctx.restore();
		});
	});
})();

//HealBarsBuildings
(function () {
	"use strict";

	function init() {
		if (!window.Cow) {
			setTimeout(init, 100);
			return;
		}

		const Cow = window.Cow;

		function drawHP(ctx, o) {
			const max = o.maxHealth || o.maxHP || 100;
			const cur = o.health || o.hp || max;
			if (cur >= max) return;

			const hp = cur / max;
			const r = 20;
			const w = 8;
			const a = hp * Math.PI * 2;

			ctx.save();
			ctx.translate(o.renderX || o.x, o.renderY || o.y);

			ctx.strokeStyle = "#2b0000";
			ctx.lineWidth = w;
			ctx.beginPath();
			ctx.arc(0, 0, r, 0, Math.PI * 2);
			ctx.stroke();

			let hpColor;
			if (hp > 0.6) hpColor = "#00aa00";
			else if (hp > 0.3) hpColor = "#ffaa00";
			else hpColor = "#ff0000";

			ctx.strokeStyle = hpColor;
			ctx.lineWidth = w - 2;
			ctx.lineCap = "round";
			ctx.beginPath();
			ctx.arc(0, 0, r, 0, a);
			ctx.stroke();

			if (hp < 0.3) {
				ctx.fillStyle = "#ffffff";
				ctx.font = "bold 10px Arial";
				ctx.textAlign = "center";
				ctx.textBaseline = "middle";
				ctx.fillText(Math.round(hp * 100) + "%", 0, 0);
			}

			ctx.restore();
		}

		function render() {
			if (!Cow.player) return;
			const ctx = Cow.renderer.context;

			Cow.objectsManager.eachVisible((o) => {
				if (
					(o.health == null && o.hp == null) ||
					(o.maxHealth == null && o.maxHP == null)
				) return;

				const isEnemy = o.ownerId && o.ownerId !== Cow.player.id;
				if (isEnemy || (o.health || o.hp) < (o.maxHealth || o.maxHP)) {
					drawHP(ctx, o);
				}
			});
		}

		if (Cow.addRender) {
			Cow.addRender("hp-circle-red", render);
		} else {
			(function loop() {
				render();
				requestAnimationFrame(loop);
			})();
		}
	}

	if (document.readyState === "complete") init();
	else window.addEventListener("load", init);
})();

//AutoVerifity
(function () {
    'use strict';

    let ws = null;
    let { msgpack } = window;
    let playerID = null;
    let myPlayer = {
        id: null, x: null, y: null, dir: null, object: null, weapon: null,
        clan: null, isLeader: null, maxXP: 300, XP: 0, age: 1,
        hat: null, accessory: null, isSkull: null, maxHealth: 100,
        health: 100
    };
    let players = [], enemy = [], nearestEnemy = {};
    let gameCanvas = document.getElementById("gameCanvas");
    let width = window.innerWidth;
    let height = window.innerHeight;
    let mouseX, mouseY;

    const sendPacket = (packet, ...data) => {
        if (ws && ws.readyState === WebSocket.OPEN) {
            ws.send(new Uint8Array(msgpack.encode([packet, data])));
        }
    };

    const updatePlayers = data => {
        players = [];
        for (let i = 0; i < data[1].length / 13; i++) {
            const playerInfo = data[1].slice(i * 13, i * 13 + 13);
            if (playerInfo[0] === myPlayer.id) {
                myPlayer.x = playerInfo[1];
                myPlayer.y = playerInfo[2];
                myPlayer.dir = playerInfo[3];
                myPlayer.object = playerInfo[4];
                myPlayer.weapon = playerInfo[5];
                myPlayer.clan = playerInfo[7];
                myPlayer.isLeader = playerInfo[8];
                myPlayer.hat = playerInfo[9];
                myPlayer.accessory = playerInfo[10];
                myPlayer.isSkull = playerInfo[11];
            } else {
                players.push({
                    id: playerInfo[0],
                    x: playerInfo[1],
                    y: playerInfo[2],
                    dir: playerInfo[3],
                    object: playerInfo[4],
                    weapon: playerInfo[5],
                    clan: playerInfo[7],
                    isLeader: playerInfo[8],
                    hat: playerInfo[9],
                    accessory: playerInfo[10]
                });
            }
        }
    };

    const updateHealth = (health, playerIDCheck) => {
        if (myPlayer.id === playerIDCheck) {
            myPlayer.health = health;
        }
    };

    const handleMessage = (message) => {
        const decoded = msgpack.decode(new Uint8Array(message.data));
        const data = Array.isArray(decoded) && decoded.length > 1 ? [decoded[0], ...decoded[1]] : decoded;
        if (!data) return;
        const type = data[0];
        if (type === "C" && myPlayer.id == null) {
            myPlayer.id = data[1];
            console.log("[Nurbo Mod] Player ID:", myPlayer.id);
        }
        if (type === "a") updatePlayers(data);
        if (type === "O") updateHealth(data[2], data[1]);
    };

    const socketFound = (sock) => {
        sock.addEventListener("message", handleMessage);
        if (gameCanvas) {
            gameCanvas.addEventListener("mousemove", ({ x, y }) => {
                mouseX = x;
                mouseY = y;
            });
        }
        window.addEventListener("resize", () => {
            width = window.innerWidth;
            height = window.innerHeight;
        });
    };

    WebSocket.prototype.oldSend = WebSocket.prototype.send;
    WebSocket.prototype.send = function (m) {
        if (!ws) {
            ws = this;
            document.websocket = this;
            socketFound(this);
            console.log("[Nurbo Mod] WebSocket intercepted");
        }
        this.oldSend(m);
    };

    const altchaCheck = setInterval(() => {
        let altcha = document.getElementById('altcha');
        let altchaBox = document.getElementById('altcha_checkbox');

        if (altcha && altchaBox) {
            altcha.style.display = 'none';
            altcha.style.opacity = '0';
            altcha.style.pointerEvents = 'none';
            altchaBox.checked = true;

            altchaBox.dispatchEvent(new Event('change', { bubbles: true }));
            altchaBox.dispatchEvent(new Event('click', { bubbles: true }));

            setTimeout(() => {
                if (!altchaBox.checked) {
                    altchaBox.checked = true;
                    altchaBox.click();
                }
            }, 500);

            clearInterval(altchaCheck);
            console.log("[Nurbo Mod] Altcha solved automatically");
        }

        const captchaElements = document.querySelectorAll('[class*="captcha"], [id*="Captcha"], [class*="verif"]');
        captchaElements.forEach(el => {
            if (el && el.style) {
                el.style.display = 'none';
                el.style.opacity = '0';
                el.style.pointerEvents = 'none';
            }
        });
    }, 300);

    const originalAlert = window.alert;
    window.alert = function(message) {
        console.log("[Nurbo Mod] Alert blocked:", message);
        if (typeof message === 'string' && (
            message.toLowerCase().includes('verify') ||
            message.toLowerCase().includes('captcha') ||
            message.toLowerCase().includes('robot') ||
            message.toLowerCase().includes('human')
        )) {
            return;
        }
        return originalAlert.apply(this, arguments);
    };
})();

//AutoReloadWeb
(function() {
    "use strict";

    function delay(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    async function refreshPage() {
        console.log("[Nurbo Mod] Auto-reloading page...");
        await delay(1200);
        window.onbeforeunload = null;
        location.reload();
    }

    function interceptProperty(target, propName, onSetCallback) {
        const hiddenKey = Symbol(propName);
        Object.defineProperty(target, propName, {
            get() {
                return this[hiddenKey];
            },
            set(value) {
                onSetCallback(this, hiddenKey, value);
            },
            configurable: true
        });
    }

    function wrapFunction(originalFunc, wrapper) {
        return new Proxy(originalFunc, {
            apply(target, thisArg, args) {
                return wrapper.call(thisArg, target, args);
            }
        });
    }

    interceptProperty(Object.prototype, "errorCallback", (obj, key, val) => {
        obj[key] = val;
        if (typeof val !== "function") return;
        obj[key] = wrapFunction(val, (target, args) => {
            console.log("[Nurbo Mod] errorCallback triggered, auto-reloading");
            window.alert = () => {};
            refreshPage();
            return target.apply(this, args);
        });
    });

    ["onclose", "onerror"].forEach(eventName => {
        const descriptor = Object.getOwnPropertyDescriptor(WebSocket.prototype, eventName);
        if (!descriptor || !descriptor.set) return;

        Object.defineProperty(WebSocket.prototype, eventName, {
            set(handler) {
                const wrappedHandler = wrapFunction(handler, (target, args) => {
                    console.log(`[Nurbo Mod] WebSocket ${eventName} triggered, auto-reloading`);
                    refreshPage();
                    return target.apply(this, args);
                });
                descriptor.set.call(this, wrappedHandler);
            },
            configurable: true
        });
    });

    window.addEventListener('error', function(e) {
        if (e.message && (
            e.message.includes('WebSocket') ||
            e.message.includes('connection') ||
            e.message.includes('network')
        )) {
            console.log("[Nurbo Mod] Page error detected, auto-reloading");
            setTimeout(refreshPage, 1000);
        }
    });

    window.addEventListener('unhandledrejection', function(e) {
        if (e.reason && typeof e.reason === 'string' && (
            e.reason.includes('WebSocket') ||
            e.reason.includes('network')
        )) {
            console.log("[Nurbo Mod] Unhandled promise rejection, auto-reloading");
            setTimeout(refreshPage, 1000);
        }
    });

    setInterval(() => {
        if (document.websocket && document.websocket.readyState !== WebSocket.OPEN) {
            console.log("[Nurbo Mod] WebSocket not open, checking...");
            setTimeout(() => {
                if (document.websocket && document.websocket.readyState !== WebSocket.OPEN) {
                    console.log("[Nurbo Mod] WebSocket still closed, reloading");
                    refreshPage();
                }
            }, 2000);
        }
    }, 10000);

})();
let multiboxAlts = [];
const mousePosition = {x: 0, y: 0};

const upgradeOptions = {};

let placingSpikes = false;
let placingTraps = false;
let repellingAlts = false;
let automill = false;

const updateAltsCounter = () => {
    document.getElementById('altsCounter').innerText = String(multiboxAlts.length);
};

class PowSolver {
    constructor() {
        console.log('PowSolver initialized');
    };

    createToken(json, solution) {
        return 'alt:' + btoa(JSON.stringify({
            algorithm: "SHA-256",
            challenge: json.challenge,
            number: solution,
            salt: json.salt,
            signature: json.signature || null,
            took: 15439
        }));
    };

    async getCaptcha() {
        const resp = await fetch('https://api.moomoo.io/verify');
        const json = await resp.json();
        return json;
    };

    async hash(string) {
        const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(string));
        return new Uint8Array(hash).toHex();
    };

    async solveCaptcha(json) {
        for (let i = 0; i < json.maxnumber; i++) {
            if (await this.hash(json.salt + i) == json.challenge) {
                return i;
            };
        };
    };

    async generateAltchaToken() {
        const json = await this.getCaptcha();
        const solution = await this.solveCaptcha(json);
        return this.createToken(json, solution);
    };
};

class Input {
    constructor(ws) {
        this.msgpack = msgpack;
        this.ws = ws;
    };

    sendMsg(data) {
        this.ws.send(this.msgpack.encode(data));
    };

    sendChatMessage(message) {
        this.sendMsg(['6', [message]]);
    };

    useItem(id) {
        this.sendMsg(['z', [id, null]]);
        this.sendMsg(['F', [1, null]]);
        this.sendMsg(['F', [0, null]]);
        this.sendMsg(['z', [document.ws.player.entity.weapon, true]]);
    };

    healPlayer(currentHealth) {
        let timeout = 115;
        if (currentHealth <= 60) {
            timeout = 1;
        };
        setTimeout(() => {
            this.useItem(0);
            this.useItem(1);
        }, timeout);
    };

    moveTowardsDirection(angle) {
        this.sendMsg(['9', [angle]]);
    };

    sendEnterWorld(name) {
        this.sendMsg(['M', [{
            name: name,
            moofoll: true,
            skin: 0
        }]]);
    };

    joinTribe(name) {
        this.sendMsg(['b', [name]]);
    };
};

class Player {
    constructor(ws) {
        this.ws = ws;
        this.input = new Input(this.ws);
        this.autoheal = true;
        this.entity = {
            id: null,
            health: 100,
            knownPlayers: [],
            position: {
                x: 0,
                y: 0
            },
            aimingYaw: 0,
            object: -1,
            weapon: 0,
            clan: null,
            isLeader: 0,
            hat: 0,
            accessory: 0
        };
        this.fullyUpgraded = true;

        this.ws.addEventListener('message', this.handleMessage.bind(this));
    };

    handleMessage(msg) {
        const data = msgpack.decode(msg.data);

        switch (data[0]) {
            case 'C':
                this.entity.id = data[1][0];
                break;
            case 'O':
                if (data[1][0] == this.entity.id) this.entity.health = data[1][1];
                if (data[1][0] == this.entity.id && this.autoheal && data[1][1] < 100) this.input.healPlayer(this.entity.health);
                break;
            case 'a':
                this.entity.knownPlayers = [];
                var playerInfos = data[1][0];
                for (let j = 0; j < playerInfos.length; j += 13) {
                    const playerInfo = playerInfos.slice(j, j + 13);
                    if (playerInfo[0] == this.entity.id) {
                        this.entity.position.x = playerInfo[1];
                        this.entity.position.y = playerInfo[2];
                        this.entity.aimingYaw = playerInfo[3];
                        this.entity.object = playerInfo[4];
                        this.entity.weapon = playerInfo[5];
                        this.entity.clan = playerInfo[7];
                        this.entity.isLeader = playerInfo[8];
                        this.entity.hat = playerInfo[9];
                        this.entity.accessory = playerInfo[10];
                    } else {
                        this.entity.knownPlayers.push({
                            id: playerInfo[0],
                            position: {
                                x: playerInfo[1],
                                y: playerInfo[2],
                            },
                            aimingYaw: playerInfo[3],
                            object: playerInfo[4],
                            weapon: playerInfo[5],
                            clan: playerInfo[7],
                            isLeader: playerInfo[8],
                            hat: playerInfo[9],
                            accessory: playerInfo[10]
                        });
                    };
                };
                break;
            case 'U':
                this.upgradeAge = ((data[1][0] + data[1][1]) - data[1][0]);
                if (data[1][0] == 0) {
                    this.fullyUpgraded = true;
                } else {
                    this.fullyUpgraded = false;
                };
                break;
        };
    };
};

class Bot {
    constructor(serverUrl) {
        this.powSolver = new PowSolver();
        // Генерация имени бота: Hypbo- + случайное число от 1000 до 9999
        this.name = 'Hypbo-' + Math.floor(Math.random() * 9000 + 1000);
        this.age = 1;

        this.powSolver.generateAltchaToken().then((token) => {
            this.ws = new WebSocket(document.ws.url.split('?token=')[0] + `?token=${token}`);
            this.ws.binaryType = 'arraybuffer';
            this.ws.player = new Player(this.ws);
            this.ws.addEventListener('message', this.handleMessage.bind(this));

            setInterval(() => {
                // Отправляем сообщение в чат только с возрастом
                this.ws.player.input.sendChatMessage('age: ' + this.age);

                if (!this.ws.player.fullyUpgraded) {
                    try {
                        this.ws.player.input.sendMsg(['H', [upgradeOptions[this.ws.player.upgradeAge]]]);
                    } catch(e) {
                        ;
                    };
                };
            }, 1000);
        });
    };

    handleMessage(msg) {
        const data = this.ws.player.input.msgpack.decode(msg.data);
        switch (data[0]) {
            case 'io-init':
                multiboxAlts.push(this.ws);
                this.ws.player.input.sendEnterWorld(this.name);
                setInterval(() => {
                    this.ws.player.input.sendEnterWorld(this.name);
                    this.ws.player.input.joinTribe(document.ws.player.entity.clan);
                }, 1000);
                updateAltsCounter();
                console.log(multiboxAlts.length);
                break;
            case 'a':
                var mouseXWorld = (document.ws.player.entity.position.x - this.ws.player.entity.position.x) + (mousePosition.x - (window.innerWidth / 2)) * (1+(1/3));
                var mouseYWorld = (document.ws.player.entity.position.y - this.ws.player.entity.position.y) + (mousePosition.y - (window.innerHeight / 2)) * (1+(1/3));
                var dirToMove = Math.atan2(mouseYWorld, mouseXWorld);
                this.ws.player.input.sendMsg(['D', [dirToMove]]);
                if (repellingAlts) {
                    this.ws.player.input.moveTowardsDirection(dirToMove - 2.35619);
                } else {
                    this.ws.player.input.moveTowardsDirection(dirToMove);
                };
                break;
            case 'U':
                this.age = (data[1][0] + data[1][1]) - 1;
        };
    };
};

const init = () => {
    document.getElementById('promoImgHolder').remove();
    for (let i = 0; i < document.getElementsByClassName('adsbygoogle').length; i++) {
        document.getElementsByClassName('adsbygoogle')[0].remove();
    };
    document.getElementById('gameName').innerText = 'Hypbo mod'
    document.getElementById('gameName').style = 'color: white';
    document.getElementById('mainMenu').style = 'background-color: #333';
    document.getElementById('diedText').innerText = 'You Died';
    document.getElementById('diedText').style = 'color: #f00; background-color: #444;';

    const altCounter = document.createElement('h2');
    altCounter.style = 'text-align: center;color:#444; font-size: 10px; position: fixed; top: 5px; left: 50%; transform: translateX(-50%);';
    altCounter.innerHTML = 'alts: <span id="altsCounter">0</span>';
    document.getElementById('gameUI').appendChild(altCounter);

    document.getElementById('touch-controls-fullscreen').addEventListener('mousemove', (e) => {
        mousePosition.x = e.clientX;
        mousePosition.y = e.clientY;
    });

    const originalWebSocket = WebSocket;

    const wsInterceptor = {
        construct(target, args) {
            const ws = new originalWebSocket(...args);
            document.ws = ws;
            console.log('captured ws');
            window.WebSocket = originalWebSocket;

            document.ws.player = new Player(document.ws);
            window.addEventListener('keyup', (e) => {
                if (e.target.tagName === 'INPUT') {
                    return;
                };

                if (e.key === 'l') {
                    new Bot('Hypbo-' + Math.floor(Math.random() * 9000 + 1000))
                };

                if (e.key === ',') {
                    multiboxAlts.forEach((sock) => {
                        sock.close();
                    })
                    multiboxAlts = [];
                    updateAltsCounter();
                };

                if (e.key === 'm') {
                    automill = !automill;
                };
            });

            setInterval(() => {
                if (automill) {
                    if (upgradeOptions[5] == 27) {
                        if (upgradeOptions[8] == 28) {
                            document.ws.player.input.useItem(12);
                        } else {
                            document.ws.player.input.useItem(11);
                        };
                    } else {
                        document.ws.player.input.useItem(10);
                    };
                };
            }, 50);

            let originalSend = document.ws.send.bind(document.ws);
            document.ws.send = (msg) => {
                if (msgpack.decode(msg)[0] === 'F' || msgpack.decode(msg)[0] === 'z' || msgpack.decode(msg)[0] === 'c') {
                    multiboxAlts.forEach((sock) => {
                        sock.send(msg);
                    });
                };

                if (msgpack.decode(msg)[0] === 'H') {
                    upgradeOptions[document.ws.player.upgradeAge] = msgpack.decode(msg)[1][0];
                };

                console.log(msgpack.decode(msg));
                originalSend(msg);
            };

            return ws;
        }
    };

    window.WebSocket = new Proxy(originalWebSocket, wsInterceptor);
};

let waitForGameName = setInterval(() => {
    if (document.getElementById('gameName')) {
        clearInterval(waitForGameName);
        return init();
    };
}, 100);