x-RedDragon Client

R=InstaNormal | T=ReverseInsta | Y=BoostInsta | G=BoostSpike | B=4Traps/Boost | ,=AntiTrap | M=AutoMills | F=Trap/BoostPad | V=Spike | N=Mill | H=Teleport/Turret | AutoBiomeHat | Esc=MenuGoldbot/Music | ClickRight=FastBreak | AutoHeal | AntiInsta and visual mods.

19.09.2025 itibariyledir. En son verisyonu görün.

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name         x-RedDragon Client
// @namespace    http://youtube.com/@x-RedDragonYT
// @version      1.4.3
// @description  R=InstaNormal | T=ReverseInsta | Y=BoostInsta | G=BoostSpike | B=4Traps/Boost | ,=AntiTrap | M=AutoMills | F=Trap/BoostPad | V=Spike | N=Mill | H=Teleport/Turret | AutoBiomeHat | Esc=MenuGoldbot/Music | ClickRight=FastBreak | AutoHeal | AntiInsta and visual mods.
// @icon         https://i.imgur.com/AFJt4iq.png
// @author       x-RedDragonYT
// @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
    };
    let myPlayeroldx, myPlayeroldy;
    let automillx = 10, automilly = 10;
    let walkmillhaha = false;
    let healToggle = true;
    const keysPressed = {};
    const placementIntervals = {};
    let gInterval = null;

    const ID_BullHelmet = 7;
    const ID_TurretGear = 53;
    const ID_SoldierHelmet = 6;
    const ID_TankGear = 40;

    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 = true;
    let primary = null;

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

    // === INSTAKILL NORMAL ===
    function sequenceInstaKill() {
    storeEquip(0, 1);
    setTimeout(() => {
        autoaim = true;
        const primary = myPlayer.weapon;
        const secondary = getSecondaryWeaponIndex();


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


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


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


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

            }, 170);

        }, 120);

    }, 120);
}

    // === INSTAKILL REVERSO ===
    function reverseInstaKill() {
        storeEquip(0, 1);
        setTimeout(() => {
            autoaim = true;
            const primary = myPlayer.weapon;
            const secondary = getSecondaryWeaponIndex();

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

            setTimeout(() => {
                doNewSend(["z", [primary, true]]);
                doNewSend(["c", [0, ID_BullHelmet, 0]]);
                doNewSend(["F", [1]]);
                setTimeout(() => doNewSend(["F", [0]]), 25);
            }, 90);

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

                setTimeout(() => storeEquip(11, 1), 200);
            }, 500);
        }, 120);
    }

    // === boostTick ===
    function boostTick() {
    storeEquip(0, 1);
    place(boostType);

    setTimeout(() => {
        const primary = myPlayer.weapon;
        const secondary = getSecondaryWeaponIndex();


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


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


            if (nearestEnemy) {
                place(spikeType, nearestEnemyAngle);
            } else {
                place(foodType);
            }

            doNewSend(["F", [1]]);
            setTimeout(() => doNewSend(["F", [0]]), 25);


            setTimeout(() => {
                doNewSend(["c", [0, ID_SoldierHelmet, 0]]);
                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);
                    }

                    doNewSend(["z", [primary, true]]);
                    doNewSend(["z", [secondary, true]]);
                }, 170);
            }, 170);

        }, 110);
    }, 100);
}

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

    function performGSequence() {
        const dir = myPlayer.dir;
        place(spikeType, dir + Math.PI / 2);
        place(spikeType, dir - Math.PI / 2);
        place(boostType, dir);
    }
    function performGReleaseSequence() {
        const dir = myPlayer.dir;
        place(spikeType, dir - Math.PI / 4);
        place(spikeType, dir + Math.PI / 4);
    }
    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);
    }

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

        if (k === 'r') sequenceInstaKill();
        if (k === 't') reverseInstaKill();
        if (k === 'y') boostTick();
        if (k === 'm') {
            walkmillhaha = !walkmillhaha;
            doNewSend(["6", ["Mills : " + walkmillhaha]]);
        }
        if (k === 'f') startPlacingStructure(k, boostType);
        if (k === 'v') startPlacingStructure(k, spikeType);
        if (k === 'n') startPlacingStructure(k, windmillType);
        if (k === 'h') startPlacingStructure(k, turretType);
        if (k === 'g' && !gInterval) {
            performGSequence();
            gInterval = setInterval(performGSequence, 80);
        }
        if (k === 'b') performBPlacement();
    });

    document.addEventListener("keyup", e => {
        const k = e.key.toLowerCase();
        keysPressed[k] = false;
        stopPlacingStructure(k);
        if (k === 'g' && gInterval) {
            clearInterval(gInterval);
            gInterval = null;
            setTimeout(performGReleaseSequence, 80);
        }
    });

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

            if (data[0] === "O" && data[1] === myPlayer.id) {
                let damage = HP - data[2];
                HP = data[2];
                if (damage <= -1) {
                    damageTimes++;
                    if (!lastDamageTick) return;
                    let healTime = gameTick - lastDamageTick;
                    lastDamageTick = 0;
                    if (healTime <= 1) {
                        shame = shame++;
                    } else {
                        shame = Math.max(0, shame - 2);
                    }
                } else {
                    lastDamageTick = gameTick;
                }
            }

            // Normal Heal
            if (data[2] < 100 && data[2] > 0 && healToggle == true) {
                console.log("normal healing");
                setTimeout(() => {
                    place(foodType);
                    place(foodType);
                    doNewSend(["c", [0, 6, 0]]);
                }, 115);
            }

            // Anti Insta
            if (data[2] < 48 && data[2] > 0 && anti == true && (nearestEnemy[5] == 5 || nearestEnemy[5] == 3)) {
                healToggle = false;
                console.log("no soldier anti - polearm");
                doNewSend(["c", [0, 22, 0]]);
                place(foodType);
                setTimeout(() => {
                    place(foodType);
                    doNewSend(["c", [0, 6, 0]]);
                    healToggle = true;
                }, 200);
                setTimeout(() => {
                    doNewSend(["c", [0, 7, 0]]);
                }, 700);
                setTimeout(() => {
                    doNewSend(["c", [0, 6, 0]]);
                }, 1900);
            }

            // Anti Insta
            if (data[2] < 62 && data[2] > 41 && anti == true && (nearestEnemy[5] == 5 || nearestEnemy[5] == 3)) {
                healToggle = false;
                console.log("anti insta - polearm");
                doNewSend(["c", [0, 22, 0]]);
                place(foodType);
                setTimeout(() => {
                    place(foodType);
                    doNewSend(["c", [0, 6, 0]]);
                    healToggle = true;
                }, 200);
                setTimeout(() => {
                    doNewSend(["c", [0, 7, 0]]);
                }, 700);
                setTimeout(() => {
                    doNewSend(["c", [0, 6, 0]]);
                }, 1900);
            }

            // Anti Bullspam
            if (data[2] < 56 && data[2] > 50) {
                healToggle = false;
                console.log("anti bullspam");
                setTimeout(() => {
                    place(foodType);
                    place(foodType);
                    doNewSend(["c", [0, 6, 0]]);
                    healToggle = true;
                }, 140);
            }

            // Hitback
            if (data[2] < 41 && data[2] > 0 && hitBack == true && nearestEnemy[5] == 4) {
                console.log("hitbacking");
                healToggle = false;
                autoaim = true;
                setTimeout(() => {
                    place(foodType);
                    place(foodType);
                }, 133);
                place(spikeType, nearestEnemyAngle);
                doNewSend(["n", [1]]);
                doNewSend(["c", [0, 7, 0]]);
                doNewSend(["z", [primary, true]]);
                setTimeout(() => {
                    doNewSend(["c", [0, 53, 0]]);
                    doNewSend(["n", [0]]);
                    healToggle = true;
                }, 150);
                setTimeout(() => {
                    doNewSend(["c", [0, 11, 0]]);
                    autoaim = false;
                }, 300);
            }
        }

    }

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

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

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

