x-RedDragon Client

R=InstaNormal, T=BoostInsta, G=BoostSpike, B=4Traps/Boost, M=AutoMills, F=Trap/BoostPad, V=Spike, N=Mill, H=Teleport/Turret, P=AutoGrindsBETA, AutoBiomeHat, Esc=MenuMusic, ClickRight=FastBreak, AutoGG, AutoHeal, AntiInsta and visual mods.

// ==UserScript==
// @name         x-RedDragon Client
// @namespace    http://youtube.com/@x-RedDragonYT
// @version      1.0.5
// @description  R=InstaNormal, T=BoostInsta, G=BoostSpike, B=4Traps/Boost, M=AutoMills, F=Trap/BoostPad, V=Spike, N=Mill, H=Teleport/Turret, P=AutoGrindsBETA, AutoBiomeHat, Esc=MenuMusic, ClickRight=FastBreak, AutoGG, AutoHeal, AntiInsta and visual mods.
// @icon         https://i.imgur.com/AFJt4iq.png
// @author       x-RedDragonYT
// @match        *://moomoo.io/*
// @match        *://*.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==

(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;
    let prevKillCount = 0;

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

    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 emit(type, ...data) {
        if (ws && msgpack5) ws.send(Uint8Array.from(msgpack5.encode([type, data])));
    }

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

    function sequenceInstaKill(includeBoost = false) {
        if (includeBoost) place(boostType);

        setTimeout(() => {
            doNewSend(["c", [0, ID_BullHelmet, 0]]);
            emit("z", myPlayer.weapon, true);
            emit("F", 1);
            emit("F", 0);

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

                setTimeout(() => {
                    doNewSend(["c", [0, ID_SoldierHelmet, 0]]);
                }, 200);
            }, 120);
        }, 120);
    }

    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(false);
        if (k === 't') sequenceInstaKill(true);
        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);
        }
    });

    // ✅ Redefinición segura de WebSocket.send
    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]];
                }
            }

            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) {
            const hp = data[2];
            if (hp < 100 && hp > 0 && healToggle) {
                let delay = hp <= 60 ? 5 : 122;
                setTimeout(() => place(foodType), delay);
            }
        }
    }

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

    // 🗨️ AutoGG al matar
    const observeKills = new MutationObserver(mutations => {
        for (const mutation of mutations) {
            if (mutation.target.id === "killCounter") {
                const count = parseInt(mutation.target.innerText, 10) || 0;
                if (count > prevKillCount) {
                    prevKillCount = count;
                    doNewSend(["6", ["<[GG]>x-RedDragon Client<[GG]>"]]);
                }
            }
        }
    });
    observeKills.observe(document, { subtree: true, childList: true });

// 🖱️ Click derecho: ataque automático + cambio de casco (sin storeEquip)
let rightClickAttackInterval = null;
let rightClickHeld = false;
let isPlacingStructure = false;
let attackPausedForPlacement = false;

function startAttackLoop() {
    if (rightClickAttackInterval) return;
    rightClickAttackInterval = setInterval(() => {
        doNewSend(["c", [0, ID_TankGear, 0]]); // Casco ofensivo
        doNewSend(["F", [1]]);
        setTimeout(() => doNewSend(["F", [0]]), 10);
    }, 60);
}

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

// Escucha el clic derecho y activa la lógica de ataque
document.addEventListener("mousedown", function (e) {
    if (e.button === 2 && !rightClickHeld) {
        rightClickHeld = true;
        doNewSend(["c", [0, ID_TankGear, 0]]); // Equipar casco ofensivo

        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); // Volver al casco base
    }
});

// Interceptamos la función `place(...)` para pausar el ataque si se colocan estructuras
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);
};

// 🔁 AutoGrind Beta-2
let autoGrindActive = false;
let autoGrindInterval = null;
const myStructures = [];
const STRUCTURE_LIFETIME = 1000;
const STRUCTURE_DISTANCE = 50;
const UP_DIR = -Math.PI / 2;

