🛡️ The Hylian Companion Mod (Zelda Edition) ⚔️

Invoke the full power of the Triforce! Transform your Drawaria into Hyrule with all legendary items and powers.

// ==UserScript==
// @name         🛡️ The Hylian Companion Mod (Zelda Edition) ⚔️
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Invoke the full power of the Triforce! Transform your Drawaria into Hyrule with all legendary items and powers.
// @author       YouTubeDrawaria
// @match        https://drawaria.online/*
// @match        https://*.drawaria.online/*
// @icon         https://fonts.gstatic.com/s/e/notoemoji/latest/2728/512.webp
// @grant        GM_xmlhttpRequest
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    /* ----------------------------------------------------------------------------------
    //  PIXEL ART HYLIAN (Drawaria Line Format)
    //  Definición de los assets visuales clave en arrays para ser dibujados línea por línea.
    // ---------------------------------------------------------------------------------- */

    // R=Rojo, D=Oscuro, G=Oro, P=Púrpura, B=Azul, L=Plata, W=Blanco, Y=Amarillo, F=Fairy/Rosa, O=Naranja
    const HYLIAN_PIXEL_ASSETS = {
        // Corazón de Vida (Zelda Classic Style)
        'HEART_CONTAINER': {
            art: [
                "  DDRRDD  ",
                " DRRRRRRD ",
                "DRRRRRRRRD",
                "DRRRRRRRRD",
                " DRRRRRRD ",
                "  DRRRRD  ",
                "   DRRD   "
            ],
            colors: { 'D': '#440000', 'R': '#FF0000' }
        },
        // Espada Maestra (Master Sword)
        'MASTER_SWORD': {
            art: [
                "   L   ",
                "   B   ",
                "  BLB  ",
                "  GLG  ",
                "  PGP  ",
                "  W W  "
            ],
            colors: { 'B': '#1E90FF', 'L': '#C0C0C0', 'G': '#FFD700', 'P': '#800080', 'W': '#FFFFFF' }
        },
        // Escudo Hylian (Hylian Shield)
        'HYLIAN_SHIELD': {
            art: [
                "   B   ",
                "  GBG  ",
                " BBRBB ",
                " WBBBW ",
                " GBBBG ",
                "  BBB  "
            ],
            colors: { 'B': '#1E90FF', 'G': '#FFD700', 'R': '#DC143C', 'W': '#FFFFFF' }
        },
        // Trifuerza (Triforce)
        'TRIFORCE': {
            art: [
                "   G   ",
                "  G G  ",
                " GGGGG "
            ],
            colors: { 'G': '#FFD700' }
        },
        // Hada de Recuperación (Navi/Fairy)
        'RECOVERY_FAIRY': {
            art: [
                "  YYY  ",
                " YFFFY ",
                " YFFFY ",
                "  YYY  "
            ],
            colors: { 'Y': '#FFFFFF', 'F': '#FFC0CB' }
        },
        // Nota Musical (Ocarina Stun)
        'MUSIC_NOTE': {
            art: [
                " WW ",
                " WB ",
                " B  "
            ],
            colors: { 'W': '#FFFFFF', 'B': '#ADD8E6' }
        }
    };


    /* ----------------------------------------------------------------------------------
    //  CONSTANTES DE HYRULE - ITEMS Y PODERES
    // ---------------------------------------------------------------------------------- */
    const ZELDA_ITEMS = {
        'Ninguno': '',
        '⚔️ Espada Maestra (Ataque)': 'weapon:master_sword',
        '🏹 Flecha de Luz (Laser)': 'weapon:light_arrow',
        '💣 Bomba (Explosión)': 'weapon:bomb_explosion',
        '🎣 Gancho (Movimiento)': 'weapon:hookshot_draw',
        '🌪️ Gran Spin Attack': 'weapon:spin_attack',
        '✨ Espada Lanzarrayos': 'weapon:sword_beam_boost'
    };

    const HYLIAN_POWERS = {
        'Ninguno': '',
        '🛡️ Escudo Hylian (Defensa)': 'effect:hylian_shield',
        '🧚 Hada de Recuperación': 'effect:recovery_fairy',
        '💛 Contenedor de Corazón': 'effect:heart_container_boost',
        '🌀 Ocarina de Tiempo (Stun)': 'effect:ocarina_stun',
        '🔥 Varita de Fuego': 'effect:fire_rod'
    };

    const POWER_INTENSITY_LABELS = ['Bajo (Kokiri)', 'Medio (Goron)', 'Alto (Zora)', 'Maestro (Hylian)', 'Leyenda (Trifuerza)'];

    /* ----------------------------------------------------------------------------------
    //  SETUP BASE (Conexión y Canvas)
    // ---------------------------------------------------------------------------------- */
    let socket;
    const canvas = document.getElementById('canvas');
    const ctx = canvas ? canvas.getContext('2d') : null;

    let stopSignal = false;
    let stopPowerBtn;
    let activePowerInterval = null;

    const originalSend = WebSocket.prototype.send;
    WebSocket.prototype.send = function (...args) {
        if (!socket) socket = this;
        return originalSend.apply(this, args);
    };

    /* ----------------------------------------------------------------------------------
    //  INTERFAZ DE USUARIO: Hylian Command Panel (UI) - (Mismo código, no se modifica)
    // ---------------------------------------------------------------------------------- */
    const hylianContainer = document.createElement('div');
    hylianContainer.id = 'HylianCompanionUI';
    hylianContainer.style.cssText = `
        position:fixed; bottom:10px; right:10px; z-index:9999;
        background:rgba(21, 67, 96, 0.85); /* Azul/Verde Oscuro de Inventario */
        color:#FFD700; padding:15px 20px; border-radius:10px;
        font-family: 'Pixelify Sans', 'Press Start 2P', monospace, sans-serif; font-size:12px;
        display:flex; flex-direction:column; gap:10px;
        box-shadow: 0 5px 15px rgba(0,0,0,0.6);
        border: 3px solid #FFD700; /* Borde Dorado (Trifuerza) */
        min-width: 250px;
        backdrop-filter: blur(5px);
    `;

    const titleBar = document.createElement('div');
    titleBar.innerHTML = '⚔️ HYLIAN COMPANION MANAGER 🧚';
    titleBar.style.cssText = `
        font-weight: bold; font-size: 14px; text-align: center; cursor: grab;
        color: #00FF00; /* Verde de Link */
        background: rgba(30, 80, 50, 0.7);
        text-shadow: 0 0 5px #00FF00;
        margin: -15px -20px 8px -20px; padding: 10px 20px;
        border-bottom: 2px solid #FFD700;
        border-radius: 7px 7px 0 0;
    `;
    hylianContainer.appendChild(titleBar);

    const contentDiv = document.createElement('div');
    contentDiv.style.cssText = `display:flex; flex-direction:column; gap:8px;`;
    hylianContainer.appendChild(contentDiv);

    const hylianInputStyle = `
        flex-grow: 1; padding: 6px 10px; border-radius: 5px;
        border: 2px solid #00FF00; background: rgba(50, 100, 70, 0.8);
        color: #FFD700; font-size: 11px; font-family: monospace;
        transition: all 0.2s ease;
    `;

    function createHylianRow(parent, labelText, inputElement) {
        const wrapper = document.createElement('div');
        wrapper.style.cssText = `display:flex; align-items:center; gap:8px;`;
        const label = document.createElement('span');
        label.textContent = labelText;
        label.style.cssText = `color: #FFFFFF; font-weight: bold; min-width: 80px;`;
        wrapper.appendChild(label);
        wrapper.appendChild(inputElement);
        parent.appendChild(wrapper);
        return { wrapper, label, inputElement };
    }

    // Selector de Enemigo (Target)
    const enemySelect = document.createElement('select');
    enemySelect.style.cssText = hylianInputStyle;
    createHylianRow(contentDiv, '👤 Objetivo (Bokoblin):', enemySelect);

    // Selector de Items
    const itemSelect = document.createElement('select');
    itemSelect.style.cssText = hylianInputStyle;
    for (const name in ZELDA_ITEMS) {
        const opt = document.createElement('option');
        opt.value = ZELDA_ITEMS[name];
        opt.textContent = name;
        itemSelect.appendChild(opt);
    }
    itemSelect.value = ZELDA_ITEMS['Ninguno'];
    createHylianRow(contentDiv, '🗡️ Item/Arma:', itemSelect);

    // Selector de Poderes (Magic/Effects)
    const powerSelect = document.createElement('select');
    powerSelect.style.cssText = hylianInputStyle;
    for (const name in HYLIAN_POWERS) {
        const opt = document.createElement('option');
        opt.value = HYLIAN_POWERS[name];
        opt.textContent = name;
        powerSelect.appendChild(opt);
    }
    powerSelect.value = HYLIAN_POWERS['Ninguno'];
    createHylianRow(contentDiv, '✨ Poder Mágico:', powerSelect);

    // Auto-reset de selectores (solo uno a la vez)
    itemSelect.addEventListener('change', () => {
        if (itemSelect.value !== '') powerSelect.value = HYLIAN_POWERS['Ninguno'];
    });

    powerSelect.addEventListener('change', () => {
        if (powerSelect.value !== '') itemSelect.value = ZELDA_ITEMS['Ninguno'];
    });

    // Medidor de Fuerza/Poder (Intensity)
    const powerInput = document.createElement('input');
    powerInput.type = 'range';
    powerInput.min = '1';
    powerInput.max = '5';
    powerInput.value = '3';
    powerInput.style.cssText = `flex-grow: 1; accent-color: #00FF00;`;
    const powerRow = createHylianRow(contentDiv, '💪 Fuerza (Medidor):', powerInput);

    const powerLabel = document.createElement('span');
    powerLabel.style.cssText = 'color: #FFCC00; font-size: 10px; text-align: center; margin-top: -5px;';
    powerLabel.textContent = `Nivel: ${POWER_INTENSITY_LABELS[powerInput.value - 1]}`;
    contentDiv.appendChild(powerLabel);
    powerInput.addEventListener('input', () => {
        powerLabel.textContent = `Nivel: ${POWER_INTENSITY_LABELS[powerInput.value - 1]}`;
    });


    // Toggle de Repetición (Opcional - "Flujo de Magia")
    const repeatToggle = document.createElement('input');
    repeatToggle.type = 'checkbox';
    repeatToggle.style.cssText = `transform: scale(1.2); accent-color: #FFD700;`;
    const repeatLabel = document.createElement('label');
    repeatLabel.textContent = ' 🔄 Flujo de Magia Continua';
    repeatLabel.style.cssText = `color: #FFD700; font-weight: bold; cursor: pointer;`;
    const repeatWrapper = document.createElement('div');
    repeatWrapper.style.cssText = `display:flex; align-items:center; gap:8px; justify-content: center;`;
    repeatWrapper.appendChild(repeatToggle);
    repeatWrapper.appendChild(repeatLabel);
    contentDiv.appendChild(repeatWrapper);

    // Botón de Activación
    const activateBtn = document.createElement('button');
    activateBtn.textContent = '🔺 ACTIVA PODER / USA ITEM 🔺';
    activateBtn.disabled = true;
    activateBtn.style.cssText = `
        padding: 10px 15px; border-radius: 8px; border: none;
        background: linear-gradient(45deg, #FFD700, #FFCC00); /* Dorado */
        color: #2E8B57; font-weight: bold; font-size: 14px; /* Verde Oscuro */
        cursor: pointer; transition: all 0.2s ease;
        box-shadow: 0 3px 10px rgba(255, 215, 0, 0.5);
        text-shadow: 0 1px 2px rgba(0,0,0,0.3);
        font-family: 'Pixelify Sans', monospace;
        &:hover { background: linear-gradient(45deg, #FFCC00, #FFAC00); transform: translateY(-1px); }
        &:disabled { background: #666; cursor: not-allowed; opacity: 0.5; transform: none; }
    `;
    contentDiv.appendChild(activateBtn);

    // Botón de Parada (Final de la Aventura)
    stopPowerBtn = document.createElement('button');
    stopPowerBtn.textContent = '🛑 GUARDA LA ESPADA (Detener)';
    stopPowerBtn.disabled = true;
    stopPowerBtn.style.cssText = `
        margin-top: 5px; padding: 8px 12px; border-radius: 6px; border: none;
        background: linear-gradient(45deg, #B22222, #8B0000); /* Rojo Oscuro */
        color: white; font-weight: bold; font-size: 12px;
        cursor: pointer; transition: all 0.2s ease;
        box-shadow: 0 2px 8px rgba(178, 34, 34, 0.4);
        font-family: 'Pixelify Sans', monospace;
        &:hover { background: linear-gradient(45deg, #8B0000, #550000); transform: translateY(-1px); }
        &:disabled { background: #666; cursor: not-allowed; opacity: 0.5; transform: none; }
    `;
    contentDiv.appendChild(stopPowerBtn);

    document.body.appendChild(hylianContainer);

    /* ----------------------------------------------------------------------------------
    //  NÚCLEO DE DIBUJO HYLIAN
    // ---------------------------------------------------------------------------------- */

    /**
     * Envía el comando de dibujo (Drawcmd) a través del WebSocket.
     */
    function sendZeldaDrawCommand(x1, y1, x2, y2, color, thickness) {
        x1 = Math.round(x1);
        y1 = Math.round(y1);
        x2 = Math.round(x2); y2 = Math.round(y2);

        if (ctx && canvas) {
            ctx.strokeStyle = color;
            ctx.lineWidth = thickness;
            ctx.lineCap = 'round';
            ctx.lineJoin = 'round';
            ctx.beginPath();
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.stroke();
        }

        if (!socket || !canvas) return;

        // Conversión a coordenadas normalizadas para Drawaria
        const normX1 = (x1 / canvas.width).toFixed(4);
        const normY1 = (y1 / canvas.height).toFixed(4);
        const normX2 = (x2 / canvas.width).toFixed(4);
        const normY2 = (y2 / canvas.height).toFixed(4);

        const cmd = `42["drawcmd",0,[${normX1},${normY1},${normX2},${normY2},false,${0 - thickness},"${color}",0,0,{}]]`;
        socket.send(cmd);
    }

    /**
     * Dibuja el pixel art de Zelda definido en HYLIAN_PIXEL_ASSETS en la posición del objetivo.
     */
    function drawPixelArt(x, y, asset, sizeMultiplier = 1) {
        const { art, colors } = asset;
        const pixelSize = 5 * sizeMultiplier;

        const height = art.length;
        const width = art[0].length;

        const startX = x - (width * pixelSize) / 2;
        const startY = y - (height * pixelSize) / 2;

        for (let row = 0; row < height; row++) {
            for (let col = 0; col < width; col++) {
                const char = art[row][col];
                const color = colors[char];

                if (color) {
                    const pX = startX + col * pixelSize;
                    const pY = startY + row * pixelSize;

                    // Dibuja el pixel como un punto grande (simula un cuadrado rellenado)
                    sendZeldaDrawCommand(pX, pY, pX + 1, pY + 1, color, pixelSize);
                }
            }
        }
    }

    // Obtener coordenadas del jugador objetivo
    function getPlayerCoords(playerId) {
        const avatar = document.querySelector(`.spawnedavatar[data-playerid="${playerId}"]`);
        if (!avatar || !canvas) return null;

        const cRect = canvas.getBoundingClientRect();
        const aRect = avatar.getBoundingClientRect();

        return {
            x: Math.round((aRect.left - cRect.left) + (aRect.width / 2)),
            y: Math.round((aRect.top - cRect.top) + (aRect.height / 2)),
            width: aRect.width,
            height: aRect.height
        };
    }

    /* ----------------------------------------------------------------------------------
    //  FUNCIONES DE ARMAS ZELDA (COMPLETADAS)
    // ---------------------------------------------------------------------------------- */

    // 1. Espada Maestra (Ataque) - "Sword Beam"
    async function masterSwordBeam(playerId, intensity = 3) {
        if (stopSignal) return;
        console.log(`⚔️ ¡Link ha desenvainado la Espada Maestra! ¡SWORD BEAM!`);

        const target = getPlayerCoords(playerId);
        if (!target) return;

        const startX = canvas.width * 0.5;
        const startY = canvas.height - 50; // Posición de Link (abajo)
        const endX = target.x;
        const endY = target.y;

        const beamThickness = 5 + intensity * 2;
        const beamColor = '#1E90FF'; // Azul de la Espada Maestra

        // Animación del rayo
        for (let i = 0; i < 8; i++) {
            if (stopSignal) break;
            const progress = i / 7;
            const currentX = startX + (endX - startX) * progress;
            const currentY = startY + (endY - startY) * progress;

            // Dibuja la onda azul
            sendZeldaDrawCommand(startX, startY, currentX, currentY, beamColor, beamThickness);
            sendZeldaDrawCommand(currentX, currentY, currentX, currentY, '#FFFFFF', 3); // Brillo en la punta

            await new Promise(r => setTimeout(r, 40));
        }

        // Efecto de impacto: Dibujar Trifuerza
        drawPixelArt(endX, endY, HYLIAN_PIXEL_ASSETS.TRIFORCE, 1.5);
        await new Promise(r => setTimeout(r, 100));
    }

    // 2. Flecha de Luz (Light Arrow)
    async function lightArrow(playerId, intensity = 3) {
        if (stopSignal) return;
        console.log(`🏹 ¡Zelda dispara una Flecha de Luz!`);

        const target = getPlayerCoords(playerId);
        if (!target) return;

        const startX = canvas.width * 0.1;
        const startY = canvas.height * 0.1;
        const endX = target.x;
        const endY = target.y;

        const duration = 800 + intensity * 200;
        const startTime = Date.now();

        while (Date.now() - startTime < duration) {
            if (stopSignal) break;

            // Trazo principal: Blanco y Dorado
            sendZeldaDrawCommand(startX, startY, endX, endY, '#FFFFFF', 4 + intensity);
            sendZeldaDrawCommand(startX, startY, endX, endY, '#FFD700', 2 + intensity);

            // Estela de energía
            for (let i = 0; i < 3; i++) {
                const offsetX = (Math.random() - 0.5) * 5;
                const offsetY = (Math.random() - 0.5) * 5;
                sendZeldaDrawCommand(
                    startX + offsetX, startY + offsetY,
                    endX + offsetX, endY + offsetY,
                    '#ADD8E6', 1
                );
            }
            await new Promise(r => setTimeout(r, 30));
        }

        // Impacto: Ráfaga de luz
        for (let i = 0; i < 8; i++) {
            const angle = (i / 8) * 2 * Math.PI;
            const dist = 10 + intensity * 2;
            sendZeldaDrawCommand(endX, endY, endX + dist * Math.cos(angle), endY + dist * Math.sin(angle), '#FFD700', 3);
        }
    }

    // 3. Bomba (Explosión)
    async function bombExplosion(playerId, intensity = 3) {
        if (stopSignal) return;
        console.log(`💣 ¡Cuidado con el radio de explosión!`);

        const target = getPlayerCoords(playerId);
        if (!target) return;

        const centerX = target.x;
        const centerY = target.y;

        // Anima el fuego/humo de la explosión
        const colors = ['#8B4513', '#FF4500', '#FFD700'];
        const explosionSteps = 15;
        const maxRadius = 60 + intensity * 15;

        for (let step = 0; step < explosionSteps; step++) {
            if (stopSignal) break;
            const progress = step / explosionSteps;
            const currentRadius = maxRadius * progress;
            const particleCount = 15 + intensity * 5;

            for (let p = 0; p < particleCount; p++) {
                const angle = Math.random() * Math.PI * 2;
                const distance = currentRadius * (0.5 + Math.random() * 0.5);
                const x = centerX + distance * Math.cos(angle);
                const y = centerY + distance * Math.sin(angle);
                const color = colors[Math.floor(Math.random() * colors.length)];
                const thickness = Math.max(1, 10 - step);
                sendZeldaDrawCommand(centerX, centerY, x, y, color, thickness);
            }
            await new Promise(r => setTimeout(r, 60));
        }
    }

    // 4. Gancho (Hookshot Draw) - IMPLEMENTADO
    async function hookshotDraw(playerId, intensity = 3) {
        if (stopSignal) return;
        console.log(`🎣 ¡Enganche activado! Atrayendo al enemigo.`);

        const target = getPlayerCoords(playerId);
        if (!target) return;

        const startX = canvas.width / 2;
        const startY = canvas.height - 50;
        const endX = target.x;
        const endY = target.y;

        const chainColor = '#C0C0C0'; // Plata
        const headColor = '#FFD700';  // Dorado

        // Paso 1: Extender la cadena
        for (let i = 0; i < 10; i++) {
            if (stopSignal) break;
            const progress = i / 9;
            const currentX = startX + (endX - startX) * progress;
            const currentY = startY + (endY - startY) * progress;

            sendZeldaDrawCommand(startX, startY, currentX, currentY, chainColor, 2);
            // Dibuja la cabeza del gancho en la punta
            sendZeldaDrawCommand(currentX, currentY, currentX, currentY, headColor, 8);
            await new Promise(r => setTimeout(r, 30));
        }

        // Paso 2: Dibujar el efecto de "enganche"
        for (let i = 0; i < 5; i++) {
            const size = 10 + i * 3;
            sendZeldaDrawCommand(endX, endY, endX, endY, headColor, size);
            await new Promise(r => setTimeout(r, 20));
        }

        // Paso 3: Retraer (Opcional: puedes hacer que dibuje una línea hacia atrás rápidamente si quieres simular un tirón)
        await new Promise(r => setTimeout(r, 200));
    }

    // 5. Gran Spin Attack - IMPLEMENTADO
    async function spinAttack(playerId, intensity = 3) {
        if (stopSignal) return;
        console.log(`🌪️ ¡Gran Spin Attack de Link!`);

        const target = getPlayerCoords(playerId);
        if (!target) return;

        const centerX = target.x;
        const centerY = target.y;
        const maxRadius = 30 + intensity * 10;
        const duration = 800;
        const startTime = Date.now();

        while (Date.now() - startTime < duration) {
            if (stopSignal) break;
            const elapsed = Date.now() - startTime;
            const rotation = elapsed * 0.05; // Velocidad de rotación
            const segments = 12;

            for (let i = 0; i < segments; i++) {
                const angle1 = (i / segments) * 2 * Math.PI + rotation;
                const angle2 = ((i + 1) / segments) * 2 * Math.PI + rotation;

                const r1 = maxRadius * (0.8 + Math.random() * 0.2);
                const r2 = maxRadius * (0.8 + Math.random() * 0.2);

                const x1 = centerX + r1 * Math.cos(angle1);
                const y1 = centerY + r1 * Math.sin(angle1);
                const x2 = centerX + r2 * Math.cos(angle2);
                const y2 = centerY + r2 * Math.sin(angle2);

                sendZeldaDrawCommand(x1, y1, x2, y2, '#00FF00', 4 + intensity); // Espada verde de Link
            }
            await new Promise(r => setTimeout(r, 30));
        }
    }

    // 6. Espada Lanzarrayos (Sword Beam Boost) - IMPLEMENTADO
    async function swordBeamBoost(playerId, intensity = 3) {
        if (stopSignal) return;
        console.log(`✨ ¡Espada Lanzarrayos: Poder del Maestro!`);

        const target = getPlayerCoords(playerId);
        if (!target) return;

        // Se usa la función base, pero con un triple rayo
        await masterSwordBeam(playerId, intensity * 1.5);

        // Rayo adicional más grueso y amarillo
        const startX = canvas.width * 0.5;
        const startY = canvas.height - 50;
        const endX = target.x;
        const endY = target.y;

        sendZeldaDrawCommand(startX, startY, endX, endY, '#FFD700', 4);
        sendZeldaDrawCommand(startX + 10, startY, endX + 10, endY, '#1E90FF', 4);

        await new Promise(r => setTimeout(r, 200));
        // Dibujar Trifuerza más grande
        drawPixelArt(endX, endY + 20, HYLIAN_PIXEL_ASSETS.TRIFORCE, 2);
    }


    /* ----------------------------------------------------------------------------------
    //  FUNCIONES DE PODERES HYLIAN (COMPLETADAS)
    // ---------------------------------------------------------------------------------- */

    // 1. Escudo Hylian (Defensa)
    async function hylianShieldDefense(playerId, intensity = 3) {
        if (stopSignal) return;
        console.log(`🛡️ ¡El Escudo Hylian brilla! Defensa activa.`);

        const target = getPlayerCoords(playerId);
        if (!target) return;

        const duration = 4000;
        const startTime = Date.now();

        while (Date.now() - startTime < duration) {
            if (stopSignal) break;

            const elapsed = Date.now() - startTime;
            const shieldRadius = 40 + intensity * 5;
            const pulse = Math.sin(elapsed * 0.015) * 3;

            drawPixelArt(target.x, target.y - 10, HYLIAN_PIXEL_ASSETS.HYLIAN_SHIELD, 1.5);

            // Efecto de parry (destello blanco/azul)
            for (let i = 0; i < 4; i++) {
                const angle = Math.random() * Math.PI * 2;
                const dist = shieldRadius + pulse;
                sendZeldaDrawCommand(target.x, target.y, target.x + dist * Math.cos(angle), target.y + dist * Math.sin(angle), '#ADD8E6', 1);
            }

            await new Promise(r => setTimeout(r, 100));
        }
    }

    // 2. Hada de Recuperación
    async function recoveryFairy(playerId, intensity = 3) {
        if (stopSignal) return;
        console.log(`🧚 ¡Hey, Listen! El hada te restaura la vida.`);

        const target = getPlayerCoords(playerId);
        if (!target) return;

        const fairyDuration = 2000;
        const startTime = Date.now();

        while (Date.now() - startTime < fairyDuration) {
            if (stopSignal) break;
            const elapsed = Date.now() - startTime;
            const yOffset = Math.sin(elapsed * 0.01) * 10;

            drawPixelArt(target.x - 40, target.y - 50 + yOffset, HYLIAN_PIXEL_ASSETS.RECOVERY_FAIRY, 1.2);

            if (elapsed % 500 < 250) {
                drawPixelArt(target.x, target.y + 30, HYLIAN_PIXEL_ASSETS.HEART_CONTAINER, 1.5);
            }

            await new Promise(r => setTimeout(r, 100));
        }

        for (let size = 1.5; size < 2.5; size += 0.2) {
            drawPixelArt(target.x, target.y + 30, HYLIAN_PIXEL_ASSETS.HEART_CONTAINER, size);
            await new Promise(r => setTimeout(r, 50));
        }
    }

    // 3. Contenedor de Corazón (Vida Extendida)
    async function heartContainerBoost(playerId, intensity = 3) {
        if (stopSignal) return;
        console.log(`💖 ¡Felicidades! Has ganado un Contenedor de Corazón.`);

        const target = getPlayerCoords(playerId);
        if (!target) return;

        const centerX = target.x;
        const centerY = target.y;

        for (let i = 0; i < 20; i++) {
            if (stopSignal) break;
            const size = 1 + i * 0.1;
            drawPixelArt(centerX, centerY, HYLIAN_PIXEL_ASSETS.HEART_CONTAINER, size);
            await new Promise(r => setTimeout(r, 50));
        }

        drawPixelArt(centerX, centerY - 80, HYLIAN_PIXEL_ASSETS.TRIFORCE, 2);
        await new Promise(r => setTimeout(r, 500));
    }

    // 4. Ocarina de Tiempo (Stun) - IMPLEMENTADO
    async function ocarinaStun(playerId, intensity = 3) {
        if (stopSignal) return;
        console.log(`🌀 ¡Tocando la Canción del Sol! Enemigo congelado.`);

        const target = getPlayerCoords(playerId);
        if (!target) return;

        const centerX = target.x;
        const centerY = target.y;
        const duration = 2500;
        const startTime = Date.now();
        const colors = ['#00FFFF', '#ADD8E6'];

        while (Date.now() - startTime < duration) {
            if (stopSignal) break;
            const elapsed = Date.now() - startTime;
            const maxRadius = 50 + intensity * 10;
            const pulse = Math.sin(elapsed * 0.02) * 5;

            // Notas musicales girando
            const noteRadius = 30 + pulse;
            const noteAngle = elapsed * 0.01;
            const x = centerX + noteRadius * Math.cos(noteAngle);
            const y = centerY + noteRadius * Math.sin(noteAngle);
            drawPixelArt(x, y, HYLIAN_PIXEL_ASSETS.MUSIC_NOTE, 1.5);
            drawPixelArt(centerX - (x - centerX), centerY - (y - centerY), HYLIAN_PIXEL_ASSETS.MUSIC_NOTE, 1.5);

            // Onda de choque azul
            for (let i = 0; i < 3; i++) {
                const r = maxRadius * (i / 3) + pulse;
                for (let seg = 0; seg < 10; seg++) {
                    const angle1 = (seg / 10) * 2 * Math.PI;
                    const angle2 = ((seg + 1) / 10) * 2 * Math.PI;

                    const x1 = centerX + r * Math.cos(angle1);
                    const y1 = centerY + r * Math.sin(angle1);
                    const x2 = centerX + r * Math.cos(angle2);
                    const y2 = centerY + r * Math.sin(angle2);
                    sendZeldaDrawCommand(x1, y1, x2, y2, colors[i % 2], 1);
                }
            }
            await new Promise(r => setTimeout(r, 80));
        }
    }

    // 5. Varita de Fuego (Fire Rod) - IMPLEMENTADO
    async function fireRod(playerId, intensity = 3) {
        if (stopSignal) return;
        console.log(`🔥 ¡El Fuego de Din se desata!`);

        const target = getPlayerCoords(playerId);
        if (!target) return;

        const startX = 50; // Inicia desde la izquierda
        const endX = target.x;
        const centerY = target.y;

        const flameColors = ['#FF4500', '#FF8C00', '#FFD700'];
        const numFlames = 15 + intensity * 5;

        for (let i = 0; i < numFlames; i++) {
            if (stopSignal) break;

            const progress = i / numFlames;
            const currentX = startX + (endX - startX) * progress;
            const currentY = centerY + (Math.random() - 0.5) * 50; // Movimiento vertical de la flama

            // Dibujar la flama como múltiples líneas
            for (let j = 0; j < 5; j++) {
                const color = flameColors[j % flameColors.length];
                const thickness = Math.max(1, 10 - j * 2 + intensity);
                const x2 = currentX + (Math.random() - 0.5) * 20;
                const y2 = currentY + (Math.random() - 0.5) * 20;
                sendZeldaDrawCommand(currentX, currentY, x2, y2, color, thickness);
            }

            await new Promise(r => setTimeout(r, 40));
        }

        // Impacto final
        await bombExplosion(playerId, intensity * 0.5); // Explosión de fuego menor
    }

    /* ----------------------------------------------------------------------------------
    //  SISTEMA DE GESTIÓN DE JUGADORES (Hylian List) - (Mismo código, no se modifica)
    // ---------------------------------------------------------------------------------- */

    let lastPlayerList = new Set();
    let isUpdatingList = false;

    function refreshPlayerList() {
        if (isUpdatingList) return;

        const currentPlayers = new Set();
        const playerRows = document.querySelectorAll('.playerlist-row[data-playerid]');

        playerRows.forEach(row => {
            if (row.dataset.self !== 'true' && row.dataset.playerid !== '0') {
                const name = row.querySelector('.playerlist-name a')?.textContent || `Player ${row.dataset.playerid}`;
                currentPlayers.add(`${row.dataset.playerid}:${name}`);
            }
        });

        const playersChanged = currentPlayers.size !== lastPlayerList.size ||
              ![...currentPlayers].every(player => lastPlayerList.has(player));

        if (!playersChanged) return;

        isUpdatingList = true;
        const previousSelection = enemySelect.value;

        enemySelect.innerHTML = '';
        enemySelect.textContent = '👤 Link'; // Nombre por defecto si es Link

        playerRows.forEach(row => {
            if (row.dataset.self === 'true') return;
            if (row.dataset.playerid === '0') return;
            const name = row.querySelector('.playerlist-name a')?.textContent || `Enemy ${row.dataset.playerid}`;
            const opt = document.createElement('option');
            opt.value = row.dataset.playerid;
            // Muestra nombre de jugador como "Bokoblin" o "Ganondorf"
            const zeldaName = name.includes('Ganondorf') ? '😈 Ganondorf' : '👹 Bokoblin';
            opt.textContent = `🎯 ${zeldaName} (${name})`;
            enemySelect.appendChild(opt);
        });

        if (previousSelection) {
            enemySelect.value = previousSelection;
        }

        lastPlayerList = new Set(currentPlayers);
        activateBtn.disabled = enemySelect.children.length === 0;
        isUpdatingList = false;
    }


    /* ----------------------------------------------------------------------------------
    //  EVENTOS PRINCIPALES DE HYRULE
    // ---------------------------------------------------------------------------------- */

    // Arrastrar ventana
    let isDragging = false;
    let offsetX, offsetY;
    titleBar.addEventListener('mousedown', (e) => {
        isDragging = true;
        offsetX = e.clientX - hylianContainer.getBoundingClientRect().left;
        offsetY = e.clientY - hylianContainer.getBoundingClientRect().top;
    });
    document.addEventListener('mousemove', (e) => {
        if (!isDragging) return;
        let newX = e.clientX - offsetX;
        let newY = e.clientY - offsetY;
        newX = Math.max(0, Math.min(newX, window.innerWidth - hylianContainer.offsetWidth));
        newY = Math.max(0, Math.min(newY, window.innerHeight - hylianContainer.offsetHeight));
        hylianContainer.style.left = newX + 'px';
        hylianContainer.style.top = newY + 'px';
    });
    document.addEventListener('mouseup', () => {
        isDragging = false;
    });

    // Botón de parada de emergencia (Guarda la espada)
    stopPowerBtn.addEventListener('click', () => {
        console.log('🛑 ¡Aventura terminada! "Game Over" de Zelda.');
        stopSignal = true;

        if (activePowerInterval) {
            clearInterval(activePowerInterval);
            activePowerInterval = null;
        }

        activateBtn.textContent = '🔺 ACTIVA PODER / USA ITEM 🔺';
        activateBtn.style.background = 'linear-gradient(45deg, #FFD700, #FFCC00)';
        activateBtn.disabled = false;
        stopPowerBtn.disabled = true;
    });

    // Botón principal de activación
    activateBtn.addEventListener('click', async () => {
        const playerId = enemySelect.value;
        if (!playerId) {
            alert('🎯 ¡Escoge un Bokoblin/Objetivo en el que enfocarte!');
            return;
        }

        const selectedItem = itemSelect.value;
        const selectedPower = powerSelect.value;
        const intensity = parseInt(powerInput.value);

        if (activePowerInterval) {
            console.log('Deteniendo Flujo de Magia...');
            stopPowerBtn.click();
            return;
        }

        let actionToExecute = null;
        let powerName = '';

        // Mapeo COMPLETO de Items/Poderes a Funciones
        if (selectedItem && selectedItem.startsWith('weapon:')) {
            switch (selectedItem) {
                case 'weapon:master_sword': actionToExecute = () => masterSwordBeam(playerId, intensity); powerName = 'Espada Maestra'; break;
                case 'weapon:light_arrow': actionToExecute = () => lightArrow(playerId, intensity); powerName = 'Flecha de Luz'; break;
                case 'weapon:bomb_explosion': actionToExecute = () => bombExplosion(playerId, intensity); powerName = 'Bomba'; break;
                case 'weapon:hookshot_draw': actionToExecute = () => hookshotDraw(playerId, intensity); powerName = 'Gancho'; break; // Mapeo Corregido
                case 'weapon:spin_attack': actionToExecute = () => spinAttack(playerId, intensity); powerName = 'Spin Attack'; break; // Mapeo Corregido
                case 'weapon:sword_beam_boost': actionToExecute = () => swordBeamBoost(playerId, intensity); powerName = 'Master Sword Boost'; break; // Mapeo Corregido
                default:
                    console.log('⚠️ ¡Ese Item de Zelda no está en tu inventario!');
                    return;
            }
        } else if (selectedPower && selectedPower.startsWith('effect:')) {
            switch (selectedPower) {
                case 'effect:hylian_shield': actionToExecute = () => hylianShieldDefense(playerId, intensity); powerName = 'Escudo Hylian'; break;
                case 'effect:recovery_fairy': actionToExecute = () => recoveryFairy(playerId, intensity); powerName = 'Hada'; break;
                case 'effect:heart_container_boost': actionToExecute = () => heartContainerBoost(playerId, intensity); powerName = 'Contenedor de Corazón'; break;
                case 'effect:ocarina_stun': actionToExecute = () => ocarinaStun(playerId, intensity); powerName = 'Ocarina Stun'; break; // Mapeo Corregido
                case 'effect:fire_rod': actionToExecute = () => fireRod(playerId, intensity); powerName = 'Varita de Fuego'; break; // Mapeo Corregido
                default:
                    console.log('⚠️ ¡Ese Poder Mágico no está cargado!');
                    return;
            }
        } else {
            alert('🔺 ¡Debes seleccionar un Item o Poder Mágico de Zelda!');
            return;
        }

        stopSignal = false;
        activateBtn.disabled = true;
        stopPowerBtn.disabled = false;

        try {
            if (repeatToggle.checked) {
                activateBtn.textContent = '🔄 DETENER FLUJO MÁGICO';
                activateBtn.style.background = 'linear-gradient(45deg, #B22222, #8B0000)';
                activateBtn.disabled = false;

                console.log(`🔥 ¡Iniciando Flujo de Magia Continua de ${powerName}!`);

                const continuousAction = async () => {
                    if (stopSignal || !repeatToggle.checked) {
                        if (activePowerInterval) clearInterval(activePowerInterval);
                        activePowerInterval = null;
                        activateBtn.textContent = '🔺 ACTIVA PODER / USA ITEM 🔺';
                        activateBtn.style.background = 'linear-gradient(45deg, #FFD700, #FFCC00)';
                        stopPowerBtn.disabled = true;
                        return;
                    }

                    try {
                        await actionToExecute();
                    } catch (error) {
                        console.error(`Error durante el Flujo de Magia (${powerName}):`, error);
                    }
                };

                await continuousAction();
                if (!stopSignal) {
                    activePowerInterval = setInterval(continuousAction, 2500); // Intervalo de 2.5s
                }
            } else {
                console.log(`💥 Ejecutando ${powerName} una sola vez...`);
                await actionToExecute();
            }
        } finally {
            if (!activePowerInterval) {
                activateBtn.disabled = false;
                stopPowerBtn.disabled = true;
            }
        }
    });

    // Observar cambios en la lista de jugadores (para actualizar Targets)
    const playerListElement = document.getElementById('playerlist');
    if (playerListElement) {
        new MutationObserver(() => {
            setTimeout(refreshPlayerList, 100);
        }).observe(playerListElement, {
            childList: true,
            subtree: true,
            attributes: true,
            attributeFilter: ['data-playerid']
        });
    }

    // Limpieza al cerrar (Despide al compañero)
    window.addEventListener('beforeunload', () => {
        if (activePowerInterval) {
            clearInterval(activePowerInterval);
            activePowerInterval = null;
        }
        stopSignal = true;
        console.log('¡Gracias por jugar! Regresa a Drawaria cuando quieras aventurar de nuevo. -El Compadre Hylian.');
    });

    // Inicialización (Muestra el mensaje de inicio)
    refreshPlayerList();
    console.log('✨ ¡Bienvenido a Hyrule! The Hylian Companion Mod cargado exitosamente. ¡Que la Trifuerza te guíe! ✨');

})();