// función auxiliar para verificar y equipar solo si es necesario
function ensureCorrectWeapon() {
    const primary = myPlayer.weapon;
    const secondary = getSecondaryWeaponIndex();

    // Determinar qué arma debería estar equipada
    let correctWeapon = (secondary === 10) ? secondary : primary;

    // Si no tengo equipada la correcta → la equipo
    if (myPlayer.weapon !== correctWeapon) {
        doNewSend(["z", [correctWeapon, true]]);
    }
}

function startAttackLoop() {
    if (rightClickAttackInterval) return;

    rightClickAttackInterval = setInterval(() => {
        // Asegurar arma correcta solo si está mal equipada
        ensureCorrectWeapon();

        // Golpe con engranajes y ataque
        doNewSend(["c", [0, ID_TankGear, 0]]);
        doNewSend(["F", [1]]);
        setTimeout(() => doNewSend(["F", [0]]), 10);

    }, 60);
}

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

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

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

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

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

// --- Hook para corrección instantánea cuando cambias de arma ---
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() {
    const ID_SoldierHelmet = 6;
    const ID_SnowHelmet = 15;
    const ID_SandHelmet = 31;
    const ID_GrassHelmet = 12;

    let normalHat = ID_GrassHelmet;
    let currentHat = null;
    let overridePause = false;
    let resumeTimeout = null;
    const movementKeys = new Set();
    const overrideKeys = new Set(["r", "t", " "]);

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

           
            let accessoryId = null;
            if (id === ID_SoldierHelmet) {
                accessoryId = 0; 
            } else if ([ID_SnowHelmet, ID_SandHelmet, ID_GrassHelmet].includes(id)) {
                accessoryId = 11;
            }

           
            if (accessoryId !== null) {
                [40, 80, 120].forEach(delay => {
                    setTimeout(() => {
                        storeEquip(accessoryId, 1);
                    }, delay);
                });
            }
        }
    }

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

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

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

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

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

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

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

    console.log("✅ AutoBiomeHatController V3 activado (con accesorios asegurados).");
}

autoBiomeHatController();

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

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

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) { // trap enemiga
            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, ID_SoldierHelmet, 0]]), 100);
    }

    oldHandleMessage(m);
};

// función auxiliar para verificar y equipar solo si es necesario
function ensureCorrectWeapon() {
    const primary = myPlayer.weapon;
    const secondary = getSecondaryWeaponIndex();

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

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

// --- Hook seguro para storeEquip y equipWeapon ---
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 (autoTrapBreaker && intrap) ensureCorrectWeapon();
            return result;
        };

        const oldEquipWeapon = window.equipWeapon;
        window.equipWeapon = function (id) {
            const result = oldEquipWeapon.apply(this, arguments);
            if (autoTrapBreaker && intrap) ensureCorrectWeapon();
            return result;
        };
    } else {
        setTimeout(hookEquipFunctions, 100); // reintentar hasta que existan
    }
}
hookEquipFunctions();