function customPlaceAndTrack(id, angle) {
    place(id, angle);
    const fakeX = myPlayer.x + Math.cos(angle) * STRUCTURE_DISTANCE;
    const fakeY = myPlayer.y + Math.sin(angle) * STRUCTURE_DISTANCE;
    myStructures.push({ type: id, angle, x: fakeX, y: fakeY, time: Date.now() });
}

function cleanupStructures() {
    const now = Date.now();
    while (myStructures.length > 0 && now - myStructures[0].time > STRUCTURE_LIFETIME) {
        myStructures.shift();
    }
}

function countRecentPlaced(type) {
    const now = Date.now();
    return myStructures.filter(obj =>
        obj.type === type && now - obj.time < STRUCTURE_LIFETIME
    ).length;
}

document.addEventListener("keydown", e => {
    if (document.activeElement.id.toLowerCase() === 'chatbox') return;
    if (e.key.toLowerCase() === 'p') {
        autoGrindActive = !autoGrindActive;

        if (autoGrindActive) {
            console.log("⚙️ AutoGrind ACTIVADO");
            doNewSend(["6", ["AutoGrind ACTIVADO"]]);

            // ⚔️ Equipar TankGear al iniciar
            doNewSend(["c", [0, ID_TankGear, 0]]);

            autoGrindInterval = setInterval(() => {
                if (!turretType || typeof myPlayer.x !== 'number' || typeof myPlayer.y !== 'number') return;

                cleanupStructures();
                emit("D", UP_DIR);

                if (countRecentPlaced(turretType) < 2) {
                    customPlaceAndTrack(turretType, UP_DIR);
                }

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

                // ⚔️ Reequipar TankGear por seguridad
                doNewSend(["c", [0, ID_TankGear, 0]]);
                emit("D", UP_DIR);
            }, 120);
        } else {
            console.log("❌ AutoGrind DESACTIVADO");
            doNewSend(["6", ["AutoGrind DESACTIVADO"]]);
            clearInterval(autoGrindInterval);
            autoGrindInterval = null;

            // 🛡 Volver a SoldierHelmet después
            setTimeout(() => {
                doNewSend(["c", [0, ID_SoldierHelmet, 0]]);
            }, 300);
        }
    }
});
// 🎩 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]]);
        }
    }

    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); // más reactivo y fluido

    console.log("✅ AutoBiomeHatController V2 activado.");
}

autoBiomeHatController();
})();

(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) {
            // Solo bloqueamos líneas completamente horizontales o verticales
            const isStraight = (x1 === x2 || y1 === y2);

            // Solo si ambas coordenadas están cerca de múltiplos del grid
            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]; // Guardamos el punto anterior
            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);
        };
    });
})();

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

    input, select {
        background-color: rgba(31, 31, 31, 0.2) !important;
        color: #fff !important;
        border: 1px solid #ff3300 !important;
        border-radius: 10px;
        padding: 10px;
        text-align: center;
    }

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

(function() {
    'use strict';

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

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

    // Crear y añadir nuevo favicon
    const newFavicon = document.createElement("link");
    newFavicon.rel = "icon";
    newFavicon.type = "image/png";
    newFavicon.href = "https://i.imgur.com/vXgDJSp.png";
    document.head.appendChild(newFavicon);
})();

