Drawaria Sci-Fi Cockpit Mod

Immersive and detailed recreation of a spacecraft cockpit (HMI) on Drawaria.online's canvas, featuring functional control systems and modular architecture.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Drawaria Sci-Fi Cockpit Mod
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Immersive and detailed recreation of a spacecraft cockpit (HMI) on Drawaria.online's canvas, featuring functional control systems and modular architecture.
// @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/
// @connect      i.pinimg.com
// @connect      static.wikia.nocookie.net
// @connect      www.myinstants.com
// @grant        GM_registerMenuCommand
// @grant        GM_xmlhttpRequest
// @license      MIT
// @icon         https://www.google.com/s2/favicons?sz=64&domain=drawaria.online
// ==/UserScript==

(function() {
    'use strict';

    /* ---------- COMPONENTES DE INFRAESTRUCTURA DE DIBUJO ---------- */
    let drawariaSocket = null;
    let drawariaCanvas = null;
    let drawariaCtx = null;
    const commandQueue = [];
    let batchProcessor = null;
    const BATCH_SIZE = 12; // Aumentamos el lote para un dibujo más rápido
    const BATCH_INTERVAL = 50; // Intervalo más corto para mayor fluidez

    // 1. Interceptación del WebSocket
    const originalWebSocketSend = WebSocket.prototype.send;
    WebSocket.prototype.send = function(...args) {
        if (!drawariaSocket && this.url && this.url.includes('drawaria')) {
            drawariaSocket = this;
            console.log('🔗 WebSocket de Drawaria capturado para la Cabina HMI.');
            startBatchProcessor();
        }
        return originalWebSocketSend.apply(this, args);
    };

    // 2. Procesador de Comandos por Lote (Batch Processor)
    function startBatchProcessor() {
        if (batchProcessor) return;
        batchProcessor = setInterval(() => {
            if (!drawariaSocket || drawariaSocket.readyState !== WebSocket.OPEN || commandQueue.length === 0) {
                return;
            }
            const batch = commandQueue.splice(0, BATCH_SIZE);
            batch.forEach(cmd => {
                try {
                    drawariaSocket.send(cmd);
                } catch (e) {
                    console.warn('⚠️ Fallo al enviar el comando de dibujo:', e);
                }
            });
        }, BATCH_INTERVAL);
    }

    /**
     * Envía un comando de dibujo al servidor (42["drawcmd",...]) y renderiza localmente.
     * @param {number} x1 - Coordenada X normalizada (0 a 1) o absoluta.
     * @param {number} y1 - Coordenada Y normalizada (0 a 1) o absoluta.
     * @param {number} x2 - Coordenada X destino.
     * @param {number} y2 - Coordenada Y destino.
     * @param {string} color - Color hexadecimal.
     * @param {number} thickness - Grosor de la línea. Negativo para simular formas rellenas.
     * @param {boolean} isArc - Si es un arco/círculo (usando x1, y1 como centro y thickness/2 como radio).
     * @param {number} startAngle - Ángulo inicial (en radianes).
     * @param {number} endAngle - Ángulo final (en radianes).
     */
    function enqueueDrawCommand(x1, y1, x2, y2, color, thickness, isArc = false, startAngle = 0, endAngle = 0) {
        if (!drawariaCanvas || !drawariaSocket) return;

        // Convertir coordenadas absolutas a normalizadas (0 a 1) para el servidor
        const normX1 = (x1 / drawariaCanvas.width).toFixed(4);
        const normY1 = (y1 / drawariaCanvas.height).toFixed(4);
        const normX2 = (x2 / drawariaCanvas.width).toFixed(4);
        const normY2 = (y2 / drawariaCanvas.height).toFixed(4);
        const isFill = thickness < 0;
        const absThickness = Math.abs(thickness);

        // 3. Renderizado Local (para feedback inmediato)
        if (drawariaCtx) {
            drawariaCtx.fillStyle = color;
            drawariaCtx.strokeStyle = color;
            drawariaCtx.lineWidth = absThickness;
            drawariaCtx.lineCap = isFill ? 'butt' : 'round';
            drawariaCtx.lineJoin = 'round';

            if (isArc) {
                // Simulación de arco rellenado o círculo
                drawariaCtx.beginPath();
                drawariaCtx.arc(x1, y1, absThickness / 2, startAngle, endAngle);
                drawariaCtx.closePath();
                drawariaCtx.fill();
            } else if (isFill) {
                 // Simulación de relleno: Dibujar un punto grande o línea muy gruesa
                drawariaCtx.beginPath();
                drawariaCtx.moveTo(x1, y1);
                drawariaCtx.lineTo(x2, y2);
                drawariaCtx.stroke();
            } else {
                // Línea normal
                drawariaCtx.beginPath();
                drawariaCtx.moveTo(x1, y1);
                drawariaCtx.lineTo(x2, y2);
                drawariaCtx.stroke();
            }
        }

        // 4. Comando para el Servidor Drawaria
        // Usamos el formato de línea/relleno del motor Drawaria:
        const cmd = `42["drawcmd",0,[${normX1},${normY1},${normX2},${normY2},false,${thickness.toFixed(2)},"${color}",0,0,{}]]`;
        commandQueue.push(cmd);
    }

    class SciFiCockpitHMI {
        constructor() {
            this.canvasWidth = 0;
            this.canvasHeight = 0;
            this.isDrawn = false;
            this.currentView = 'planetary'; // Nuevo estado: 'planetary' o 'nebula'
            this.shieldsActive = false;    // Nuevo estado: control de escudo
            // Coordenadas para el indicador de escudo, inicializadas más tarde en drawMainConsoles
            this.shieldIndicatorCoords = { x: 0, y: 0, size: 0 };
            this.init();
        }

        init() {
            const checkReady = () => {
                const gameCanvas = document.getElementById('canvas');
                if (gameCanvas) {
                    drawariaCanvas = gameCanvas;
                    drawariaCtx = gameCanvas.getContext('2d');
                    this.canvasWidth = drawariaCanvas.width;
                    this.canvasHeight = drawariaCanvas.height;
                    this.createControlPanel();
                    console.log('✅ Cabina HMI inicializada. Canvas: ' + this.canvasWidth + 'x' + this.canvasHeight);
                } else {
                    setTimeout(checkReady, 100);
                }
            };
            checkReady();
        }

        // --- UTILIDADES ---
        clearCanvas() {
             // Utiliza un grosor enorme y color negro para el borrado total
            enqueueDrawCommand(
                this.canvasWidth / 2, this.canvasHeight / 2, // Centro del canvas
                this.canvasWidth / 2, this.canvasHeight / 2,
                '#000000', -Math.max(this.canvasWidth, this.canvasHeight) * 2
            );
            this.isDrawn = false;
        }

        // --- PANEL DE CONTROL DRAGABLE (Interfaz de Operación) ---
        createControlPanel() {
            const existingPanel = document.getElementById('scifi-cockpit-panel');
            if (existingPanel) existingPanel.remove();

            const panel = document.createElement('div');
            panel.id = 'scifi-cockpit-panel';
            panel.style.cssText = `
                position: fixed !important;
                top: 50px !important;
                left: 50px !important;
                width: 300px !important;
                z-index: 2147483647 !important;
                background: linear-gradient(145deg, #1A237E, #0D47A1) !important;
                border: 3px solid #00BFFF !important;
                border-radius: 15px !important;
                color: white !important;
                font-family: 'Segoe UI', Arial, sans-serif !important;
                box-shadow: 0 0 25px rgba(0, 191, 255, 0.5) !important;
                padding: 20px !important;
                text-align: center !important;
            `;

            panel.innerHTML = `
                <h3 style="margin-top: 0; color: #00BFFF; cursor: grab;">🛰️ Centro de Mando HMI (v1.1)</h3>
                <p style="font-size: 12px; margin-top: -10px; color: #81D4FA;">[PROTOCOLO DE DESPLIEGUE RÁPIDO]</p>
                <div style="margin-bottom: 15px; border-bottom: 1px solid #00BFFF; padding-bottom: 10px;">
                    Estado: <span id="cockpit-status" style="color: #FFEB3B; font-weight: bold;">STANDBY</span>
                </div>

                <div style="margin-bottom: 15px; padding: 10px; border-radius: 5px; background: rgba(0,0,0,0.2);">
                    <h4 style="margin: 0 0 10px 0; color: #81D4FA;">Secuencia Base</h4>
                    <button id="draw-cockpit-btn" style="
                        width: 100%; padding: 10px; background: #28a745; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: bold; margin-bottom: 5px; transition: background 0.3s ease;
                    ">✅ Iniciar Secuencia de Despliegue</button>
                    <button id="clear-canvas-btn" style="
                        width: 100%; padding: 10px; background: #dc3545; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: bold; transition: background 0.3s ease;
                    ">❌ Purgar Memoria Gráfica</button>
                </div>

                <div style="margin-bottom: 15px; padding: 10px; border-radius: 5px; background: rgba(0,0,0,0.2);">
                    <h4 style="margin: 0 0 10px 0; color: #81D4FA;">Sistemas de Navegación</h4>
                    <button id="view-toggle-btn" style="
                        width: 100%; padding: 10px; background: #007bff; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; margin-bottom: 5px;
                    ">🌌 Cambiar Vista (Actual: <span id="current-view-text">PLANETARIO</span>)</button>
                </div>

                <div style="margin-bottom: 15px; padding: 10px; border-radius: 5px; background: rgba(0,0,0,0.2);">
                    <h4 style="margin: 0 0 10px 0; color: #81D4FA;">Controles Tácticos</h4>
                    <button id="shields-toggle-btn" style="
                        width: 100%; padding: 10px; background: #FFC107; color: #333; border: none; border-radius: 8px; cursor: pointer; font-size: 14px;
                    ">🛡️ Toggle Escudos (OFF)</button>
                </div>

                <div style="margin-bottom: 5px; padding: 10px; border-radius: 5px; background: rgba(0,0,0,0.2);">
                    <h4 style="margin: 0 0 10px 0; color: #81D4FA;">Controles de Motor</h4>
                    <button id="warp-btn" style="
                        width: 100%; padding: 10px; background: #6f42c1; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px;
                    ">🚀 Iniciar Salto WARP</button>
                </div>
            `;
            document.body.appendChild(panel);
            this.setupEventListeners();
            this.makePanelDraggable(panel);
        }

        setupEventListeners() {
            document.getElementById('draw-cockpit-btn').addEventListener('click', () => this.drawFullCockpit());
            document.getElementById('clear-canvas-btn').addEventListener('click', () => {
                this.clearCanvas();
                this.updateStatus('PURGADO', '#dc3545');
                this.isDrawn = false;
                this.currentView = 'planetary';
                this.shieldsActive = false;
                this.updateViewText();
                this.updateShieldButton();
            });
            document.getElementById('view-toggle-btn').addEventListener('click', () => this.toggleExternalView());
            document.getElementById('shields-toggle-btn').addEventListener('click', () => this.toggleShields());
            document.getElementById('warp-btn').addEventListener('click', () => this.simulateWarp());
        }

        updateStatus(text, color) {
            const statusEl = document.getElementById('cockpit-status');
            if (statusEl) {
                statusEl.textContent = text;
                statusEl.style.color = color;
            }
        }

        updateViewText() {
            const viewTextEl = document.getElementById('current-view-text');
            if (viewTextEl) {
                viewTextEl.textContent = this.currentView.toUpperCase();
            }
        }

        updateShieldButton() {
            const shieldBtn = document.getElementById('shields-toggle-btn');
            if (shieldBtn) {
                if (this.shieldsActive) {
                    shieldBtn.textContent = '🛡️ Toggle Escudos (ON)';
                    shieldBtn.style.backgroundColor = '#28A745';
                    shieldBtn.style.color = 'white';
                } else {
                    shieldBtn.textContent = '🛡️ Toggle Escudos (OFF)';
                    shieldBtn.style.backgroundColor = '#FFC107';
                    shieldBtn.style.color = '#333';
                }
            }
        }

        // --- NUEVAS FUNCIONES DE MANIPULACIÓN DE NAVE ---

        toggleExternalView() {
            if (!this.isDrawn) {
                alert('⚠️ ¡Despliega la cabina primero!');
                return;
            }

            this.currentView = this.currentView === 'planetary' ? 'nebula' : 'planetary';
            this.updateStatus(`VISTA: ${this.currentView.toUpperCase()}`, '#00BFFF');
            this.updateViewText();

            // Borra y redibuja solo la vista externa
            this.drawExternalView(true); // El parámetro true le indica que es un redibujo rápido de fondo.
        }

        toggleShields() {
            if (!this.isDrawn) {
                alert('⚠️ ¡Despliega la cabina primero!');
                return;
            }

            this.shieldsActive = !this.shieldsActive;
            this.updateShieldButton();
            this.updateStatus(`ESCUDOS: ${this.shieldsActive ? 'ACTIVOS' : 'INACTIVOS'}`, this.shieldsActive ? '#28A745' : '#FFC107');

            // Redibuja solo el indicador de escudo en la consola principal
            const { x, y, size } = this.shieldIndicatorCoords;
            const color = this.shieldsActive ? '#00FF00' : '#FF0000'; // Verde para ON, Rojo para OFF
            const darkBg = '#000000';

            // 1. Borra el área del indicador
            enqueueDrawCommand(x, y, x, y, darkBg, -size * 2, true);

            // 2. Dibuja el nuevo indicador (Círculo relleno)
            enqueueDrawCommand(x, y, x, y, color, size, true);
        }

        simulateWarp() {
            if (!this.isDrawn) {
                alert('⚠️ ¡Despliega la cabina primero!');
                return;
            }

            this.updateStatus('PREPARANDO WARP...', '#6f42c1');
            const W = this.canvasWidth;
            const H = this.canvasHeight;
            const warpColor = '#00BFFF'; // Azul de motor

            // 1. Efecto de Estiramiento/Convergencia (Temporal)
            for (let i = 0; i < 50; i++) {
                const x = Math.random() * W;
                const y = Math.random() * H;
                const targetX = W / 2;
                const targetY = H / 2;
                // Dibuja líneas que convergen en el centro
                enqueueDrawCommand(x, y, targetX + (x - targetX) / 10, targetY + (y - targetY) / 10, warpColor, 3);
            }

            // 2. Limpia el efecto y restaura la vista
            setTimeout(() => {
                // Borra solo el fondo
                this.drawExternalView(true);
                this.updateStatus('WARP COMPLETADO', '#28a745');
            }, 1000); // 1 segundo de efecto
        }

        // --- LÓGICA DE DIBUJO COMPLEJO ---

        drawFullCockpit() {
            if (this.isDrawn) {
                this.clearCanvas();
                setTimeout(() => this._drawElements(), 150); // Pequeño retraso para asegurar el borrado
            } else {
                this._drawElements();
            }
        }

        _drawElements() {
            if (this.isDrawn) return;
            this.updateStatus('DESPLEGANDO...', '#FFC107');
            this.updateViewText();
            this.updateShieldButton();
            console.log('Iniciando secuencia de dibujo de cabina...');

            // Secuencia de renderizado por capas (de atrás hacia adelante)
            this.drawExternalView(false); // Planetas y estrellas (Fondo)
            this.drawCockpitShell(); // Estructura (Ventanas, Techo, Piso)
            this.drawMainConsoles(); // Consolas de Mando (Escritorio)
            this.drawHMI_Displays(); // Pantallas y HUDs (Detalle técnico)
            this.drawSeats(); // Asientos (Primer plano)

            this.isDrawn = true;
            this.updateStatus('OPERACIONAL', '#28a745');
            console.log('Secuencia de cabina finalizada.');
        }

        drawExternalView(onlyBackgroundRedraw = false) {
            const W = this.canvasWidth;
            const H = this.canvasHeight;

            // Siempre borra el fondo antes de dibujar la vista
            enqueueDrawCommand(W / 2, H / 2, W / 2, H / 2, '#000000', -Math.max(W, H) * 2);

            // Fondo Estelar base (azul oscuro)
            enqueueDrawCommand(W / 2, H / 2, W / 2, H / 2, '#191970', -Math.max(W, H) * 2);

            if (this.currentView === 'planetary') {
                // 2. Estrellas
                for (let i = 0; i < 50; i++) {
                    enqueueDrawCommand(Math.random() * W, Math.random() * H, Math.random() * W, Math.random() * H, '#FFFFFF', 1);
                }

                // 3. Planeta Gigante Gaseoso (Derecha, color naranja/rojo)
                enqueueDrawCommand(W * 0.9, H * 0.4, W * 0.9, H * 0.4, '#FF4500', 400, true);
                enqueueDrawCommand(W * 0.9 - 150, H * 0.4, W * 0.9 + 150, H * 0.4, '#FFA07A', 10);

                // 4. Planeta Púrpura (Centro-izquierda)
                enqueueDrawCommand(W * 0.45, H * 0.35, W * 0.45, H * 0.35, '#8A2BE2', 150, true);

            } else if (this.currentView === 'nebula') {
                // Vista de Nebulosa (Nubes de color púrpura y verde)
                const nebulaColors = ['#8A2BE2', '#4B0082', '#3CB371'];
                for (let i = 0; i < 8; i++) {
                    const color = nebulaColors[i % 3];
                    const x = Math.random() * W;
                    const y = Math.random() * H;
                    const size = 150 + Math.random() * 200;
                    // Nubes grandes difusas (círculos rellenos)
                    enqueueDrawCommand(x, y, x, y, color, size, true);
                }
            }

            // Si solo estamos redibujando el fondo, no redibujamos el resto de la cabina.
            if (onlyBackgroundRedraw) {
                // El resto de elementos de la cabina (techo, consolas, etc.)
                // deben estar superpuestos correctamente al dibujarse inicialmente.
                // Si la vista externa requiere un borrado completo del canvas,
                // las capas superiores deben ser redibujadas. Para simplificar
                // y ahorrar comandos, asumimos que el borrado de fondo es
                // suficientemente discreto para no afectar las capas superiores
                // dibujadas *encima*.
            }
        }


        drawCockpitShell() {
            const W = this.canvasWidth;
            const H = this.canvasHeight;
            const darkBlue = '#1E3F66'; // Material estructural oscuro
            const lightGrey = '#FFFFFF'; // Techo/Piso interior

            // 1. Piso Interior
            enqueueDrawCommand(W * 0.1, H * 0.65, W * 0.9, H * 0.65, lightGrey, -H * 0.4);

            // 2. Techo y Paredes
            enqueueDrawCommand(W * 0.1, H * 0.05, W * 0.9, H * 0.05, darkBlue, -H * 0.5);

            // 3. Marcos de Ventanas y Pilares
            const pillarWidth = 15;
            enqueueDrawCommand(W * 0.5 - pillarWidth / 2, H * 0.05, W * 0.5 - pillarWidth / 2, H * 0.65, darkBlue, pillarWidth);
            enqueueDrawCommand(W * 0.1, H * 0.05, W * 0.1, H * 0.65, darkBlue, pillarWidth);
            enqueueDrawCommand(W * 0.9, H * 0.05, W * 0.9, H * 0.65, darkBlue, pillarWidth);

            // 4. Iluminación de Techo
            const lampColor = '#FFFFFF';
            enqueueDrawCommand(W * 0.3, H * 0.08, W * 0.35, H * 0.08, lampColor, 5);
            enqueueDrawCommand(W * 0.65, H * 0.08, W * 0.7, H * 0.08, lampColor, 5);
        }

        drawMainConsoles() {
            const W = this.canvasWidth;
            const H = this.canvasHeight;
            const consoleColor = '#F0F0F0';
            const consoleBaseH = H * 0.6;
            const consoleDepth = H * 0.15;

            // 1. Superficie de la Consola Principal
            enqueueDrawCommand(W * 0.15, consoleBaseH, W * 0.85, consoleBaseH, consoleColor, -consoleDepth * 2);

            // 2. Módulos de Pantalla
            const screenMountColor = '#C0C0C0';
            const screenH = H * 0.18;
            const screenW = W * 0.25;
            enqueueDrawCommand(W * 0.28, consoleBaseH - screenH / 2, W * 0.28, consoleBaseH + screenH / 2, screenMountColor, -screenW);
            enqueueDrawCommand(W * 0.72, consoleBaseH - screenH / 2, W * 0.72, consoleBaseH + screenH / 2, screenMountColor, -screenW);

            // 3. Panel de Control Central Integrado
            const centralPanelColor = '#E0E0E0';
            const centralW = W * 0.2;
            const centralH = H * 0.1;
            enqueueDrawCommand(W * 0.5, consoleBaseH + centralH / 2, W * 0.5, consoleBaseH - centralH / 2, centralPanelColor, -centralW);

            // Indicador de Nivel Crítico (ej. Nivel de Potencia)
            enqueueDrawCommand(W * 0.5, consoleBaseH, W * 0.5, consoleBaseH, '#00BFFF', 40);
            enqueueDrawCommand(W * 0.49, consoleBaseH - 5, W * 0.51, consoleBaseH - 5, '#FFFFFF', 2);
            enqueueDrawCommand(W * 0.49, consoleBaseH + 5, W * 0.51, consoleBaseH + 5, '#FFFFFF', 2);

            // 4. Indicador de ESCUDO (Pequeño indicador táctico, cerca del centro)
            this.shieldIndicatorCoords.x = W * 0.4;
            this.shieldIndicatorCoords.y = consoleBaseH + 40;
            this.shieldIndicatorCoords.size = 20;

            const x = this.shieldIndicatorCoords.x;
            const y = this.shieldIndicatorCoords.y;
            const size = this.shieldIndicatorCoords.size;

            // Dibuja el indicador de escudo en estado inicial (OFF - Rojo)
            enqueueDrawCommand(x, y, x, y, '#FF0000', size, true);
            // Dibuja el borde exterior
            enqueueDrawCommand(x, y, x, y, '#333333', size + 5, true);
        }

        drawHMI_Displays() {
            const W = this.canvasWidth;
            const H = this.canvasHeight;
            const hudColor = '#32CD32';

            const screenH = H * 0.18;
            const screenW = W * 0.25;
            const consoleBaseH = H * 0.6;

            // MFD Izquierdo (Simulando Radar/Mapa Táctico)
            const mfdL_X = W * 0.28;
            const mfdL_Y = consoleBaseH;
            enqueueDrawCommand(mfdL_X, mfdL_Y, mfdL_X, mfdL_Y, '#000000', -screenW);
            enqueueDrawCommand(mfdL_X, mfdL_Y, mfdL_X, mfdL_Y, hudColor, 80, true, 0, 2 * Math.PI);
            enqueueDrawCommand(mfdL_X - 10, mfdL_Y - 10, mfdL_X + 10, mfdL_Y + 10, hudColor, 3);

            // MFD Derecho (Simulando Datos de Vuelo/Telemetría)
            const mfdR_X = W * 0.72;
            const mfdR_Y = consoleBaseH;
            enqueueDrawCommand(mfdR_X, mfdR_Y, mfdR_X, mfdR_Y, '#000000', -screenW);
            enqueueDrawCommand(mfdR_X - 40, mfdR_Y + 10, mfdR_X + 40, mfdR_Y + 10, hudColor, 5);
            enqueueDrawCommand(mfdR_X, mfdR_Y - 20, mfdR_X, mfdR_Y + 20, hudColor, 5);
        }

        drawSeats() {
            const W = this.canvasWidth;
            const H = this.canvasHeight;
            const seatBaseColor = '#C0C0D0';
            const neonBlue = '#00BFFF';

            // Asiento Izquierdo
            const seatL_X = W * 0.25;
            const seatY = H * 0.8;
            const seatW = 120;
            enqueueDrawCommand(seatL_X, seatY, seatL_X, seatY, seatBaseColor, -seatW * 1.5);
            enqueueDrawCommand(seatL_X - seatW / 3, seatY - 50, seatL_X - seatW / 3, seatY + 100, neonBlue, 5);
            enqueueDrawCommand(seatL_X + seatW / 3, seatY - 50, seatL_X + seatW / 3, seatY + 100, neonBlue, 5);

            // Asiento Derecho
            const seatR_X = W * 0.75;
            enqueueDrawCommand(seatR_X, seatY, seatR_X, seatY, seatBaseColor, -seatW * 1.5);
            enqueueDrawCommand(seatR_X - seatW / 3, seatY - 50, seatR_X - seatW / 3, seatY + 100, neonBlue, 5);
            enqueueDrawCommand(seatR_X + seatW / 3, seatY - 50, seatR_X + seatW / 3, seatY + 100, neonBlue, 5);
        }

        // --- FUNCIÓN DE ARRASTRE DEL PANEL (copia del modelo Pac-Man) ---
        makePanelDraggable(panel) {
            let isDragging = false;
            let currentX;
            let currentY;
            let initialX;
            let initialY;
            let xOffset = 0;
            let yOffset = 0;

            const dragStart = (e) => {
                initialX = e.clientX - xOffset;
                initialY = e.clientY - yOffset;
                isDragging = true;
                panel.style.cursor = 'grabbing';
            };

            const dragEnd = () => {
                initialX = currentX;
                initialY = currentY;
                isDragging = false;
                panel.style.cursor = 'grab';
            };

            const drag = (e) => {
                if (isDragging) {
                    e.preventDefault();
                    currentX = e.clientX - initialX;
                    currentY = e.clientY - initialY;
                    xOffset = currentX;
                    yOffset = currentY;
                    panel.style.transform = `translate3d(${currentX}px, ${currentY}px, 0)`;
                }
            };

            const header = panel.querySelector('h3');
            if (header) {
                header.style.cursor = 'grab';
                header.addEventListener("mousedown", dragStart);
                document.addEventListener("mouseup", dragEnd);
                document.addEventListener("mousemove", drag);
            }
        }
    }

    /* ---------- INICIALIZACIÓN DEL SISTEMA ---------- */
    const initSciFiCockpit = () => {
        // Asegura que la clase se instancie solo una vez.
        new SciFiCockpitHMI();
    };

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initSciFiCockpit);
    } else {
        setTimeout(initSciFiCockpit, 500);
    }
})();