// --- Loop de trap breaker ---
setInterval(() => {
    if (!autoTrapBreaker || !intrap) return;
    if (!ws || ws.readyState !== WebSocket.OPEN) return;

    let oppositeAngle = trapAngle + Math.PI;

    place(spikeType, oppositeAngle);

    ensureCorrectWeapon();

    doNewSend(["D", [trapAngle]]);
    doNewSend(["c", [0, ID_TankGear, 0]]);
    doNewSend(["F", [1, trapAngle]]);
    setTimeout(() => doNewSend(["F", [0, trapAngle]]), 15);

}, 300);
})();

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

    const GRID_ENABLED = false;

    function waitForConfig(callback) {
        if (window.config && window.config.maxScreenWidth && window.config.maxScreenHeight) {
            callback();
        } else {
            setTimeout(() => waitForConfig(callback), 100);
        }
    }

    waitForConfig(() => {
        const maxWidth = window.config.maxScreenWidth;
        const maxHeight = window.config.maxScreenHeight;

        const CELL_SIZE = 50;
        const tolerance = 1.5;

        function isGridLinePair(x1, y1, x2, y2) {
            const isStraight = (x1 === x2 || y1 === y2);
            const isNearGrid = (coord) =>
                (coord % CELL_SIZE <= tolerance) || (CELL_SIZE - (coord % CELL_SIZE) <= tolerance);
            return isStraight && (isNearGrid(x1) || isNearGrid(y1));
        }

        let lastMoveTo = null;

        const originalMoveTo = CanvasRenderingContext2D.prototype.moveTo;
        const originalLineTo = CanvasRenderingContext2D.prototype.lineTo;

        CanvasRenderingContext2D.prototype.moveTo = function(x, y) {
            lastMoveTo = [x, y];
            return originalMoveTo.call(this, x, y);
        };

        CanvasRenderingContext2D.prototype.lineTo = function(x, y) {
            if (!GRID_ENABLED && lastMoveTo) {
                const [x0, y0] = lastMoveTo;
                if (
                    x >= 0 && x <= maxWidth &&
                    y >= 0 && y <= maxHeight &&
                    isGridLinePair(x0, y0, x, y)
                ) {
                    return this;
                }
            }
            return originalLineTo.call(this, x, y);
        };
    });
})();

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

    console.log("x-RedDragon Client Visuals Loaded");

    const config = window.config || {};
    config.skinColors = [
        "#bf8f54", "#4c4c4c", "#896c4b",
        "#fadadc", "#ececec", "#c37373",
        "#000000", "#ecaff7", "#738cc3",
        "#8bc373", "#91b2db"
    ];
    window.config = config;

    const css = `
    body {
        background: linear-gradient(135deg, rgba(15, 15, 15, 0.2), rgba(28, 28, 28, 0.2));
        font-family: 'Orbitron', sans-serif;
        color: white;
    }

    #mainMenu {
        background-color: black !important;
        background-size: cover;
        background-position: center;
        background-repeat: no-repeat;
    }

    .menuButton {
        background-color: rgba(0, 0, 0, 0.6);
        border: 2px solid #ff3333;
        color: #ffffff;
        font-family: 'Orbitron', sans-serif;
        font-size: 18px;
        font-weight: bold;
        padding: 12px 28px;
        border-radius: 14px;
        cursor: pointer;
        box-shadow: 0 0 15px #ff0000;
        transition: all 0.4s ease-in-out;
        text-shadow: 0 0 6px #ff0000;
    }

    .menuButton.epic-hover:hover {
        background: linear-gradient(135deg, #ff1111, #ff0000, #cc0000);
        background-size: 300% 300%;
        animation: redPulse 3s infinite ease-in-out;
        box-shadow: 0 0 25px #ff0000, 0 0 50px #ff1111;
        color: #fff;
        transform: scale(1.1);
        border: 3px solid #ffffff;
    }

    @keyframes redPulse {
        0% { background-position: 0% 50%; }
        50% { background-position: 100% 50%; }
        100% { background-position: 0% 50%; }
    }

    #gameName {
        font-size: 80px !important;
        font-weight: bold;
        color: #ff2222 !important;
        text-shadow: 0 0 12px #ff0000, 0 0 30px #ff1111;
        animation: shimmer 3s infinite;
        font-family: 'Courier New', monospace !important;
        position: relative;
        top: -50px;
        text-align: center;
        transition: all 0.5s ease;
    }

    @keyframes shimmer {
        0% { text-shadow: 0 0 12px #ff0000, 0 0 30px #ff1111; }
        50% { text-shadow: 0 0 20px #ff3333, 0 0 40px #ff0000; }
        100% { text-shadow: 0 0 12px #ff0000, 0 0 30px #ff1111; }
    }

    #gameName::after {
        content: "𝕩-ℝ𝕖𝕕𝔻𝕣𝕒𝕘𝕠𝕟 ℂ𝕝𝕚𝕖𝕟𝕥";
        display: block;
        font-size: 1.1em;
        color: #ff4444;
        text-shadow: 0 0 25px #ff1111, 0 0 45px #ff0000;
        animation: glowtext 2s infinite alternate;
        position: relative;
        top: 10px;
        text-align: center;
    }

    @keyframes glowtext {
        0% { opacity: 1; }
        100% { opacity: 0.7; }
    }

    #loadingScreen {
        background: rgba(0, 0, 0, 0.2) !important;
        box-shadow: none !important;
        border: none !important;
    }

    #loadingScreen::before {
        content: "Cargando x-RedDragon Client...";
        font-size: 28px;
        color: #ff2222;
        text-shadow: 0 0 12px #ff0000;
        margin-bottom: 20px;
        animation: pulseText 2s infinite;
    }

    @keyframes pulseText {
        0% { opacity: 1; transform: scale(1); }
        50% { opacity: 0.8; transform: scale(1.05); }
        100% { opacity: 1; transform: scale(1); }
    }

    .menuCard, #bottomText, #storeHolder, #youtuberBtn, #adCard, .setNameContainer, .newsHolder {
        background-color: rgba(20, 20, 20, 0.2);
        padding: 20px;
        border: 2px solid #ff3333;
        box-shadow: 0 0 25px rgba(255, 0, 0, 0.8), 0 0 35px rgba(255, 50, 50, 0.6);
        color: #fff !important;
        animation: borderGlow 4s linear infinite;
        text-align: center;
    }

    @keyframes borderGlow {
        0% { box-shadow: 0 0 12px #ff0000; }
        50% { box-shadow: 0 0 25px #ff3333, 0 0 35px #ff1111; }
        100% { box-shadow: 0 0 12px #ff0000; }
    }

    #gameUI .joinAlBtn, a {
        animation: 5s infinite linear both normal redRainbow;
    }

    @keyframes redRainbow {
        0% { filter: brightness(1) hue-rotate(0deg); }
        100% { filter: brightness(1.2) hue-rotate(360deg); }
    }

    .resourceDisplay, #killCounter {
        width: 120px;
        margin: 0 auto;
        border: 3px solid #ff2222;
        border-radius: 12px;
        background-color: rgba(50, 0, 0, 0.3);
        color: #fff;
        padding: 8px;
        text-align: center;
        font-size: 14px;
        box-shadow: 0 0 10px #ff0000;
    }

    .uiElement {
        border: 2px solid #ff4444;
        background-color: rgba(40, 0, 0, 0.25);
        padding: 10px;
        color: #fff;
        font-size: 14px;
        text-align: center;
        box-shadow: 0 0 10px #ff1111;
    }

    .actionBarItem {
        border: 3px solid #ff4444;
        border-radius: 50%;
        width: 65px;
        height: 65px;
        background-position: center;
        background-size: 55px 55px;
        background-color: rgba(255, 0, 0, 0.2);
        box-shadow: 0 0 15px #ff0000;
        transition: transform 0.2s ease-in-out;
    }

    .actionBarItem:hover {
        transform: scale(1.1);
        box-shadow: 0 0 18px #ff6666;
        background-color: rgba(255, 70, 70, 0.35);
    }

    #itemInfoHolder {
        position: absolute;
        top: 25px;
        left: 50%;
        transform: translateX(-50%);
        width: 350px;
        background-color: rgba(0, 0, 0, 0.3);
        border: 2px solid #ff3333;
        border-radius: 12px;
        color: white;
        padding: 10px;
        font-size: 14px;
        text-align: center;
        box-shadow: 0 0 15px #ff0000;
    }

    ::-webkit-scrollbar {
        width: 12px;
    }

    ::-webkit-scrollbar-track {
        background: rgba(0,0,0,0.2);
        margin-top: 10px;
        margin-bottom: 10px;
    }

    ::-webkit-scrollbar-thumb {
        background: #ff3333;
        border-radius: 0px;
        box-shadow: 0 0 12px #ff3333;
    }
    `;

    const style = document.createElement('style');
    style.innerText = css;
    document.head.appendChild(style);

    const observer = new MutationObserver(() => {
        const gameName = document.getElementById('gameName');
        if (gameName && gameName.innerText !== '𝕩-ℝ𝕖𝕕𝔻𝕣𝕒𝕘𝕠𝕟 ℂ𝕝𝕚𝕖𝕟𝕥') {
            gameName.innerText = '';
        }
    });

    observer.observe(document.body, { childList: true, subtree: true });

    console.log("x-RedDragon Client Full Customization Applied.");

    const waitForMap = setInterval(() => {
        const map = document.getElementById("mapDisplay");
        if (map) {
            map.style.backgroundImage = "url('http://i.imgur.com/Qllo1mA.png')";
            map.style.backgroundSize = "cover";
            map.style.border = "3px solid #ff3333";
            map.style.boxShadow = "0 0 15px #ff0000";
            map.style.borderRadius = "8px";
            clearInterval(waitForMap);
        }
    }, 1);

    document.title = "𝕩-ℝ𝕖𝕕𝔻𝕣𝕒𝕘𝕠𝕟 ℂ𝕝𝕚𝕖𝕟𝕥";


    const oldIcons = document.querySelectorAll("link[rel*='icon']");
    oldIcons.forEach(icon => icon.remove());


    const newFavicon = document.createElement("link");
    newFavicon.rel = "icon";
    newFavicon.type = "image/png";
    newFavicon.href = "https://i.imgur.com/vXgDJSp.png";
    document.head.appendChild(newFavicon);

    let frameCount = 0;
    let fps = 0;
    let ping = 0;
    let lastLoop = performance.now();
    let pingTimes = [];


    function updatePing() {
        const startTime = performance.now();
        fetch(window.location.href, { method: 'HEAD', cache: "no-store" })
            .then(() => {
                const endTime = performance.now();
                const latency = Math.round(endTime - startTime);
                pingTimes.push(latency);
                if (pingTimes.length > 10) pingTimes.shift();
                ping = Math.round(pingTimes.reduce((a, b) => a + b, 0) / pingTimes.length);
            })
            .catch(() => {
                ping = 0;
            });

        setTimeout(updatePing, 1000);
    }
    updatePing();


    function updateFPS() {
        const now = performance.now();
        frameCount++;
        if (now - lastLoop >= 1000) {
            fps = Math.round(frameCount / ((now - lastLoop) / 1000));
            frameCount = 0;
            lastLoop = now;
        }
        requestAnimationFrame(updateFPS);
    }
    updateFPS();


    const statsContainer = document.createElement('div');
    statsContainer.id = 'fpsPingDisplay';
    Object.assign(statsContainer.style, {
        position: 'fixed',
        top: '12px',
        left: '50%',
        transform: 'translateX(-50%)',
        fontSize: '22px',
        fontFamily: "'Orbitron', sans-serif",
        color: '#FFFFFF',
        textShadow: '0 0 3px #000000, 1px 1px 0 #000, -1px -1px 0 #000',
        background: 'none',
        padding: '0',
        borderRadius: '0',
        border: 'none',
        boxShadow: 'none',
        zIndex: '0',
        pointerEvents: 'none'
    });
    document.body.appendChild(statsContainer);


    function updateStatsDisplay() {
        statsContainer.textContent = `FPS: ${fps} | Ping: ${ping}ms`;
        setTimeout(updateStatsDisplay, 500);
    }
    updateStatsDisplay();


    window.getStats = function () {
        return { fps, ping };
    };
})();

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

    let hue = 0;
    function changeStyle() {
        const ageBarBody = document.getElementById("ageBarBody");
        if (ageBarBody) {
            hue = (hue + 2) % 360;
            const rgbColor = `hsl(${hue}, 100%, 50%)`;
            ageBarBody.style.backgroundColor = rgbColor;
            ageBarBody.style.border = `2px solid ${rgbColor}`;
            ageBarBody.style.transform = "translateY(-2px)";
        }
    }
    setInterval(changeStyle, 100);

    let turretLastClickTime = null;
    let turretReady = true;

    window.Cow.setCodec(msgpack);
    CanvasRenderingContext2D.prototype._roundRect = CanvasRenderingContext2D.prototype.roundRect;

    window.addEventListener("mousedown", (e) => {
        if (e.button === 1 && turretReady) {
            turretLastClickTime = Date.now();
            turretReady = false;
        }
    });

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

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

            const width = window.config.healthBarWidth / 2 - window.config.healthBarPad / 2;
            const yOffset = player.renderY + player.scale + window.config.nameY - 5;
            const primaryReload = Math.min(Math.max(player.reloads.primary.count / player.reloads.primary.max, 0), 1);
            const secondaryReload = Math.min(Math.max(player.reloads.secondary.count / player.reloads.secondary.max, 0), 1);
            const pad = window.config.healthBarPad;
            const height = 17;
            const radius = 8;

            ctx.save();
            ctx.fillStyle = "#3d3f42";
            ctx.translate(player.renderX - width * 1.19, yOffset);
            ctx.beginPath();
            ctx._roundRect(-width - pad, -8.5, 2 * width + 2 * pad, height, radius);
            ctx.fill();
            ctx.restore();

            ctx.save();
            ctx.fillStyle = player.isAlly ? "#8ecc51" : "#cc5151";
            ctx.translate(player.renderX - width * 1.19, yOffset);
            ctx.beginPath();
            ctx._roundRect(-width, -8.5 + pad, 2 * width * primaryReload, height - 2 * pad, radius - 1);
            ctx.fill();
            ctx.restore();

            ctx.save();
            ctx.fillStyle = "#3d3f42";
            ctx.translate(player.renderX + width * 1.19, yOffset);
            ctx.beginPath();
            ctx._roundRect(-width - pad, -8.5, 2 * width + 2 * pad, height, radius);
            ctx.fill();
            ctx.restore();

            ctx.save();
            ctx.fillStyle = player.isAlly ? "#8ecc51" : "#cc5151";
            ctx.translate(player.renderX + width * 1.19, yOffset);
            ctx.beginPath();
            ctx._roundRect(-width, -8.5 + pad, 2 * width * secondaryReload, height - 2 * pad, radius - 1);
            ctx.fill();
            ctx.restore();

            const hpCurrent = Math.floor(player.health);
            const hpMax = Math.floor(player.maxHealth || 100);
            const hpText = `HP: ${hpCurrent}/${hpMax}`;

            ctx.save();
            ctx.font = "bold 20px GameFont";
            ctx.textAlign = "center";
            ctx.lineWidth = 3;
            ctx.strokeStyle = "black";
            ctx.fillStyle = "white";
            const textX = player.renderX;
            const textY = yOffset + 32;
            ctx.strokeText(hpText, textX, textY);
            ctx.fillText(hpText, textX, textY);
            ctx.restore();
        });
    });
})();