(function () {
    'use strict';

    // Variables para FPS y Ping
    let frameCount = 0;
    let fps = 0;
    let ping = 0;
    let lastLoop = performance.now();
    let pingTimes = [];

    // Función para obtener el ping real con fetch y promediarlo
    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); // Actualiza cada 1s
    }
    updatePing();

    // FPS con requestAnimationFrame
    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();

    // Crear el contador visual con el nuevo diseño Orbitron
    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', // Debajo de los botones
        pointerEvents: 'none'
    });
    document.body.appendChild(statsContainer);

    // Actualiza cada 500ms el texto visible
    function updateStatsDisplay() {
        statsContainer.textContent = `FPS: ${fps} | Ping: ${ping}ms`;
        setTimeout(updateStatsDisplay, 500);
    }
    updateStatsDisplay();

    // Acceso desde consola opcional
    window.getStats = function () {
        return { fps, ping };
    };
})();

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

    const previousReloadStates = new Map();
    const turretCooldown = 2500;
    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;

            // Barra primaria
            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();

            // Barra secundaria
            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();

            // === Contador de HP ===
            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"; // Usa GameFont, o Arial si no carga
            ctx.textAlign = "center";
            ctx.lineWidth = 3;
            ctx.strokeStyle = "black";
            ctx.fillStyle = "white";

            const textX = player.renderX;
            const textY = yOffset + 32; // 12 píxeles más abajo

            ctx.strokeText(hpText, textX, textY); // Borde negro
            ctx.fillText(hpText, textX, textY);   // Letra blanca
            ctx.restore();
        });
    });
})();

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

