Drawaria JSAB Bosses Drawings Collection

Draw every boss of JSAB with details and instantly

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name Drawaria JSAB Bosses Drawings Collection
// @namespace http://tampermonkey.net/
// @version 7.2
// @description Draw every boss of JSAB with details and instantly
// @author       YouTubeDrawaria
// @include	 https://drawaria.online/*
// @include	 https://*.drawaria.online/*
// @include      https://drawaria.online*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=drawaria.online/room/
// @grant        GM_registerMenuCommand
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const canvas = document.getElementById('canvas');
    const ctx = canvas?.getContext('2d');
    let socket;

    // === CONSTANTES DE DISEÑO GENERALES Y COMPARTIDAS ===
    const corruptionColor = '#FF008C'; // Magenta Brillante
    const darkCorruptionColor = '#B3005D'; // Magenta Oscuro
    const innerColor = '#000000';      // Negro Puro
    const highlightColor = '#FFFFFF';   // Blanco (para ojos de Fresh/LltNF)

    // Parámetros de lienzo base
    const centerX_Factor = 0.5;
    const centerY_Factor = 0.6;
    const radiusFactor = 0.35; // Radio base relativo a la altura del canvas
    const outlineThickness = 12;

    let isDrawing = false;
    let isStopped = false;

    // === UTILITIES Y HOOKS (COMPARTIDOS) ===

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

    function getCanvasSize() {
        return { width: canvas.width, height: canvas.height };
    }

    function clamp(value, min, max) {
        return Math.min(Math.max(value, min), max);
    }

    // Función central que envía el comando de dibujo al servidor Y DIBUJA LOCALMENTE
    function sendDrawCommand(x1, y1, x2, y2, color, thickness) {
        if (isStopped || !socket || !canvas || !ctx) return;

        // 1. DIBUJO LOCAL (Instantáneo en tu pantalla)
        ctx.strokeStyle = color;
        ctx.lineWidth = thickness;
        ctx.lineCap = 'round';
        ctx.lineJoin = 'round';
        ctx.beginPath();
        ctx.moveTo(x1, y1);
        ctx.lineTo(x2, y2);
        ctx.stroke();

        // 2. ENVÍO AL SERVIDOR (Normalizar coordenadas a valores 0-1)
        const normX1 = (clamp(x1, -100, canvas.width + 100) / canvas.width).toFixed(4);
        const normY1 = (clamp(y1, 0, canvas.height) / canvas.height).toFixed(4);
        const normX2 = (clamp(x2, -100, canvas.width + 100) / canvas.width).toFixed(4);
        const normY2 = (clamp(y2, 0, canvas.height) / canvas.height).toFixed(4);

        // thickness se envía como negativo para indicar grosor
        const command = `42["drawcmd",0,[${normX1},${normY1},${normX2},${normY2},false,${0 - thickness},"${color}",0,0,{}]]`;
        socket.send(command);
    }

    // Dibuja una línea simple (SÍNCRONO)
    function drawLine(startX, startY, endX, endY, color, thickness) {
        sendDrawCommand(startX, startY, endX, endY, color, thickness);
    }

    // Dibuja un triángulo sólido (relleno) usando tres líneas gruesas (SÍNCRONO)
    function drawSolidTriangle(p1, p2, p3, color, baseThickness) {
        // Usar un grosor grande para asegurar que se rellene
        const t = baseThickness * 3;
        drawLine(p1.x, p1.y, p2.x, p2.y, color, t);
        drawLine(p2.x, p2.y, p3.x, p3.y, color, t);
        drawLine(p3.x, p3.y, p1.x, p1.y, color, t);
    }

    // Dibuja un círculo sólido (relleno) usando la técnica de scanline (SÍNCRONO)
    function drawSolidCircle(centerX, centerY, radius, color, lineDensity = 5) {
        const lineThickness = lineDensity * 2;
        const squaredRadius = Math.pow(radius, 2);
        for (let y = centerY - radius; y <= centerY + radius; y += lineDensity) {
            if (isStopped) return;
            const dy = y - centerY;
            const squaredDY = Math.pow(dy, 2);
            if (squaredRadius < squaredDY) continue;

            const dx = Math.sqrt(squaredRadius - squaredDY);
            const startX = centerX - dx;
            const endX = centerX + dx;

            if (endX > startX) {
                drawLine(startX, y, endX, y, color, lineThickness);
            }
        }
    }

    // Dibuja el contorno circular (SÍNCRONO)
    function drawCircularOutline(coords, thickness, color) {
        if (isStopped) return;
        const { centerX, centerY, radius } = coords;
        const numSegments = 60;
        let prevX = 0, prevY = 0;

        for (let i = 0; i <= numSegments; i++) {
            if (isStopped) break;
            const angle = (i / numSegments) * 2 * Math.PI;
            const currentX = centerX + radius * Math.cos(angle);
            const currentY = centerY + radius * Math.sin(angle);

            if (i > 0) {
                drawLine(prevX, prevY, currentX, currentY, color, thickness);
            }
            prevX = currentX;
            prevY = currentY;
        }
    }

    // === FUNCIONES DE COORDENADAS BASE ===
    function calculateBaseCoordinates() {
        const size = getCanvasSize();
        const radius = Math.floor(size.height * radiusFactor);
        const centerX = Math.floor(size.width * centerX_Factor);
        const centerY = Math.floor(size.height * centerY_Factor);
        return { centerX, centerY, radius, size };
    }


    // =================================================================
    // === V6.1 ORIGINAL (EL JEFE DE CEÑO Y COLMILLOS - MANTENIDO INTACTO)
    // =================================================================

    function calculateSmartCoordinates_V61() {
        const size = getCanvasSize();
        const radius = Math.floor(size.height * radiusFactor);
        const centerX = Math.floor(size.width * centerX_Factor);
        const centerY = Math.floor(size.height * centerY_Factor);

        // Ajuste: Aumento el grosor del contorno magenta de cuernos.
        const HORN_OUTLINE_THICKNESS = 10;

        // AJUSTE: Grosor base para los colmillos rellenos (se multiplica por 3 en drawSolidTriangle)
        const FANG_BASE_THICKNESS = 8;

        // AJUSTE CLAVE: Mover el ceño un número fijo de píxeles hacia arriba (positivo = arriba)
        const BROW_TOP_ADJUSTMENT = -40;

        return {
            centerX,
            centerY,
            radius,

            // Cuernos
            hornBaseY: centerY - radius + Math.floor(radius * 0.05),
            hornTipY: centerY - radius - Math.floor(radius * 0.08),
            hornWidth: Math.floor(radius * 0.08),
            hornSpacing: Math.floor(radius * 0.70),
            hornOutlineThickness: HORN_OUTLINE_THICKNESS,

            // Ceño (¡Posición MUCHO más alta, V normal!)
            browCenterRadius: Math.floor(radius * 0.09),

            // Base (Lados de la 'V'). Factor ajustado para posición alta.
            browBaseY: centerY - Math.floor(radius * 0.55),

            // Punta (Centro de la 'V'). Factor más alto que la base para la forma de 'V' normal,
            // más el AJUSTE que lo sube aún más.
            browTipY: centerY - Math.floor(radius * 0.65) - BROW_TOP_ADJUSTMENT,

            browWidth: Math.floor(radius * 0.25),

            // Colmillos (AJUSTE: HACIÉNDOLOS MÁS PEQUEÑOS)
            fangY: centerY + Math.floor(radius * 0.45), // Un poco más abajo
            fangHeight: Math.floor(radius * 0.07),    // Más cortos (antes 0.15)
            fangSpacing: Math.floor(radius * 0.25),   // Más juntos (antes 0.30)
            fangWidth: Math.floor(radius * 0.05),     // Más delgados (antes 0.10)
            fangBaseThickness: FANG_BASE_THICKNESS, // Grosor base para relleno
        };
    }

    function drawBossDetails_V61(coords) {
        if (isStopped) return;
        const { centerX, hornTipY, hornBaseY, hornWidth, hornSpacing, hornOutlineThickness, browCenterRadius, browTipY, browBaseY, browWidth, fangY, fangHeight, fangSpacing, fangWidth, fangBaseThickness } = coords;
        const detailThickness = 10;

        // FASE 3A: CUERNOS (RELLENO NEGRO Y CONTORNO MAGENTA V6.1)
        const hornDraw = (sign) => {
            const hl_p1 = { x: centerX + sign * hornSpacing / 2, y: hornBaseY };
            const hl_p2 = { x: centerX + sign * (hornSpacing / 2 + hornWidth), y: hornBaseY };
            const hl_p3 = { x: centerX + sign * (hornSpacing / 2 + (hornWidth / 2)), y: hornTipY };
            drawSolidTriangle(hl_p1, hl_p2, hl_p3, innerColor, detailThickness);
            drawSolidTriangle(hl_p1, hl_p2, hl_p3, corruptionColor, hornOutlineThickness);
        };
        hornDraw(-1); hornDraw(1);

        // FASE 3B: CEÑO AGRESIVO (V6.1)
        drawSolidCircle(centerX, browBaseY + 40, browCenterRadius, corruptionColor, 3); // Nariz
        const aggressiveThickness = detailThickness * 1.5;
        drawLine(centerX - browWidth / 2, browBaseY, centerX, browTipY, corruptionColor, aggressiveThickness);
        drawLine(centerX + browWidth / 2, browBaseY, centerX, browTipY, corruptionColor, aggressiveThickness);

        // FASE 3C: COLMILLOS INFERIORES (AJUSTADOS Y RELLENOS)
        const fangDraw = (sign) => {
            const fl_p1 = { x: centerX + sign * fangSpacing / 2, y: fangY };
            const fl_p2 = { x: centerX + sign * (fangSpacing / 2 - sign * fangWidth), y: fangY };
            const fl_p3 = { x: centerX + sign * (fangSpacing / 2 - sign * (fangWidth / 2)), y: fangY + fangHeight };
            drawSolidTriangle(fl_p1, fl_p2, fl_p3, corruptionColor, fangBaseThickness);
        };
        fangDraw(-1); fangDraw(1);
    }

    // FUNCIÓN PRINCIPAL V6.1
    function drawJSABBoss_V61() {
        if (isDrawing) { alert('Ya está en curso un dibujo. Presiona "Parar" para cancelar.'); return; }
        if (!socket || !canvas || !ctx) { alert('No se detectó conexión o canvas. Asegúrate de estar en una sala de juego.'); return; }

        isDrawing = true;
        isStopped = false;
        const statusDiv = document.getElementById('boss-status') || createStatusDiv('boss-status');

        try {
            updateStatus(statusDiv, `🚀 JEFE JSAB: Iniciando Corrupción V6.1 (Instantáneo)...`, corruptionColor);
            const coords = calculateSmartCoordinates_V61();

            // 1. RELLENO INTERIOR NEGRO SÓLIDO
            const innerRadius = coords.radius - Math.floor(outlineThickness / 2);
            drawSolidCircle(coords.centerX, coords.centerY, innerRadius, innerColor, 5);
            updateStatus(statusDiv, "⚫ FASE 1: Relleno Negro Completo...", innerColor);

            // 2. CONTORNO CIRCULAR MAGENTA
            drawCircularOutline(coords, outlineThickness, corruptionColor);
            updateStatus(statusDiv, "⭕ FASE 2: Contorno de Corrupción Magenta...", corruptionColor);

            // 3. DETALLES FACIALES SÓLIDOS Y PRECISOS (V6.1)
            drawBossDetails_V61(coords);
            updateStatus(statusDiv, "👁️ FASE 3: Dibujando detalles precisos (V6.1)...", corruptionColor);

            updateStatus(statusDiv, "🏆 ¡JEFE JSAB DIBUJADO AL INSTANTE! 🎯", "#006400", true);
            setTimeout(() => { if (statusDiv.parentNode) { statusDiv.style.opacity = 0; setTimeout(() => statusDiv.remove(), 500); } }, 3000);

        } catch (error) {
            console.error("Error al dibujar jefe JSAB V6.1:", error);
            updateStatus(statusDiv, `❌ Error: ${error.message}`, "#B22222", true);
        } finally {
            isDrawing = false;
        }
    }


    // =================================================================
    // === V7.1 NUEVOS JEFES (GEOMETRÍA DE ALTA PRECISIÓN)
    // =================================================================

    // BOSS A: Long Live The New Fresh (LltNF) / The Corrupted - (IMAGEN 1 - Ojos y Sonrisa Rayada)
    function drawLltNF_Image1(coords) {
        const { centerX, centerY, radius: R } = coords;

        // --- CÁLCULO DE COORDENADAS ESPECÍFICAS ---
        const HORN_TIP_Y = centerY - R - Math.floor(R * 0.08);
        const HORN_BASE_Y = centerY - R + Math.floor(R * 0.05);
        const HORN_WIDTH = Math.floor(R * 0.08);
        const HORN_SPACING = Math.floor(R * 0.70);
        const HORN_OUTLINE_T = 10;
        const DETAIL_T = 10;
        const L_EYE_R = Math.floor(R * 0.16); // Ojo Izquierdo Grande
        const R_EYE_R = Math.floor(R * 0.09); // Ojo Derecho Pequeño
        const EYE_BASE_Y = centerY - Math.floor(R * 0.15);
        const L_EYE_X = centerX - Math.floor(R * 0.22);
        const R_EYE_X = centerX + Math.floor(R * 0.25);
        const MOUTH_W = Math.floor(R * 0.55); // Ancho de la sonrisa
        const MOUTH_Y = centerY + Math.floor(R * 0.22); // Centro de la boca
        const MOUTH_STRIPES = 12;

        // 1. Círculo Base (Relleno Negro y Contorno Magenta)
        drawSolidCircle(centerX, centerY, R - Math.floor(outlineThickness / 2), innerColor);
        drawCircularOutline(coords, outlineThickness, corruptionColor);

        // 2. Cuernos (Triángulos Rellenos de Negro con Borde Magenta)
        const hornDraw = (sign) => {
            const h_p1 = { x: centerX + sign * HORN_SPACING / 2, y: HORN_BASE_Y };
            const h_p2 = { x: centerX + sign * (HORN_SPACING / 2 + HORN_WIDTH), y: HORN_BASE_Y };
            const h_p3 = { x: centerX + sign * (HORN_SPACING / 2 + (HORN_WIDTH / 2)), y: HORN_TIP_Y };
            drawSolidTriangle(h_p1, h_p2, h_p3, innerColor, DETAIL_T);
            drawSolidTriangle(h_p1, h_p2, h_p3, corruptionColor, HORN_OUTLINE_T);
        };
        hornDraw(-1); hornDraw(1);

        // 3. Ojos Desproporcionados
        drawSolidCircle(L_EYE_X, EYE_BASE_Y, L_EYE_R, highlightColor, 3);
        drawSolidCircle(R_EYE_X, EYE_BASE_Y, R_EYE_R, highlightColor, 3);

        // 4. Sonrisa Rayada (Magenta)
        const stripeThickness = Math.floor((MOUTH_W / MOUTH_STRIPES) * 0.5);
        const stripeSpacing = MOUTH_W / MOUTH_STRIPES;
        const mouthR = Math.floor(R * 0.45); // Radio para la curva de la boca

        for (let i = 0; i < MOUTH_STRIPES; i++) {
            const x = centerX - MOUTH_W / 2 + i * stripeSpacing + stripeSpacing / 2;
            const dx = x - centerX;

            // Usamos la curva del círculo para determinar el punto final de la línea
            const dyFromCenter = Math.sqrt(Math.pow(mouthR, 2) - Math.pow(dx, 2));
            const endY = centerY + Math.floor(R * 0.3) + dyFromCenter; // Ajuste la posición Y para que la boca esté en la parte inferior

            const startY = centerY + Math.floor(R * 0.05); // Comienza por debajo del centro del círculo

            drawLine(x, startY, x, endY, corruptionColor, stripeThickness);
        }
    }


    // BOSS B: Barracuda (El Triángulo)
    function drawBarracuda(coords) {
        const { centerX, centerY, radius } = coords;
        const R = radius * 1.2;
        const H = R * 1.732 / 2;

        // Puntos del triángulo centralizado
        const p_top = { x: centerX, y: centerY - H * 0.6 };
        const p_bl = { x: centerX - R / 2, y: centerY + H * 0.4 };
        const p_br = { x: centerX + R / 2, y: centerY + H * 0.4 };

        // 1. Capa Externa Oscura (Relleno grueso)
        drawSolidTriangle(p_top, p_bl, p_br, darkCorruptionColor, 15);

        // 2. Capa Interna Brillante (Triángulo más pequeño)
        const innerFactor = 0.8;
        const i_top = { x: centerX, y: p_top.y * innerFactor + centerY * (1 - innerFactor) };
        const i_bl = { x: centerX - (R / 2) * innerFactor, y: p_bl.y * innerFactor + centerY * (1 - innerFactor) };
        const i_br = { x: centerX + (R / 2) * innerFactor, y: p_br.y * innerFactor + centerY * (1 - innerFactor) };
        drawSolidTriangle(i_top, i_bl, i_br, corruptionColor, 15);

        // 3. Núcleo Central (Anillo y Punto)
        const core_R_out = Math.floor(radius * 0.1);
        const core_R_in = Math.floor(radius * 0.05);
        drawSolidCircle(centerX, centerY, core_R_out, innerColor, 3);
        drawSolidCircle(centerX, centerY, core_R_in, corruptionColor, 3);
    }


    // BOSS C: Close To Me (Urchin/Spiky Blob)
    function drawCloseToMe(coords) {
        const { centerX, centerY, radius } = coords;
        const R = radius * 0.6;
        const NUM_SPIKES = 14;
        const SPIKE_LENGTH = Math.floor(R * 0.3);

        // 1. Cuerpo Principal (Círculo Sólido Magenta)
        drawSolidCircle(centerX, centerY, R, corruptionColor, 5);

        // 2. Spikes (Triángulos Alrededor)
        for (let i = 0; i < NUM_SPIKES; i++) {
            if (isStopped) break;
            const angle = (i / NUM_SPIKES) * 2 * Math.PI;
            const p1 = { x: centerX + R * Math.cos(angle - 0.1), y: centerY + R * Math.sin(angle - 0.1) };
            const p2 = { x: centerX + R * Math.cos(angle + 0.1), y: centerY + R * Math.sin(angle + 0.1) };
            const tipX = centerX + (R + SPIKE_LENGTH) * Math.cos(angle);
            const tipY = centerY + (R + SPIKE_LENGTH) * Math.sin(angle);
            const p3 = { x: tipX, y: tipY };
            drawSolidTriangle(p1, p2, p3, corruptionColor, 8);
        }

        // 3. Ojos y Boca (Relleno Negro)
        const browH = Math.floor(R * 0.08);
        const browW = Math.floor(R * 0.2);
        const browY = centerY - Math.floor(R * 0.3);
        const browX = Math.floor(R * 0.2);
        drawLine(centerX - browX, browY, centerX - browX + browW, browY + browH, innerColor, 10);
        drawLine(centerX + browX, browY, centerX + browX - browW, browY + browH, innerColor, 10);

        const MOUTH_W = Math.floor(R * 0.3);
        const MOUTH_Y = centerY + Math.floor(R * 0.1);
        drawLine(centerX - MOUTH_W / 2, MOUTH_Y, centerX + MOUTH_W / 2, MOUTH_Y, innerColor, 10);
    }


    // BOSS D: Annihilate (Fresh con Corona)
    function drawAnnihilate(coords) {
        // 1. Dibuja el cuerpo base de LltNF (el de la Imagen 1)
        drawLltNF_Image1(coords);

        // 2. Dibujar la Corona
        const { centerX, centerY, radius: R } = coords;
        const CROWN_BASE_Y = centerY - R - Math.floor(R * 0.05);
        const CROWN_HEIGHT = Math.floor(R * 0.3);
        const CROWN_POINTS = 5;
        const CROWN_WIDTH = Math.floor(R * 1.2);
        const BASE_T = 15;

        // Base de la Corona (Rectángulo grueso)
        drawLine(centerX - CROWN_WIDTH / 2, CROWN_BASE_Y, centerX + CROWN_WIDTH / 2, CROWN_BASE_Y, corruptionColor, BASE_T);

        // Picos de la Corona (Triángulos)
        for (let i = 0; i < CROWN_POINTS; i++) {
            const startX = centerX - CROWN_WIDTH / 2 + (i * CROWN_WIDTH / (CROWN_POINTS - 1));
            const p1 = { x: startX - Math.floor(R * 0.05), y: CROWN_BASE_Y - BASE_T / 2 };
            const p2 = { x: startX + Math.floor(R * 0.05), y: CROWN_BASE_Y - BASE_T / 2 };
            const p3 = { x: startX, y: CROWN_BASE_Y - CROWN_HEIGHT };
            drawSolidTriangle(p1, p2, p3, corruptionColor, 8);
        }

        // 3. Pequeño Triángulo Lateral
        const sideT_R = Math.floor(R * 0.1);
        const t1 = { x: centerX - R - sideT_R, y: centerY - Math.floor(R * 0.2) };
        const t2 = { x: centerX - R, y: centerY - Math.floor(R * 0.2) + sideT_R / 2 };
        const t3 = { x: centerX - R, y: centerY - Math.floor(R * 0.2) - sideT_R / 2 };
        drawSolidTriangle(t1, t2, t3, corruptionColor, 8);
    }


    // BOSS E: Final Boss (The Crown Only)
    function drawFinalBossCrown(coords) {
        const { centerX, centerY, radius: R } = coords;

        const CROWN_BASE_Y = centerY + Math.floor(R * 0.2);
        const CROWN_HEIGHT = Math.floor(R * 0.4);
        const CROWN_POINTS = 5;
        const CROWN_WIDTH = Math.floor(R * 1.5);
        const BASE_T = 20;

        // Base de la Corona (Rectángulo grueso)
        drawLine(centerX - CROWN_WIDTH / 2, CROWN_BASE_Y, centerX + CROWN_WIDTH / 2, CROWN_BASE_Y, corruptionColor, BASE_T);

        // Picos de la Corona (Triángulos)
        for (let i = 0; i < CROWN_POINTS; i++) {
            const startX = centerX - CROWN_WIDTH / 2 + (i * CROWN_WIDTH / (CROWN_POINTS - 1));
            const p1 = { x: startX - Math.floor(R * 0.05), y: CROWN_BASE_Y - BASE_T / 2 };
            const p2 = { x: startX + Math.floor(R * 0.05), y: CROWN_BASE_Y - BASE_T / 2 };
            const p3 = { x: startX, y: CROWN_BASE_Y - CROWN_HEIGHT };
            drawSolidTriangle(p1, p2, p3, corruptionColor, 8);
        }

        // Triángulo superior invertido (El ojo central de la corrupción)
        const triR = Math.floor(R * 0.3);
        const tr1 = { x: centerX, y: CROWN_BASE_Y - CROWN_HEIGHT - triR * 0.2 };
        const tr2 = { x: centerX - triR / 2, y: CROWN_BASE_Y - CROWN_HEIGHT + triR };
        const tr3 = { x: centerX + triR / 2, y: CROWN_BASE_Y - CROWN_HEIGHT + triR };
        drawSolidTriangle(tr1, tr2, tr3, corruptionColor, 10);
    }


    // BOSS F: Lycanthropy (Polígono Angular)
    function drawLycanthropy(coords) {
        const { centerX, centerY, radius } = coords;
        const R = radius * 1.1;
        const NUM_SIDES = 8;
        const FACE_OFFSET = Math.floor(R * 0.15);
        const EYE_W = Math.floor(R * 0.2);

        // 1. Cuerpo Principal (Octágono Angular Relleno)
        const points = [];
        for (let i = 0; i < NUM_SIDES; i++) {
            const angle = (i / NUM_SIDES) * 2 * Math.PI;
            const x = centerX + R * Math.cos(angle);
            const y = centerY + R * Math.sin(angle);
            points.push({ x, y });
        }
        for (let i = 0; i < NUM_SIDES; i++) {
            drawLine(points[i].x, points[i].y, points[(i + 1) % NUM_SIDES].x, points[(i + 1) % NUM_SIDES].y, darkCorruptionColor, R * 0.5);
        }

        // 2. Dientes/Boca (Magenta)
        const MOUTH_W = Math.floor(R * 0.6);
        const MOUTH_Y = centerY + Math.floor(R * 0.2) + FACE_OFFSET;
        const NUM_TEETH = 8;
        const toothSpacing = MOUTH_W / NUM_TEETH;

        for (let i = 0; i < NUM_TEETH; i++) {
            const x = centerX - MOUTH_W / 2 + i * toothSpacing + toothSpacing / 2;
            const y_base = MOUTH_Y;
            const y_tip = MOUTH_Y + Math.floor(R * 0.25);
            const d1 = { x: x - toothSpacing * 0.3, y: y_base };
            const d2 = { x: x + toothSpacing * 0.3, y: y_base };
            const d3 = { x: x, y: y_tip };
            drawSolidTriangle(d1, d2, d3, corruptionColor, 6);
            const u1 = { x: x - toothSpacing * 0.3, y: y_base - Math.floor(R * 0.3) };
            const u2 = { x: x + toothSpacing * 0.3, y: y_base - Math.floor(R * 0.3) };
            const u3 = { x: x, y: y_base - Math.floor(R * 0.5) };
            drawSolidTriangle(u1, u2, u3, corruptionColor, 6);
        }
        const tongue_r = { x: centerX, y: MOUTH_Y + Math.floor(R * 0.3) };
        const tongue_l = { x: centerX - MOUTH_W * 0.4, y: MOUTH_Y - Math.floor(R * 0.1) };
        const tongue_rgt = { x: centerX + MOUTH_W * 0.4, y: MOUTH_Y - Math.floor(R * 0.1) };
        drawSolidTriangle(tongue_r, tongue_l, tongue_rgt, darkCorruptionColor, 8);


        // 3. Ojos (Blancos, Triangulares)
        const eyeY = centerY - Math.floor(R * 0.4) + FACE_OFFSET;
        const eyeDraw = (sign) => {
            const e1 = { x: centerX + sign * EYE_W, y: eyeY };
            const e2 = { x: centerX + sign * EYE_W * 0.2, y: eyeY - EYE_W * 0.4 };
            const e3 = { x: centerX + sign * EYE_W * 0.2, y: eyeY + EYE_W * 0.4 };
            drawSolidTriangle(e1, e2, e3, highlightColor, 8);
        };
        eyeDraw(-1); eyeDraw(1);
    }


    // BOSS G: Spider Dance (Araña)
    function drawSpiderDance(coords) {
        const { centerX, centerY, radius } = coords;
        const R = radius * 1.1;
        const NUM_LEGS = 8;
        const LEG_LENGTH = R * 1.5;
        const LEG_WIDTH = Math.floor(R * 0.08);

        // 1. Cuerpo Principal (Círculo Sólido Magenta)
        drawSolidCircle(centerX, centerY, R, corruptionColor, 5);

        // 2. Patas (8 Angulares)
        for (let i = 0; i < NUM_LEGS; i++) {
            if (isStopped) break;
            const angle = (i / NUM_LEGS) * 2 * Math.PI;

            const p1 = { x: centerX + R * Math.cos(angle), y: centerY + R * Math.sin(angle) };
            const elbowFactor = 0.5;
            const elbowX = centerX + (R + LEG_LENGTH * elbowFactor) * Math.cos(angle - Math.PI / 16);
            const elbowY = centerY + (R + LEG_LENGTH * elbowFactor) * Math.sin(angle - Math.PI / 16);
            const p2 = { x: elbowX, y: elbowY };
            const tipX = centerX + (R + LEG_LENGTH) * Math.cos(angle - Math.PI / 8);
            const tipY = centerY + (R + LEG_LENGTH) * Math.sin(angle - Math.PI / 8);
            const p3 = { x: tipX, y: tipY };

            drawLine(p1.x, p1.y, p2.x, p2.y, corruptionColor, LEG_WIDTH);
            drawLine(p2.x, p2.y, p3.x, p3.y, corruptionColor, LEG_WIDTH);
        }

        // 3. Ojos (Pequeños Triángulos Agresivos)
        const EYE_H = Math.floor(R * 0.15);
        const EYE_Y = centerY - Math.floor(R * 0.2);
        const EYE_SPACING = Math.floor(R * 0.2);
        const eyeDraw = (sign) => {
            const e1 = { x: centerX + sign * EYE_SPACING, y: EYE_Y };
            const e2 = { x: centerX + sign * (EYE_SPACING + EYE_H), y: EYE_Y - EYE_H };
            const e3 = { x: centerX + sign * (EYE_SPACING + EYE_H), y: EYE_Y + EYE_H };
            drawSolidTriangle(e1, e2, e3, innerColor, 8);
        };
        eyeDraw(-1); eyeDraw(1);

        // 4. Pequeños Triángulos Inferiores (Boca)
        const MOUTH_Y = centerY + Math.floor(R * 0.2);
        const MOUTH_SPACING = Math.floor(R * 0.1);
        const MOUTH_H = Math.floor(R * 0.1);
        const mouthDraw = (sign) => {
            const m1 = { x: centerX + sign * MOUTH_SPACING, y: MOUTH_Y };
            const m2 = { x: centerX + sign * (MOUTH_SPACING + MOUTH_H), y: MOUTH_Y + MOUTH_H };
            const m3 = { x: centerX + sign * (MOUTH_SPACING - MOUTH_H), y: MOUTH_Y + MOUTH_H };
            drawSolidTriangle(m1, m2, m3, innerColor, 8);
        };
        mouthDraw(-1); mouthDraw(1);
    }


    // === MAPA DE JEFES Y FUNCIÓN PRINCIPAL PARA EL SELECTOR ===

    const BOSS_FUNCTIONS = {
        'New Game': drawLltNF_Image1,
        'Annihilate': drawAnnihilate,
        'Barracuda': drawBarracuda,
        'Close To Me': drawCloseToMe,
    };

    function drawSelectedBoss() {
        const bossSelect = document.getElementById('boss-select');
        const selectedBoss = bossSelect?.value;

        if (!selectedBoss || !BOSS_FUNCTIONS[selectedBoss]) {
            alert('Por favor, selecciona un jefe válido.');
            return;
        }

        if (isDrawing) { alert('Ya está en curso un dibujo. Presiona "Parar" para cancelar.'); return; }
        if (!socket || !canvas || !ctx) { alert('No se detectó conexión o canvas. Asegúrate de estar en una sala de juego.'); return; }

        isDrawing = true;
        isStopped = false;
        const statusDiv = document.getElementById('boss-status') || createStatusDiv('boss-status');

        try {
            updateStatus(statusDiv, `🚀 JEFE JSAB: Iniciando ${selectedBoss} (Instantáneo)...`, corruptionColor);
            const coords = calculateBaseCoordinates();

            BOSS_FUNCTIONS[selectedBoss](coords);

            updateStatus(statusDiv, `🏆 ¡JEFE ${selectedBoss} DIBUJADO AL INSTANTE! 🎯`, "#006400", true);
            setTimeout(() => { if (statusDiv.parentNode) { statusDiv.style.opacity = 0; setTimeout(() => statusDiv.remove(), 500); } }, 3000);

        } catch (error) {
            console.error(`Error al dibujar jefe JSAB (${selectedBoss}):`, error);
            updateStatus(statusDiv, `❌ Error: ${error.message}`, "#B22222", true);
        } finally {
            isDrawing = false;
        }
    }


    // === UI Y STATUS (CONSOLIDADO) ===

    function createConsolidatedUI() {
        const uiContainer = document.createElement('div');
        uiContainer.id = 'minimal-boss-ui';
        uiContainer.style.cssText = `
            position: fixed;
            bottom: 15px;
            left: 15px;
            background: linear-gradient(135deg, ${corruptionColor} 0%, #B3005D 100%);
            border: 3px solid #000;
            border-radius: 15px;
            padding: 22px;
            z-index: 9999;
            box-shadow: 0 12px 35px rgba(0,0,0,0.5);
            display: none;
            max-width: 300px;
            color: white;
            font-family: Arial, sans-serif;
        `;

        const toggleButton = document.createElement('button');
        toggleButton.innerText = '😈';
        toggleButton.style.cssText = `
            position: fixed;
            bottom: 15px;
            left: 15px;
            width: 58px;
            height: 58px;
            background: linear-gradient(135deg, ${corruptionColor} 0%, #B3005D 100%);
            border: 3px solid #000;
            border-radius: 15px;
            font-size: 28px;
            cursor: pointer;
            z-index: 9998;
            box-shadow: 0 10px 25px rgba(0,0,0,0.4);
            transition: all 0.3s;
            animation: glow-boss 3s infinite;
        `;

        const style = document.createElement('style');
        style.textContent = `
            @keyframes glow-boss {
                0%, 100% { box-shadow: 0 10px 25px rgba(0,0,0,0.4); }
                50% { box-shadow: 0 10px 35px rgba(255,0,140,0.8); }
            }
            .boss-select {
                padding: 10px;
                border-radius: 8px;
                border: 2px solid #000;
                width: 100%;
                margin-bottom: 15px;
                font-size: 14px;
                background-color: white;
                color: #333;
            }
        `;
        document.head.appendChild(style);

        const selectOptions = Object.keys(BOSS_FUNCTIONS).map(boss =>
            `<option value="${boss}">${boss}</option>`
        ).join('');

        uiContainer.innerHTML = `
            <div style="margin-bottom: 22px; font-weight: bold; text-align: center; font-size: 19px; text-shadow: 2px 2px 4px rgba(0,0,0,0.5);">
                😈 JSAB BOSS COLLECTION (V7.1) 😈
            </div>

            <!-- Botón V6.1 original -->
            <button id="draw-boss-btn-v61" style="
                background: linear-gradient(45deg, #FF69B4, #E91E63);
                color: white;
                border: none;
                border-radius: 15px;
                padding: 15px;
                width: 100%;
                font-weight: bold;
                cursor: pointer;
                margin-bottom: 20px;
                font-size: 15px;
                box-shadow: 0 6px 18px rgba(255,105,180,0.4);
                text-shadow: 1px 1px 3px rgba(0,0,0,0.4);
                transition: all 0.2s;
            " onmouseover="this.style.transform='scale(1.02)'" onmouseout="this.style.transform='scale(1)'">Long Live The New Fresh</button>

            <div style="border-top: 1px solid #FF008C; padding-top: 20px; margin-top: 10px;">
                <label for="boss-select" style="display:block; margin-bottom: 5px; font-weight: bold;">SELECCIONAR JEFE DETALLADO:</label>
                <select id="boss-select" class="boss-select">
                    ${selectOptions}
                </select>

                <button id="draw-selected-boss-btn" style="
                    background: linear-gradient(45deg, ${corruptionColor}, #B3005D);
                    color: white;
                    border: none;
                    border-radius: 15px;
                    padding: 15px;
                    width: 100%;
                    font-weight: bold;
                    cursor: pointer;
                    margin-bottom: 15px;
                    font-size: 17px;
                    box-shadow: 0 6px 18px rgba(255,0,140,0.4);
                    text-shadow: 1px 1px 3px rgba(0,0,0,0.4);
                    transition: all 0.2s;
                " onmouseover="this.style.transform='scale(1.04)'" onmouseout="this.style.transform='scale(1)'">🚀 INICIAR DIBUJO INSTANTÁNEO</button>
            </div>

            <button id="stop-btn" style="
                background: linear-gradient(45deg, #f44336, #da190b);
                color: white;
                border: none;
                border-radius: 10px;
                padding: 10px;
                width: 100%;
                cursor: pointer;
                font-size: 13px;
                margin-top: 10px;
            ">❌ Parar Todos los Dibujos</button>
        `;

        document.body.appendChild(uiContainer);
        document.body.appendChild(toggleButton);

        toggleButton.addEventListener('click', () => {
            const ui = document.getElementById('minimal-boss-ui');
            const isVisible = ui.style.display === 'block';
            ui.style.display = isVisible ? 'none' : 'block';
        });

        document.getElementById('draw-boss-btn-v61').addEventListener('click', drawJSABBoss_V61);
        document.getElementById('draw-selected-boss-btn').addEventListener('click', drawSelectedBoss);

        document.getElementById('stop-btn').addEventListener('click', () => {
            isStopped = true;
            const statusDiv = document.getElementById('boss-status');
            if (statusDiv) {
                updateStatus(statusDiv, "⛔ Dibujo detenido", "#B22222", true);
            }
        });
    }

    function createStatusDiv(id) {
        const statusDiv = document.createElement('div');
        statusDiv.id = id;
        statusDiv.style.cssText = `
            position: fixed;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
            background: linear-gradient(135deg, #787878 0%, #505050 100%);
            color: white;
            padding: 20px 40px;
            border-radius: 35px;
            font-weight: bold;
            z-index: 10000;
            transition: opacity 0.5s;
            text-align: center;
            min-width: 450px;
            box-shadow: 0 12px 30px rgba(0,0,0,0.5);
            text-shadow: 1px 1px 3px rgba(0,0,0,0.4);
        `;
        document.body.appendChild(statusDiv);
        return statusDiv;
    }

    function updateStatus(statusDiv, message, color, permanent = false) {
        if (!statusDiv) return;
        statusDiv.textContent = message;
        if (color) {
            statusDiv.style.background = `linear-gradient(135deg, ${color} 0%, #333 100%)`;
        }
        statusDiv.style.opacity = 1;
    }

    // Inicialización
    function init() {
        if (canvas && ctx) {
            createConsolidatedUI();
            console.log('😈 JSAB Boss Script V7.1 Cargado: Colección completa con V6.1 intacto.');
        } else {
            setTimeout(init, 1000);
        }
    }

    init();

})();