//HealBarsBuildings
// @require      https://update.greasyfork.org/scripts/480301/1283571/CowJS.js
// @require      https://update.greasyfork.org/scripts/480303/1282926/MooUI.js

(function () {
    "use strict";

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

        const { Cow, CowUtils } = window;
        const settings = {
            "health-bars": true,
            "circle-bars": false,
            "in-look-dir": false,
            "friendly-color": "#56e319",
            "enemy-color": "#ff3333",
            "hit-counter": true
        };

        function isOwnBuilding(object) {
            if (object && Cow.player) {
                if (object.group !== undefined && Cow.player.group !== undefined) {
                    return object.group === Cow.player.group;
                }
                if (object.owner && Cow.player.sid) {
                    return object.owner.sid === Cow.player.sid;
                }
                if (object.team !== undefined && Cow.player.team !== undefined) {
                    return object.team === Cow.player.team;
                }
            }
            return false;
        }

        function drawHealthBar(context, object) {
            const healthBarWidth = 50;
            const healthBarPad = 5;
            const width = (window.config && window.config.healthBarWidth ? window.config.healthBarWidth / 2 : healthBarWidth / 2) -
                         (window.config && window.config.healthBarPad ? window.config.healthBarPad / 2 : healthBarPad / 2);
            const height = 17;
            const radius = 8;
            const barColor = isOwnBuilding(object) ? settings["friendly-color"] : settings["enemy-color"];

            context.save();
            context.translate(object.renderX || object.x, object.renderY || object.y);
            context.fillStyle = "#3d3f42";
            if (context.roundRect) {
                context.roundRect(-width - healthBarPad, -height / 2, 2 * width + 2 * healthBarPad, height, radius);
            } else {
                context.beginPath();
                context.moveTo(-width - healthBarPad + radius, -height / 2);
                context.arcTo(-width - healthBarPad + 2 * width + 2 * healthBarPad, -height / 2, -width - healthBarPad + 2 * width + 2 * healthBarPad, -height / 2 + height, radius);
                context.arcTo(-width - healthBarPad + 2 * width + 2 * healthBarPad, -height / 2 + height, -width - healthBarPad, -height / 2 + height, radius);
                context.arcTo(-width - healthBarPad, -height / 2 + height, -width - healthBarPad, -height / 2, radius);
                context.arcTo(-width - healthBarPad, -height / 2, -width - healthBarPad + radius, -height / 2, radius);
                context.closePath();
            }
            context.fill();

            context.fillStyle = barColor;
            const healthRatio = (object.health || object.hp || 100) / (object.maxHealth || object.maxHP || 100);
            if (context.roundRect) {
                context.roundRect(-width, -height / 2 + healthBarPad, 2 * width * healthRatio, height - 2 * healthBarPad, radius - 1);
            } else {
                context.beginPath();
                context.moveTo(-width + (radius - 1), -height / 2 + healthBarPad);
                context.arcTo(-width + 2 * width * healthRatio, -height / 2 + healthBarPad, -width + 2 * width * healthRatio, -height / 2 + height - 2 * healthBarPad, radius - 1);
                context.arcTo(-width + 2 * width * healthRatio, -height / 2 + height - 2 * healthBarPad, -width, -height / 2 + height - 2 * healthBarPad, radius - 1);
                context.arcTo(-width, -height / 2 + height - 2 * healthBarPad, -width, -height / 2 + healthBarPad, radius - 1);
                context.arcTo(-width, -height / 2 + healthBarPad, -width + (radius - 1), -height / 2 + healthBarPad, radius - 1);
                context.closePath();
            }
            context.fill();
            context.restore();
        }

        function drawHitCounter(context, object) {
            if (!Cow.player || !Cow.player.weapon) return;
            try {
                const damage = Cow.player.weapon.dmg * (Cow.items.variants[Cow.player.weaponVariant]?.val || 1);
                const damageAmount = damage * (Cow.player.weapon.sDmg || 1) * (Cow.player.skin?.id === 40 ? 3.3 : 1);
                const objectHealth = object.health || object.hp || 100;
                const hits = Math.ceil(objectHealth / damageAmount);
                const offsetY = 22;

                context.save();
                context.font = `18px Hammersmith One`;
                context.fillStyle = "#fff";
                context.textBaseline = "middle";
                context.textAlign = "center";
                context.lineWidth = 8;
                context.lineJoin = "round";
                context.translate(object.renderX || object.x, object.renderY || object.y);
                context.strokeText(hits, 0, offsetY);
                context.fillText(hits, 0, offsetY);
                context.restore();
            } catch (e) {}
        }

        function renderHealthBars() {
            if (!Cow.player) return;
            const { context } = Cow.renderer;
            try {
                Cow.objectsManager.eachVisible((object) => {
                    if (!object.isItem && !object.isStructure && !object.buildingType && !object.type) return;
                    if ((object.health === undefined && object.hp === undefined) ||
                        (object.maxHealth === undefined && object.maxHP === undefined)) return;

                    const angle = CowUtils.getDirection ?
                        CowUtils.getDirection(object, Cow.player) :
                        Math.atan2(object.y - Cow.player.y, object.x - Cow.player.x);

                    if (settings["in-look-dir"] &&
                        CowUtils.getAngleDist &&
                        CowUtils.getAngleDist(angle, Cow.player.lookAngle) > (Cow.config?.gatherAngle || Math.PI/2)) {
                        return;
                    }
                    if (settings["hit-counter"]) {
                        drawHitCounter(context, object);
                    }
                    if (settings["health-bars"] && !settings["circle-bars"]) {
                        drawHealthBar(context, object);
                    }
                });
            } catch (e) {}
        }

        if (Cow.addRender) {
            Cow.addRender("building-health-bars", renderHealthBars);
        } else {
            function renderLoop() {
                try {
                    if (Cow && Cow.player && Cow.renderer && Cow.renderer.context) {
                        renderHealthBars();
                    }
                } catch (e) {}
                requestAnimationFrame(renderLoop);
            }
            requestAnimationFrame(renderLoop);
        }
        console.log("[Building Ownership Health Bars] Script iniciado correctamente");
    }

    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],
                    isSkull: playerInfo[11]
                });
            }
        }
    };

    const updateHealth = (health, playerIDCheck) => {
        if (myPlayer.id === playerIDCheck) {
            myPlayer.health = health;
            console.log("[🩸 Salud actualizada]", 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("[✔️ Verificación] ID del jugador:", 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("[🔌 WebSocket] Interceptado correctamente.");
        }
        this.oldSend(m);
    };

    const altchaCheck = setInterval(() => {
        let altcha = document.getElementById('altcha');
        let altchaBox = document.getElementById('altcha_checkbox');
        if (altcha && altchaBox) {
            altcha.style.display = 'none';
            altchaBox.checked = true;
            altchaBox.click();
            clearInterval(altchaCheck);
            console.log("[🚫 Altcha] Eliminado.");
        }
    }, 500);
})();

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

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

    async function refreshPage() {
        await delay(1500);
        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) => {
            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) => {
                    refreshPage();
                    return target.apply(this, args);
                });
                descriptor.set.call(this, wrappedHandler);
            }
        });
    });

})();