(function () {
    "use strict";

    // Asegurarse de que el script se inicie después de que el juego esté completamente cargado
    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
        };

        // Función para determinar si una construcción pertenece al jugador
        function isOwnBuilding(object) {
            // Verificar si tiene la propiedad de grupo (team)
            if (object && Cow.player) {
                // En MooMoo.io la propiedad group o team indica el equipo
                if (object.group !== undefined && Cow.player.group !== undefined) {
                    return object.group === Cow.player.group;
                }

                // Alternativa: verificar por ownerID o owner.sid
                if (object.owner && Cow.player.sid) {
                    return object.owner.sid === Cow.player.sid;
                }

                // Otra alternativa: comprobar teamID o team
                if (object.team !== undefined && Cow.player.team !== undefined) {
                    return object.team === Cow.player.team;
                }
            }

            // Por defecto si no podemos determinar, asumimos que es enemiga
            return false;
        }

        function drawHealthBar(context, object) {
            const healthBarWidth = 50; // Ancho predeterminado si window.config no está disponible
            const healthBarPad = 5;    // Padding predeterminado si window.config no está disponible

            // Usar configuración del juego si está disponible
            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;

            // Determinar el color basado en si la construcción es del jugador o enemiga
            const barColor = isOwnBuilding(object) ? settings["friendly-color"] : settings["enemy-color"];

            context.save();
            context.translate(object.renderX || object.x, object.renderY || object.y);

            // Fondo de la barra de vida
            context.fillStyle = "#3d3f42";
            if (context.roundRect) {
                context.roundRect(-width - healthBarPad, -height / 2, 2 * width + 2 * healthBarPad, height, radius);
            } else {
                // Alternativa si roundRect no está disponible
                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();

            // Barra de vida con el color según propiedad
            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 {
                // Alternativa si roundRect no está disponible
                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();

            // Mostrar texto de propietario para depuración (quitar en producción)
            /*
            context.fillStyle = "#fff";
            context.font = "10px Arial";
            context.fillText(isOwnBuilding(object) ? "Mío" : "Enemigo", 0, -30);
            if (object.group !== undefined) context.fillText("Group: " + object.group, 0, -42);
            if (object.team !== undefined) context.fillText("Team: " + object.team, 0, -54);
            if (object.owner) context.fillText("Owner: " + (object.owner.sid || "?"), 0, -66);
            */

            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) {
                console.error("Error en hit counter:", e);
            }
        }

        // Función principal para renderizar las barras de vida
        function renderHealthBars() {
            if (!Cow.player) return;
            const { context } = Cow.renderer;

            try {
                Cow.objectsManager.eachVisible((object) => {
                    // Solo procesar objetos que sean estructuras/items
                    if (!object.isItem && !object.isStructure && !object.buildingType && !object.type) return;

                    // Solo procesar objetos que tengan salud
                    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);

                    // Verificar si está en la dirección de mirada si esta opción está activada
                    if (settings["in-look-dir"] &&
                        CowUtils.getAngleDist &&
                        CowUtils.getAngleDist(angle, Cow.player.lookAngle) > (Cow.config?.gatherAngle || Math.PI/2)) {
                        return;
                    }

                    // Dibujar contador de golpes si está activado
                    if (settings["hit-counter"]) {
                        drawHitCounter(context, object);
                    }

                    // Dibujar barra de vida si está activado
                    if (settings["health-bars"] && !settings["circle-bars"]) {
                        drawHealthBar(context, object);
                    }
                });
            } catch (e) {
                console.error("Error en renderHealthBars:", e);
            }
        }

        // Agregar la función de renderizado al loop del juego
        if (Cow.addRender) {
            Cow.addRender("building-health-bars", renderHealthBars);
        } else {
            // Alternativa si addRender no está disponible: usar requestAnimationFrame
            function renderLoop() {
                try {
                    if (Cow && Cow.player && Cow.renderer && Cow.renderer.context) {
                        renderHealthBars();
                    }
                } catch (e) {
                    console.error("Error en renderLoop:", e);
                }
                requestAnimationFrame(renderLoop);
            }
            requestAnimationFrame(renderLoop);
        }

        console.log("[Building Ownership Health Bars] Script iniciado correctamente");
    }

    // Iniciar el script
    if (document.readyState === "complete") {
        init();
    } else {
        window.addEventListener("load", init);
    }
})();

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

    // Anti-Altcha (captcha visual)
    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);
})();

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

    // Función para retrasar la ejecución (sleep)
    function delay(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    // Recarga la página después de 1.5 segundos
    async function refreshPage() {
        await delay(1500);
        window.onbeforeunload = null;
        location.reload();
    }

    // Crea un hook (interceptor) para la propiedad indicada en el objeto target
    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
        });
    }

    // Intercepta una función para envolverla y modificar su comportamiento
    function wrapFunction(originalFunc, wrapper) {
        return new Proxy(originalFunc, {
            apply(target, thisArg, args) {
                return wrapper.call(thisArg, target, args);
            }
        });
    }

    // Hook para capturar cualquier asignación a "errorCallback" en Object.prototype
    interceptProperty(Object.prototype, "errorCallback", (obj, key, val) => {
        obj[key] = val;

        if (typeof val !== "function") return;

        // Reemplaza la función original con un Proxy que recarga la página
        obj[key] = wrapFunction(val, (target, args) => {
            // Anula alert para evitar alertas molestas
            window.alert = () => {};
            // Recarga la página
            refreshPage();
            // Ejecuta la función original
            return target.apply(this, args);
        });
    });

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

        Object.defineProperty(WebSocket.prototype, eventName, {
            set(handler) {
                // Envuelve el handler original para recargar la página al dispararse
                const wrappedHandler = wrapFunction(handler, (target, args) => {
                    refreshPage();
                    return target.apply(this, args);
                });
                descriptor.set.call(this, wrappedHandler);
            }
        });
    });

})();

