Drawaria Cold Ice Menu ❄️☃️

A reflective drama script. Transforms the game atmosphere into a melancholic, snowy city on Dec 31st. Weapon/Effect buttons now trigger Emotional Contrast Filters.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Drawaria Cold Ice Menu ❄️☃️
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  A reflective drama script. Transforms the game atmosphere into a melancholic, snowy city on Dec 31st. Weapon/Effect buttons now trigger Emotional Contrast Filters.
// @author       YouTubeDrawaria
// @match        https://drawaria.online/*
// @match        https://*.drawaria.online/*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @license      MIT
// @icon https://www.google.com/s2/favicons?sz=64&domain=drawaria.online
// ==/UserScript==

(function () {
    'use strict';

    /* ----------  EFECTOS REFLEXIVOS / CONTRASTES  ---------- */

    const REFLECTIVE_CONTRASTS = {
        'Ninguno': '',
        '❄️ Soledad del Invierno': 'effect:solitude_ice',
        '☕ Calor Interior': 'effect:inner_warmth',
        '🌫️ Niebla de la Memoria': 'effect:memory_fog',
        '⏳ Final de Ciclo': 'effect:end_cycle_vignette',
        '🌌 Conexión Humana': 'effect:human_connection',
        '💡 El Propósito (Raro)': 'effect:rare_purpose',
    };

    // Usaremos los mismos nombres de armas, pero su lógica será reflejar drama.
    const DRAMA_WEAPONS = {
        'Ninguno': '',
        '💔 Corazón Roto': 'drama:broken_heart',
        '⏳ Pasaje del Tiempo': 'drama:time_passage',
        '🏙️ Ciudad Despierta': 'drama:city_wakes',
        '💤 Sueño Profundo': 'drama:deep_sleep',
    };

    /* ----------  SETUP BÁSICO  ---------- */
    let socket;
    const canvas = document.getElementById('canvas');
    const ctx = canvas ? canvas.getContext('2d') : null;
    let stopSignal = false;
    let stopBtn;
    let activeEffectInterval = null;
    let isExecuting = false;

    // Almacena el filtro original del cuerpo para poder alternar.
    let originalBodyFilter = document.body.style.filter;

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

    // --- AMBIENTACIÓN MELANCÓLICA DE INVIERNO (NUEVO FONDO) ---
    GM_addStyle(`
        body {
            /* Nuevo Fondo de Noche Estrellada Melancólica */
            background-image: url('https://media.springernature.com/full/springer-static/image/art%3A10.1038%2F494027a/MediaObjects/41586_2013_BF494027a_Figa_HTML.jpg') !important;
            background-size: cover !important;
            background-attachment: fixed !important;
            background-color: #1a1a1a !important;
            /* Filtro Melancólico: Saturación baja, contraste suave, tono frío */
            filter: grayscale(30%) contrast(105%) hue-rotate(200deg) brightness(85%);
        }

        /* Ajustar el contenedor para ver el fondo */
        .wrapper {
            background-color: rgba(255, 255, 255, 0.9) !important;
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.5) !important;
        }

        /* Ajuste de colores del canvas para no ser demasiado vibrante */
        #game-canvas {
            filter: saturate(80%) contrast(100%);
        }
    `);


    /* ----------  INTERFAZ DE USUARIO (Menú de Contraste Emocional) ---------- */
    const container = document.createElement('div');
    container.style.cssText = `
        position:fixed; bottom:10px; right:10px; z-index:9999;
        /* Estilo de la Base del Menú (Inspirado en Solar Smash pero más suave) */
        background:linear-gradient(135deg, #2e1a1a, #21163e, #0f3460); /* Tonos más tierra/noche */
        color:#fff; padding:15px 20px; border-radius:15px;
        font-family: 'Segoe UI', Arial, sans-serif; font-size:13px;
        display:flex; flex-direction:column; gap:12px;
        box-shadow: 0 8px 25px rgba(0,0,0,0.8), inset 0 1px 0 rgba(255,255,255,0.1);
        border: 2px solid #b0c4de; /* Azul frío/Acero */
        min-width: 320px;
        backdrop-filter: blur(5px);
        cursor: default;
    `;

    // Título Melancólico
    const titleBar = document.createElement('div');
    titleBar.innerHTML = 'Drawaria Cold Ice Menu ❄️☃️';
    titleBar.style.cssText = `
        font-weight: bold; font-size: 16px; text-align: center; cursor: grab;
        background: linear-gradient(45deg, #a0522d, #deb887); /* Tonos de café y marrón */
        -webkit-background-clip: text; -webkit-text-fill-color: transparent;
        text-shadow: 0 0 10px rgba(160, 82, 45, 0.5);
        margin: -15px -20px 10px -20px; padding: 15px 20px;
        border-bottom: 2px solid rgba(176, 196, 222, 0.3);
        border-radius: 15px 15px 0 0;
    `;
    container.appendChild(titleBar);

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

    // Estilo de los Selectores de Contraste
    const solarInputStyle = `
        flex-grow: 1; padding: 8px 12px; border-radius: 8px;
        border: 2px solid #b0c4de; background: rgba(0, 20, 40, 0.8);
        color: #b0c4de; font-size: 13px; font-family: 'Segoe UI', monospace;
        transition: all 0.3s ease;
        appearance: none;
        /* Ícono de Flecha suave para el select */
        background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23b0c4de%22%20d%3D%22M287%2C197.3L159.2%2C69.5c-3.6-3.6-8.2-5.4-12.8-5.4s-9.2%2C1.8-12.8%2C5.4L5.4%2C197.3c-7.2%2C7.2-7.2%2C18.8%2C0%2C26c3.6%2C3.6%2C8.2%2C5.4%2C12.8%2C5.4s9.2%2C1.8%2C12.8%2C5.4l117%2C117c3.6%2C3.6%2C8.2%2C5.4%2C12.8%2C5.4s9.2%2C1.8%2C12.8%2C5.4l117-117c7.2-7.2%2C7.2-18.8%2C0-26C294.2%2C204.5%2C294.2%2C200.9%2C287%2C197.3z%22%2F%3E%3C%2Fsvg%3E');
        background-repeat: no-repeat;
        background-position: right 8px center;
        background-size: 12px;
        cursor: pointer;
    `;

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

    // **NOTA: El selector de jugadores se mantiene pero su propósito es simbólico (el 'Target' de la reflexión)**
    const playerSelect = document.createElement('select');
    playerSelect.style.cssText = solarInputStyle;
    // La función de actualización de jugadores se ejecuta más abajo.
    createSolarRow(contentDiv, '👤 Persona:', playerSelect);

    // Selector de Dramas
    const weaponSelect = document.createElement('select');
    weaponSelect.style.cssText = solarInputStyle;
    for (const name in DRAMA_WEAPONS) {
        const opt = document.createElement('option');
        opt.value = DRAMA_WEAPONS[name];
        opt.textContent = name;
        weaponSelect.appendChild(opt);
    }
    weaponSelect.value = DRAMA_WEAPONS['Ninguno'];
   // createSolarRow(contentDiv, '💔 Drama:', weaponSelect);

    // Selector de Efectos Reflexivos
    const effectSelect = document.createElement('select');
    effectSelect.style.cssText = solarInputStyle;
    for (const name in REFLECTIVE_CONTRASTS) {
        const opt = document.createElement('option');
        opt.value = REFLECTIVE_CONTRASTS[name];
        opt.textContent = name;
        effectSelect.appendChild(opt);
    }
    effectSelect.value = REFLECTIVE_CONTRASTS['Ninguno'];
   // createSolarRow(contentDiv, '✨ Contraste:', effectSelect);

    // Auto-reset de selectores (funcionalidad de exclusividad mutua se mantiene)
    weaponSelect.addEventListener('change', () => {
        if (weaponSelect.value !== '') {
            effectSelect.value = REFLECTIVE_CONTRASTS['Ninguno'];
        }
    });

    effectSelect.addEventListener('change', () => {
        if (effectSelect.value !== '') {
            weaponSelect.value = DRAMA_WEAPONS['Ninguno'];
        }
    });

    // Intensity slider (Ahora "Intensidad Emocional")
    const intensitySlider = document.createElement('input');
    intensitySlider.type = 'range';
    intensitySlider.min = '1';
    intensitySlider.max = '5';
    intensitySlider.value = '3';
    intensitySlider.style.cssText = `
        flex-grow: 1; -webkit-appearance: none; height: 6px; border-radius: 5px;
        background: linear-gradient(to right, #b0c4de 0%, #a0522d 100%); /* Azul Frío a Café Cálido */
        outline: none;
    `;
    createSolarRow(contentDiv, '🎭 Emoción:', intensitySlider);

    // Repeat toggle (Ahora "Ciclo Continuo")
    const repeatToggle = document.createElement('input');
    repeatToggle.type = 'checkbox';
    repeatToggle.id = 'solarRepeatToggle';
    repeatToggle.style.cssText = `margin-right: 8px; cursor: pointer; transform: scale(1.3);`;
    const repeatLabel = document.createElement('label');
    repeatLabel.htmlFor = 'solarRepeatToggle';
    repeatLabel.textContent = ' 🔄 Ciclo Continuo';
    repeatLabel.style.cssText = `display: flex; align-items: center; cursor: pointer; color: #b0c4de;`;
    const repeatWrapper = document.createElement('div');
    repeatWrapper.style.cssText = `display:flex; align-items:center; gap:0;`;
    repeatWrapper.appendChild(repeatToggle);
    repeatWrapper.appendChild(repeatLabel);
    contentDiv.appendChild(repeatWrapper);

    // Botones
    const executeBtn = document.createElement('button');
    executeBtn.textContent = '';
    executeBtn.disabled = true;
    executeBtn.style.cssText = `
        padding: 12px 20px; border-radius: 10px; border: none;
        background: linear-gradient(145deg, #a0522d, #deb887); /* Café Cálido */
        color: white; font-weight: bold; font-size: 15px;
        cursor: pointer; transition: all 0.3s ease;
        box-shadow: 0 4px 15px rgba(160, 82, 45, 0.4);
        text-transform: uppercase; letter-spacing: 1px;
    `;

    stopBtn = document.createElement('button');
    stopBtn.textContent = '';
    stopBtn.disabled = true;
    stopBtn.style.cssText = `
        margin-top: 8px; padding: 10px 18px; border-radius: 8px; border: none;
        background: linear-gradient(145deg, #444444, #666666); /* Gris Neutro */
        color: white; font-weight: bold; font-size: 14px;
        cursor: pointer; transition: all 0.3s ease;
        box-shadow: 0 4px 12px rgba(68, 68, 68, 0.4);
        text-transform: uppercase;
    `;

    contentDiv.appendChild(executeBtn);
    contentDiv.appendChild(stopBtn);
    document.body.appendChild(container);

    /* ----------  FUNCIONES REFLEXIVAS (REEMPLAZANDO ARMAS/EFECTOS) ---------- */

    function getPlayerCoords(playerId) {
        const avatar = document.querySelector(`.spawnedavatar[data-playerid="${playerId}"]`);
        if (!avatar) 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
        };
    }

    // Adaptación de la función de dibujo para enviar al socket (manteniendo la funcionalidad)
    function drawReflectiveCommand(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) return;
        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);
        // Usar la estructura de comando de Drawaria (asumiendo que es para dibujar líneas)
        const cmd = `42["drawcmd",0,[${normX1},${normY1},${normX2},${normY2},false,${0 - thickness},"${color}",0,0,{}]]`;
        // socket.send(cmd); // Comentado para evitar spam, descomentar si se desea que el dibujo se envíe
    }


    /* --- CONTRASTES (EFECTOS) --- */

    // ❄️ Soledad del Invierno (Filtro frío y temporal en el lienzo)
    async function solitudeIce(playerId, intensity = 3) {
        if (stopSignal) return;
        sendMessageToChat(`❄️ Se siente la Soledad del Invierno en el lienzo...`);
        const duration = 2000 + intensity * 500;

        // Efecto: Filtro de frío en el lienzo
        if (canvas) {
            canvas.style.transition = 'filter 1s ease-in-out';
            canvas.style.filter = 'grayscale(100%) contrast(150%) hue-rotate(180deg)';
        }

        await new Promise(r => setTimeout(r, duration));

        if (canvas) {
            canvas.style.filter = 'saturate(80%) contrast(100%)'; // Volver al filtro base
        }
    }

    // ☕ Calor Interior (Dibujo de humo de taza de café alrededor del objetivo)
    async function innerWarmth(playerId, intensity = 3) {
        if (stopSignal) return;
        sendMessageToChat(`☕ Un momento de Calor Interior rodea a la persona elegida...`);
        const target = getPlayerCoords(playerId);
        if (!target) return;

        const puffCount = 8 + intensity * 4;
        const colors = ['#f5f5dc', '#d2b48c', '#a0522d']; // Beige, Canela, Marrón Café

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

            // Simulación de una espiral de humo
            const smokeX = target.x + Math.sin(i * 0.5) * (10 + i * 2);
            const smokeY = target.y - 40 - i * 5;
            const color = colors[i % colors.length];

            // Dibujar el "humo" como líneas difusas
            for (let j = 0; j < 4; j++) {
                const startX = smokeX + (Math.random() - 0.5) * 5;
                const startY = smokeY + (Math.random() - 0.5) * 5;
                const endX = startX + (Math.random() - 0.5) * 15;
                const endY = startY - 10;
                drawReflectiveCommand(startX, startY, endX, endY, color, 3);
            }

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

    // 🌫️ Niebla de la Memoria (Filtro Blur temporal en toda la interfaz)
    async function memoryFog(playerId, intensity = 3) {
        if (stopSignal) return;
        sendMessageToChat(`🌫️ Una Niebla de la Memoria envuelve el mundo...`);
        const duration = 3000 + intensity * 1000;

        // Efecto: Filtro Blur en todo el cuerpo del documento
        document.body.style.transition = 'filter 2s ease-in-out';
        document.body.style.filter = 'blur(5px)';

        await new Promise(r => setTimeout(r, duration));

        document.body.style.filter = 'none';
        // Volver al filtro de ambiente (ya aplicado por GM_addStyle al inicio)
        document.body.style.filter = 'grayscale(30%) contrast(105%) hue-rotate(200deg) brightness(85%)';
    }

    // ⏳ Final de Ciclo (Vignette Oscuro y Desvanecimiento)
    async function endCycleVignette(playerId, intensity = 3) {
        if (stopSignal) return;
        sendMessageToChat(`⏳ El Final del Ciclo se acerca. El tiempo se desvanece...`);
        const duration = 2000 + intensity * 500;

        // Efecto: Vignetado oscuro y desvanecimiento
        document.body.style.transition = 'box-shadow 1s, opacity 1s';
        document.body.style.boxShadow = 'inset 0 0 100px rgba(0,0,0,0.9)';
        document.body.style.opacity = '0.5';

        await new Promise(r => setTimeout(r, duration));

        document.body.style.boxShadow = 'none';
        document.body.style.opacity = '1.0';
    }

    // 🌌 Conexión Humana (Líneas que conectan al objetivo con otros jugadores)
    async function humanConnection(playerId, intensity = 3) {
        if (stopSignal) return;
        sendMessageToChat(`🌌 El tejido de la Conexión Humana se revela...`);

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

        const playerElements = document.querySelectorAll('.spawnedavatar[data-playerid]');
        const connectionDuration = 1000 + intensity * 300;
        const color = '#ffbfff'; // Rosa claro (Tono de conexión)

        playerElements.forEach(el => {
            const connectedPlayerId = el.dataset.playerid;
            if (connectedPlayerId !== playerId) {
                const otherCoords = getPlayerCoords(connectedPlayerId);
                if (otherCoords) {
                    // Dibujar una línea de conexión
                    drawReflectiveCommand(target.x, target.y, otherCoords.x, otherCoords.y, color, 2);

                    // Efecto de pulso en el punto de conexión
                    for(let p = 0; p < 3; p++) {
                        const radius = 5 + p * 2;
                        for(let s = 0; s < 8; s++) {
                           drawReflectiveCommand(otherCoords.x, otherCoords.y,
                                                 otherCoords.x + radius * Math.cos(s),
                                                 otherCoords.y + radius * Math.sin(s), color, 1);
                        }
                    }
                }
            }
        });

        await new Promise(r => setTimeout(r, connectionDuration));
        // En este caso, no borramos el dibujo, permitimos que Drawaria lo borre naturalmente.
    }

    // 💡 El Propósito (Raro) - Invertir Colores de Interfaz (Contraste Extremo)
    async function rarePurpose(playerId, intensity = 3) {
        if (stopSignal) return;
        sendMessageToChat(`💡 **¡EL PROPÓSITO HA SIDO REVELADO!** (Contraste Extremo)`);
        const duration = 5000;

        // Inversión de colores para un contraste extremo entre la 'realidad' y el 'propósito'
        document.body.style.transition = 'filter 1s ease-in-out';
        document.body.style.filter = 'invert(100%) hue-rotate(180deg)';

        await new Promise(r => setTimeout(r, duration));

        // Volver al filtro de ambiente (y el filtro original del body)
        document.body.style.filter = 'grayscale(30%) contrast(105%) hue-rotate(200deg) brightness(85%)';
    }


    /* --- DRAMAS (ARMAS) --- */

    // Las funciones DRAMA no dibujarán, sino que cambiarán la percepción y el chat.

    // 💔 Corazón Roto (Filtro Sepia / Chat Triste)
    async function brokenHeart(playerId, intensity = 3) {
        if (stopSignal) return;
        sendMessageToChat(`💔 El Corazón Roto de la Persona se filtra en el ambiente...`);
        const duration = 4000;

        document.body.style.transition = 'filter 1s ease-in-out';
        document.body.style.filter = 'sepia(100%) saturate(150%)';

        await new Promise(r => setTimeout(r, duration));

        document.body.style.filter = 'grayscale(30%) contrast(105%) hue-rotate(200deg) brightness(85%)';
    }

    // ⏳ Pasaje del Tiempo (Acelerar y Ralentizar el juego)
    async function timePassage(playerId, intensity = 3) {
        if (stopSignal) return;
        sendMessageToChat(`⏳ El Pasaje del Tiempo se distorsiona...`);

        document.body.style.transition = 'all 0.5s ease-in-out';
        document.body.style.transform = 'scale(0.9)'; // Simular ralentización/enfoque

        await new Promise(r => setTimeout(r, 1500));

        document.body.style.transform = 'scale(1.1)'; // Simular aceleración/desenfoque

        await new Promise(r => setTimeout(r, 1500));

        document.body.style.transform = 'scale(1.0)';
    }

    // 🏙️ Ciudad Despierta (Alto Contraste y Brillo)
    async function cityWakes(playerId, intensity = 3) {
        if (stopSignal) return;
        sendMessageToChat(`🏙️ La Ciudad Despierta con un brillo cegador...`);
        const duration = 3000;

        document.body.style.transition = 'filter 1s ease-in-out';
        document.body.style.filter = 'contrast(200%) brightness(150%)';

        await new Promise(r => setTimeout(r, duration));

        document.body.style.filter = 'grayscale(30%) contrast(105%) hue-rotate(200deg) brightness(85%)';
    }

    // 💤 Sueño Profundo (Oscuridad extrema)
    async function deepSleep(playerId, intensity = 3) {
        if (stopSignal) return;
        sendMessageToChat(`💤 La mente se hunde en el Sueño Profundo...`);
        const duration = 2000;

        document.body.style.transition = 'filter 1s ease-in-out';
        document.body.style.filter = 'brightness(10%) grayscale(100%)';

        await new Promise(r => setTimeout(r, duration));

        document.body.style.filter = 'grayscale(30%) contrast(105%) hue-rotate(200deg) brightness(85%)';
    }


    /* ----------  FUNCIONES PRINCIPALES (MANTENIDAS)  ---------- */

    function updatePlayerOptions() {
        const currentSelection = playerSelect.value;
        playerSelect.innerHTML = '';
        const playerElements = document.querySelectorAll('.spawnedavatar[data-playerid], .playerlist-row[data-playerid]');
        const validPlayers = [];

        playerElements.forEach(el => {
            const playerId = el.dataset.playerid;
            if (!playerId || playerId === '0' || el.dataset.self === 'true') return;

            let playerName = '';
            const nicknameEl = el.querySelector('.nickname, .playerlist-name a, .player-name');
            if (nicknameEl) {
                playerName = nicknameEl.textContent.trim();
            } else {
                playerName = `Persona ${playerId}`;
            }

            if (!validPlayers.some(p => p.id === playerId)) {
                validPlayers.push({ id: playerId, name: playerName });
            }
        });

        if (validPlayers.length === 0) {
            const opt = document.createElement('option');
            opt.value = '';
            opt.textContent = '👤 No hay personajes.';
            playerSelect.appendChild(opt);
            executeBtn.disabled = true;
        } else {
            validPlayers.forEach(player => {
                const opt = document.createElement('option');
                opt.value = player.id;
                opt.textContent = `👤 ${player.name}`;
                playerSelect.appendChild(opt);
            });

            const stillExists = validPlayers.some(p => p.id === currentSelection);
            if (currentSelection && stillExists) {
                playerSelect.value = currentSelection;
            } else {
                playerSelect.selectedIndex = 0;
            }

            executeBtn.disabled = false;
        }
    }


    async function executeSolarAction() {
        if (isExecuting) return;

        const playerId = playerSelect.value;
        const weaponType = weaponSelect.value;
        const effectType = effectSelect.value;
        const intensity = parseInt(intensitySlider.value);
        const shouldRepeat = repeatToggle.checked;

        if (!playerId) {
            sendMessageToChat('🚫 Por favor selecciona un personaje (objetivo) válido.');
            return;
        }

        if (!weaponType && !effectType) {
            sendMessageToChat('🚫 Por favor selecciona un Drama o Contraste.');
            return;
        }

        isExecuting = true;
        stopSignal = false;
        executeBtn.disabled = true;
        stopBtn.disabled = false;

        do {
            try {
                if (weaponType) {
                    switch (weaponType) {
                        case 'drama:broken_heart': await brokenHeart(playerId, intensity); break;
                        case 'drama:time_passage': await timePassage(playerId, intensity); break;
                        case 'drama:city_wakes': await cityWakes(playerId, intensity); break;
                        case 'drama:deep_sleep': await deepSleep(playerId, intensity); break;
                    }
                }

                if (effectType) {
                    switch (effectType) {
                        case 'effect:solitude_ice': await solitudeIce(playerId, intensity); break;
                        case 'effect:inner_warmth': await innerWarmth(playerId, intensity); break;
                        case 'effect:memory_fog': await memoryFog(playerId, intensity); break;
                        case 'effect:end_cycle_vignette': await endCycleVignette(playerId, intensity); break;
                        case 'effect:human_connection': await humanConnection(playerId, intensity); break;
                        case 'effect:rare_purpose': await rarePurpose(playerId, intensity); break;
                    }
                }

                if (shouldRepeat && !stopSignal) {
                    await new Promise(r => setTimeout(r, 1000));
                }

            } catch (error) {
                console.error('☕ Error ejecutando Reflexión:', error);
                break;
            }
        } while (shouldRepeat && !stopSignal);

        isExecuting = false;
        executeBtn.disabled = false;
        stopBtn.disabled = true;
        sendMessageToChat('🎬 Secuencia Reflexiva completada.');
    }

    function stopExecution() {
        stopSignal = true;
        isExecuting = false;
        if (activeEffectInterval) {
            clearInterval(activeEffectInterval);
            activeEffectInterval = null;
        }
        executeBtn.disabled = false;
        stopBtn.disabled = true;

        // Limpiar efectos visuales globales
        document.body.style.filter = 'grayscale(30%) contrast(105%) hue-rotate(200deg) brightness(85%)';
        document.body.style.boxShadow = 'none';
        document.body.style.opacity = '1.0';
        document.body.style.transform = 'scale(1.0)';
        if(canvas) canvas.style.filter = 'saturate(80%) contrast(100%)';

        sendMessageToChat('⏸️ Vignette detenida por el usuario.');
    }

    /* ----------  EVENT LISTENERS Y INICIALIZACIÓN  ---------- */

    executeBtn.addEventListener('click', executeSolarAction);
    stopBtn.addEventListener('click', stopExecution);

    // Actualizar jugadores cada 2 segundos
    setInterval(updatePlayerOptions, 2000);
    updatePlayerOptions();

    // Lógica de arrastre
    let isDragging = false;
    let dragOffsetX = 0;
    let dragOffsetY = 0;

    titleBar.addEventListener('mousedown', (e) => {
        isDragging = true;
        dragOffsetX = e.clientX - container.offsetLeft;
        dragOffsetY = e.clientY - container.offsetTop;
        titleBar.style.cursor = 'grabbing';
    });

    document.addEventListener('mousemove', (e) => {
        if (isDragging) {
            container.style.left = (e.clientX - dragOffsetX) + 'px';
            container.style.top = (e.clientY - dragOffsetY) + 'px';
            container.style.right = 'auto';
            container.style.bottom = 'auto';
        }
    });

    document.addEventListener('mouseup', () => {
        isDragging = false;
        titleBar.style.cursor = 'grab';
    });

    // Efectos hover para los controles
    [executeBtn, stopBtn, playerSelect, weaponSelect, effectSelect].forEach(element => {
        element.addEventListener('mouseenter', () => {
            element.style.transform = 'translateY(-2px)';
            element.style.boxShadow = element.style.boxShadow.replace(/rgba$$[^)]+$$/, 'rgba(176, 196, 222, 0.6)');
        });

        element.addEventListener('mouseleave', () => {
            element.style.transform = 'translateY(0)';
            const isExecute = element === executeBtn;
            const shadowColor = isExecute ? 'rgba(160, 82, 45, 0.4)' : 'rgba(68, 68, 68, 0.4)';
            element.style.boxShadow = `0 4px 1${isExecute ? 5 : 2}px ${shadowColor}`;
        });
    });

    sendMessageToChat('☕ **[ÚLTIMO AUTOBÚS]:** El guion de Drama y Reflexión se ha cargado. Escoge un "Contraste" para tu experiencia.');
})();