//esp
localStorage.setItem("moofoll", true);

const players = [];
const property = "team";

Object.defineProperty(Object.prototype, property, {
    get: function() {
        if (this.isPlayer && !players.find(p => p.id === this.id)) {
            players.push(this);
        }
        return this[`_${property}`];
    },
    set: function(value) {
        this[`_${property}`] = value;
    },
    configurable: true
});

let ctx, owner, camX = 0, camY = 0;
const conf = {
    radar: {
        colorEnemy: "#ff0000",
        colorAlly: "#00ff00",
        w: 20,
        h: 20
    },
    maxScreenWidth: 1920,
    maxScreenHeight: 1080
};

const createArrow = (id) => {
    const el = document.createElement("div");
    el.id = `radarArrow-${id}`;
    el.style.position = "absolute";
    el.style.width = "0";
    el.style.height = "0";
    el.style.borderStyle = "solid";
    el.style.borderWidth = `10px 0 10px ${conf.radar.w}px`;
    el.style.borderColor = `transparent transparent transparent ${conf.radar.colorEnemy}`;
    el.style.display = "none";
    el.style.zIndex = 999;
    document.body.appendChild(el);
};

const updateArrow = (id, x, y, color = conf.radar.colorEnemy, opacity = 1, angle = 0) => {
    const arrow = document.getElementById(`radarArrow-${id}`);
    if (!arrow) return;
    arrow.style.left = `${x}px`;
    arrow.style.top = `${y}px`;
    arrow.style.display = "block";
    arrow.style.opacity = opacity;
    arrow.style.transform = `rotate(${angle}deg)`;
    arrow.style.borderColor = `transparent transparent transparent ${color}`;
};