(function () {
    'use strict';

    // ==== ESTILOS ====
    const style = document.createElement('style');
    style.textContent = `
        #moddedMenu {
            position: fixed;
            top: 10px;
            left: 10px;
            width: 300px;
            background: rgba(0, 0, 0, 0.95);
            border: 4px solid #ff0000;
            border-radius: 15px;
            z-index: 9999;
            color: white;
            font-family: monospace;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 20px;
            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;
        }

        #moddedMenuContent {
            width: 100%;
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        #menuTitle {
            font-size: 1.6em;
            color: #ff0000;
            text-align: center;
            margin-bottom: 20px;
        }

        .rd-select, .rd-button {
            font-family: monospace;
            width: 100%;
            max-width: 90%;
            font-size: 1em;
            padding: 8px;
            margin-bottom: 10px;
            border: 1px solid #ff0000;
            border-radius: 5px;
            background: #111;
            color: #ff0000;
            outline: none;
        }

        .rd-button {
            cursor: pointer;
            font-weight: bold;
            transition: background-color 0.3s ease;
        }

        .rd-button:hover {
            background-color: #cc0000;
        }

        #buttons {
            display: flex;
            justify-content: space-between;
            width: 90%;
            gap: 10px;
        }

        .toggle-switch {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-top: 10px;
            margin-bottom: 10px;
            color: #ff0000;
        }

        .toggle-switch input[type="checkbox"] {
            width: 40px;
            height: 20px;
            appearance: none;
            background: #222;
            border: 2px solid #ff0000;
            border-radius: 20px;
            position: relative;
            cursor: pointer;
            outline: none;
            transition: background 0.3s ease;
        }

        .toggle-switch input[type="checkbox"]::before {
            content: '';
            position: absolute;
            width: 16px;
            height: 16px;
            border-radius: 50%;
            background: #ff0000;
            top: 1px;
            left: 1px;
            transition: transform 0.3s ease;
        }

        .toggle-switch input[type="checkbox"]:checked::before {
            transform: translateX(20px);
        }
    `;
    document.head.appendChild(style);

    // ==== ELEMENTOS DEL MENÚ ====
    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 menu = document.createElement('div');
    menu.id = 'moddedMenu';

    const content = document.createElement('div');
    content.id = 'moddedMenuContent';

    const title = document.createElement('div');
    title.id = 'menuTitle';
    title.textContent = '𝕄𝕦𝕤𝕚𝕔𝕤';

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

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

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

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

    const visualsTitle = document.createElement('div');
    visualsTitle.textContent = '𝔼𝕩𝕥𝕣𝕒';
    visualsTitle.style.color = '#ff0000';
    visualsTitle.style.fontSize = '1.4em';
    visualsTitle.style.marginTop = '25px';
    visualsTitle.style.marginBottom = '10px';
    visualsTitle.style.fontWeight = 'bold';
    visualsTitle.style.textAlign = 'center';

    const toggleContainer = document.createElement('div');
    toggleContainer.className = 'toggle-switch';
    const toggleLabel = document.createElement('span');
    toggleLabel.textContent = 'Tracers';
    const toggleInput = document.createElement('input');
    toggleInput.type = 'checkbox';
    toggleContainer.appendChild(toggleLabel);
    toggleContainer.appendChild(toggleInput);

    content.appendChild(title);
    content.appendChild(musicSelect);
    content.appendChild(buttonsDiv);
    content.appendChild(modeSelect);
    content.appendChild(visualsTitle);
    content.appendChild(toggleContainer);
    content.appendChild(audio);
    menu.appendChild(content);
    document.body.appendChild(menu);

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

    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) {
            audio.src = musicSelect.value;
            audio.play();
        }
    });

    audio.addEventListener('ended', () => {
        if (modeSelect.value === 'repeat') {
            audio.currentTime = 0;
            audio.play();
        } else if (modeSelect.value === 'next') {
            const currentIndex = musicSelect.selectedIndex;
            const nextIndex = (currentIndex + 1) % musicSelect.options.length;
            musicSelect.selectedIndex = nextIndex;
            audio.src = musicSelect.value;
            audio.play();
        }
    });

    // ==== TRACERS ====
    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: "#ffffff",
            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 (!toggleInput.checked) {
            players.forEach(p => removeArrow(p.id));
            return;
        }

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

        for (let player of players) {
            if (player.id === owner.id || !player.visible || typeof player.x !== "number" || typeof player.y !== "number" || (player.team && player.team === owner.team)) {
                removeArrow(player.id);
                continue;
            }

            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, conf.radar.colorEnemy, alpha, RtoD(rad));
        }
    };

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

})();