const removeArrow = (id) => {
    const arrow = document.getElementById(`radarArrow-${id}`);
    if (arrow) arrow.remove();
};

const getDistance = (x1, y1, x2, y2) => Math.hypot(x2 - x1, y2 - y1);
const getDirection = (x1, y1, x2, y2) => Math.atan2(y2 - y1, x2 - x1);
const RtoD = (r) => r * 180 / Math.PI;

const radar = (delta) => {
    if (!ctx) {
        const gameCanvas = document.getElementById("gameCanvas");
        if (!gameCanvas) return;
        ctx = gameCanvas.getContext("2d");
    }

    owner = players.find(p => p.visible && p.wood);
    if (!owner) return;

    const centerX = window.innerWidth / 2;
    const centerY = window.innerHeight / 2;

    camX += ((owner.x - camX) * 0.1);
    camY += ((owner.y - camY) * 0.1);

    const xOffset = camX - (conf.maxScreenWidth / 2);
    const yOffset = camY - (conf.maxScreenHeight / 2);

    for (let player of players) {
        if (player.id === owner.id) continue;

        if (!player.visible || typeof player.x !== "number" || typeof player.y !== "number") {
            removeArrow(player.id);
            continue;
        }

        const isAlly = player.team && player.team === owner.team;
        const color = isAlly ? conf.radar.colorAlly : conf.radar.colorEnemy;
        const arrowId = player.id;

        let rad = getDirection(owner.x, owner.y, player.x, player.y);
        let per = getDistance(0, 0, (owner.x - player.x), (owner.y - player.y) * (16 / 9)) * 100 / (conf.maxScreenHeight / 2);
        let alpha = Math.min(per / centerY, 1);
        let dis = centerY * alpha;

        let tx = centerX + dis * Math.cos(rad) - conf.radar.w / 2;
        let ty = centerY + dis * Math.sin(rad) - conf.radar.h / 2;

        if (!document.getElementById(`radarArrow-${arrowId}`)) {
            createArrow(arrowId);
        }

        updateArrow(arrowId, tx, ty, color, alpha, RtoD(rad));
    }
};

let lastTime = Date.now();
function gameLoop() {
    requestAnimationFrame(gameLoop);
    let now = Date.now();
    radar(now - lastTime);
    lastTime = now;
}
gameLoop();

//Goldbot/Music Menu
(function () {
    'use strict';


    const style = document.createElement('style');
    style.textContent = `
        #moddedMenu { position: fixed; top: 10px; left: 10px; width: 320px; background: rgba(0,0,0,0.6);
            border: 4px solid #ff0000; border-radius: 15px; z-index: 9999; color: white;
            font-family: monospace; display: flex; flex-direction: column; align-items: center;
            padding: 15px; box-sizing: border-box; opacity: 0; transform: scale(0.5);
            transition: opacity 0.3s ease, transform 0.3s ease; pointer-events: none; }
        #moddedMenu.open { opacity:1; transform:scale(1); pointer-events:auto; }

        #menuTabs { display:flex; justify-content:center; gap:6px; width:100%; margin-bottom:15px; }
        .tabButton { padding:5px 10px; border:1px solid #ff0000; border-radius:8px; background:#111;
            color:#ff0000; cursor:pointer; font-weight:bold; font-size:0.9em; transition: background 0.3s ease, transform 0.2s ease; }
        .tabButton.active { background:#cc0000; color:white; transform:scale(1.05); }

        .tabContent { display:none; width:100%; text-align:center; }
        .tabContent.active { display:block; }

        #menuTitle { font-size:1.4em; color:#ff0000; margin-bottom:12px; }

        .rd-select, .rd-button { font-family:monospace; width:85%; font-size:1em; padding:8px; margin:6px auto;
            border:1px solid #ff0000; border-radius:6px; background:#111; color:#ff0000; outline:none; display:block; text-align:center; }
        .rd-button { cursor:pointer; font-weight:bold; transition: background-color 0.3s ease, transform 0.2s ease; }
        .rd-button:hover { background-color:#cc0000; color:white; transform:scale(1.05); }

        #buttons { display:flex; justify-content:center; gap:12px; margin:8px 0; }

        .indicator { margin-top:6px; font-size:0.9em; color:#ff0000; }
        .indicator.active { color:#00ff00; }
    `;
    document.head.appendChild(style);


    const menu = document.createElement('div'); menu.id='moddedMenu';

    const tabBar = document.createElement('div'); tabBar.id='menuTabs';
    const tabMusic = document.createElement('button'); tabMusic.textContent="🎵 Music"; tabMusic.className="tabButton active";
    const tabBot = document.createElement('button'); tabBot.textContent="🤖 Bot"; tabBot.className="tabButton";
    tabBar.appendChild(tabMusic); tabBar.appendChild(tabBot);

    // -------------------- MUSIC TAB --------------------
    const musicContent = document.createElement('div'); musicContent.className="tabContent active";
    const musicTitle = document.createElement('div'); musicTitle.id='menuTitle'; musicTitle.textContent='Music Player';
    musicContent.appendChild(musicTitle);

    const musicTracks = [
        {name:"Alan Walker - Faded",url:"https://files.catbox.moe/p9om0y.mp3"},
        {name:"Alan Walker - Alone",url:"https://files.catbox.moe/xptxat.mp3"},
        {name:"TheFatRat - Unity",url:"https://files.catbox.moe/cx5uyo.mp3"},
        {name:"TheFatRat - Monody",url:"https://files.catbox.moe/7fwpbl.mp3"},
        {name:"NEFFEX - Fight Back",url:"https://files.catbox.moe/iif5rx.mp3"},
        {name:"NEFFEX - Never Give Up",url:"https://files.catbox.moe/2pamid.mp3"},
        {name:"Alan Walker - Dust",url:"https://files.catbox.moe/w1sb9x.mp3"},
        {name:"Alan Walker - Catch Me",url:"https://files.catbox.moe/74b06c.mp3"},
        {name:"Alan Walker - Last Song",url:"https://files.catbox.moe/nuta1v.mp3"},
        {name:"Egzod - Royalty ft. Neoni",url:"https://files.catbox.moe/zlfc04.mp3"}
    ];

    const musicSelect = document.createElement('select'); musicSelect.className='rd-select';
    musicTracks.forEach(track=>{ const o=document.createElement('option'); o.value=track.url; o.textContent=track.name; musicSelect.appendChild(o); });
    musicContent.appendChild(musicSelect);

    const buttonsDiv = document.createElement('div'); buttonsDiv.id='buttons';
    const playBtn = document.createElement('button'); playBtn.className='rd-button'; playBtn.textContent='▶ Play';
    const stopBtn = document.createElement('button'); stopBtn.className='rd-button'; stopBtn.textContent='■ Stop';
    buttonsDiv.appendChild(playBtn); buttonsDiv.appendChild(stopBtn);
    musicContent.appendChild(buttonsDiv);

    const modeSelect = document.createElement('select'); modeSelect.className='rd-select';
    modeSelect.innerHTML=`<option value="repeat">🔁 Repeat</option><option value="next">⏭️ Next</option>`;
    musicContent.appendChild(modeSelect);

    const audio = document.createElement('audio'); audio.id='audioPlayer'; musicContent.appendChild(audio);

    function playMusic(){ audio.src=musicSelect.value; audio.play(); }
    playBtn.addEventListener('click',()=>{ if(audio.src!==musicSelect.value) audio.src=musicSelect.value; audio.play(); });
    stopBtn.addEventListener('click',()=>{ audio.pause(); audio.currentTime=0; });
    musicSelect.addEventListener('change',()=>{ if(!audio.paused) playMusic(); });
    audio.addEventListener('ended',()=>{ if(modeSelect.value==='repeat'){audio.currentTime=0; audio.play();} else { const idx=(musicSelect.selectedIndex+1)%musicSelect.options.length; musicSelect.selectedIndex=idx; playMusic(); }});


    const botContent = document.createElement('div'); botContent.className='tabContent';
    const botTitle = document.createElement('div'); botTitle.id='menuTitle'; botTitle.textContent='🤖 Bot Config';
    botContent.appendChild(botTitle);

    const respawnBtn = document.createElement('button'); respawnBtn.className='rd-button'; respawnBtn.textContent='Disable Respawn';
    botContent.appendChild(respawnBtn);

    const chatToggleBtn = document.createElement('button'); chatToggleBtn.className='rd-button'; chatToggleBtn.textContent='Chat Spam: ON';
    botContent.appendChild(chatToggleBtn);

    const moveToggleBtn = document.createElement('button'); moveToggleBtn.className='rd-button'; moveToggleBtn.textContent='Bot Movement: ON';
    botContent.appendChild(moveToggleBtn);

    const respawnIndicator = document.createElement('div'); respawnIndicator.className='indicator active'; respawnIndicator.textContent='Respawn Enabled';
    botContent.appendChild(respawnIndicator);


    let chatEnabled = true; // ahora viene activado por defecto
    let movementEnabled = true;
    let respawnEnabled = true;

    respawnBtn.addEventListener('click', ()=>{ respawnEnabled=false; respawnIndicator.textContent='Respawn Disabled'; respawnIndicator.classList.remove('active'); });
    chatToggleBtn.addEventListener('click', ()=>{ chatEnabled=!chatEnabled; chatToggleBtn.textContent=`Chat Spam: ${chatEnabled?'ON':'OFF'}`; bots.forEach(b=>b.chatIndex=0); });
    moveToggleBtn.addEventListener('click', ()=>{ movementEnabled=!movementEnabled; moveToggleBtn.textContent=`Bot Movement: ${movementEnabled?'ON':'OFF'}`; bots.forEach(b=>b.autm.boolean=movementEnabled); });


    menu.appendChild(tabBar); menu.appendChild(musicContent); menu.appendChild(botContent); document.body.appendChild(menu);

    function switchTab(activeButton, activeContent){
        document.querySelectorAll(".tabButton").forEach(btn=>btn.classList.remove("active"));
        document.querySelectorAll(".tabContent").forEach(c=>c.classList.remove("active"));
        activeButton.classList.add("active"); activeContent.classList.add("active");
    }
    tabMusic.addEventListener("click",()=>switchTab(tabMusic,musicContent));
    tabBot.addEventListener("click",()=>switchTab(tabBot,botContent));

    document.addEventListener('keydown',e=>{ if(e.key==='Escape') menu.classList.toggle('open'); });


    const msgpackLite = window.msgpack;
    const NativeWebSocket = window.WebSocket;

    let mainSocket; let bots=[]; let ownPlayer={sid:null,x:0,y:0,dir:0,skinIndex:0,name:null};
    const chatMessages = [
        "Hello mooaddict","I am hathu slave","Watch out!","Run!","Attack!","Stay close","Help me","Gather wood","Enemy here","Follow me"
    ];
    let randomHats=[28,29,30,36,37,38,42,43,44,49];

    async function safeDecode(event){
        try{
            let buf;
            if(event.data instanceof Blob) buf=new Uint8Array(await event.data.arrayBuffer());
            else if(event.data instanceof ArrayBuffer) buf=new Uint8Array(event.data);
            else return null;
            return msgpackLite.decode(buf);
        }catch{return null;}
    }

    function hookPacket(decoded){ if(!decoded) return null; return decoded.length>1 && Array.isArray(decoded[1]) ? [decoded[0], ...decoded[1]] : decoded; }

    class WebSocketProxy extends NativeWebSocket {
        constructor(...args){
            super(...args);
            if(!mainSocket){ mainSocket=this;
                this.addEventListener("message", async e=>{
                    let hooked=hookPacket(await safeDecode(e)); if(!hooked) return;
                    if(hooked[0]==="io-init"){ let region=mainSocket.url.split("/")[2]; const BOT_COUNT=3;
                        for(let i=0;i<BOT_COUNT;i++){ let token=await altSolver.generate(); bots.push(new BotClient(region,token)); }
                    }
                    if(hooked[0]==="C" && ownPlayer.sid==null) ownPlayer.sid=hooked[1];
                    if(hooked[0]==="D" && hooked[1][1]===ownPlayer.sid) ownPlayer.name=hooked[1][2];
                    if(hooked[0]==="a"){
                        for(let i=0;i<hooked[1].length/13;i++){ let p=hooked[1].slice(13*i,13*i+13); if(p[0]==ownPlayer.sid) [ownPlayer.x,ownPlayer.y,ownPlayer.dir,ownPlayer.skinIndex]=[p[1],p[2],p[3],p[9]]; }
                        for(let b of bots){ b.autm.x=ownPlayer.x; b.autm.y=ownPlayer.y; }
                    }
                });
            }
        }
    }
    window.WebSocket = WebSocketProxy;

    class BotClient {
        constructor(region, token){
            this.socket=new NativeWebSocket(`wss://${region}/?token=${token}`);
            this.sid=null; this.x=0; this.y=0; this.dir=0; this.weaponIndex=0; this.health=100; this.foodCount=100; this.packetCount=0;
            this.autm={x:0,y:0,boolean:true}; this.chatIndex=0; setInterval(()=>this.packetCount=0,1000);

            this.socket.addEventListener("open",()=>{
                setInterval(()=>{
                    if(this.sid && chatEnabled){ let msg=chatMessages[this.chatIndex]; this.sendMessage("6",msg); this.chatIndex=(this.chatIndex+1)%chatMessages.length; }
                },3000);

                this.socket.addEventListener("message",async e=>{
                    let hooked=hookPacket(await safeDecode(e)); if(!hooked) return;
                    if(hooked[0]==="io-init" && respawnEnabled) this.spawn();
                    if(hooked[0]==="C" && this.sid==null) this.sid=hooked[1];
                    if(hooked[0]==="D" && hooked[1][1]===this.sid){ this.foodCount=100; this.health=100; }
                    if(hooked[0]==="a"){
                        for(let i=0;i<hooked[1].length/13;i++){ let p=hooked[1].slice(13*i,13*i+13); if(p[0]===this.sid) [this.x,this.y,this.dir,this.weaponIndex]=[p[1],p[2],p[3],p[5]]; }

                        this.equipIndex(0, randomHats[Math.floor(Math.random()*randomHats.length)],0);

                        if(this.autm.boolean){
                            // === LÓGICA DE MOVIMIENTO CORREGIDA ===
                            let dx = this.autm.x - this.x;
                            let dy = this.autm.y - this.y;
                            let dist = Math.hypot(dx, dy);

                            if(dist > 5){
                                let ang = Math.atan2(dy, dx);
                                this.sendMessage("9", ang);
                            } else {
                                this.sendMessage("9", null);
                            }
                        }
                    }
                    if(hooked[0]==="P" && respawnEnabled) this.spawn();
                });
            });
        }

        spawn(){ if(!respawnEnabled) return; let randomSkin=Math.floor(Math.random()*15); this.sendMessage("M",{name:"goldbot",moofoll:true,skin:randomSkin}); }
        equipIndex(buy,id,index){ this.sendMessage("c",buy,id,index); }
        sendMessage(type,...args){ if(this.packetCount<120){ this.socket.send(new Uint8Array(msgpackLite.encode([type,args]))); this.packetCount++; } }
    }

    class AltSolver {
        constructor(){ this.core_count=Math.min(16,navigator.hardwareConcurrency||8); this.workers=[]; this.initialized=false; this.blobUrl=null; }

        initWorkerPool() {
            if(this.initialized) return;
            const workerCode = `
                importScripts('https://cdn.jsdelivr.net/npm/[email protected]/build/sha256.min.js');
                let challenge=null, salt=null;
                self.onmessage=function(e){
                    const data=e.data;
                    if(data.init){ challenge=data.challenge; salt=data.salt; self.postMessage({ready:true}); return; }
                    const {start,end}=data;
                    for(let i=start;i<=end;i++){ if(sha256(salt+i)===challenge){ self.postMessage({found:i}); return; } }
                    self.postMessage({done:true});
                };
            `;
            const blob=new Blob([workerCode],{type:"application/javascript"});
            this.blobUrl=URL.createObjectURL(blob);
            for(let i=0;i<this.core_count;i++) this.workers.push(new Worker(this.blobUrl));
            this.initialized=true;
        }

        async getChallenge(){
            const response=await fetch("https://api.moomoo.io/verify");
            return await response.json();
        }

        async solveChallenge(challengeData){
            this.initWorkerPool();
            const {challenge,salt,maxnumber}=challengeData;
            const segmentSize=Math.ceil(maxnumber/this.core_count);
            let solved=false, doneCount=0;

            return new Promise((resolve,reject)=>{
                const startTime=performance.now();
                const tasks=this.workers.map((worker,idx)=>({ start:idx*segmentSize, end:Math.min(maxnumber,(idx+1)*segmentSize-1) }));

                this.workers.forEach((worker,idx)=>{
                    worker.onmessage=e=>{
                        const msg=e.data;
                        if(msg.ready) worker.postMessage(tasks[idx]);
                        else if(msg.found!=null && !solved){
                            solved=true;
                            const number=msg.found;
                            const took=((performance.now()-startTime)/1000).toFixed(2);
                            resolve({challenge,salt,maxnumber,number,took});
                            this.cleanupWorkers();
                        } else if(msg.done){ doneCount++; if(!solved && doneCount===this.workers.length){ reject(new Error("Challenge not solved")); this.cleanupWorkers(); } }
                    };
                    worker.onerror=err=>{ if(!solved){ reject(err); this.cleanupWorkers(); } };
                    worker.postMessage({init:true,challenge,salt});
                });
            });
        }

        cleanupWorkers(){
            this.workers.forEach(w=>w.terminate());
            this.workers=[]; this.initialized=false;
            if(this.blobUrl){ URL.revokeObjectURL(this.blobUrl); this.blobUrl=null; }
        }

        static createPayload(Data,Date_){
            return btoa(JSON.stringify({
                algorithm:"SHA-256",
                challenge:Data.challenge,
                salt:Data.salt,
                number:Date_.number,
                signature:Data.signature||null,
                took:Date_.took
            }));
        }

        async generate(){
            const challengeData=await this.getChallenge();
            const solution=await this.solveChallenge(challengeData);
            this.code=`alt:${AltSolver.createPayload(challengeData,solution)}`;
            return this.code;
        }
    }

    let altSolver = new AltSolver();
})();