Drawaria The Cauldron of Curses (Halloween)

Unleash chilling spectral hexes and auras to sabotage Drawaria players with true Halloween malice.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Drawaria The Cauldron of Curses (Halloween)
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  Unleash chilling spectral hexes and auras to sabotage Drawaria players with true Halloween malice.
// @author       SpectralSaboteur
// @match        https://drawaria.online/*
// @match        https://*.drawaria.online/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=drawaria.online
// @grant        GM_xmlhttpRequest
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    /* ----------  CONFIGURACIÓN DE MALDICIONES Y AURAS  ---------- */

    // Hexes (Armas) de sabotaje espectral
    const HALLOWEEN_HEXES = {
        'Ninguno': '',
        '🧛 Vampire\'s Kiss': 'hex:vampires_kiss',         // Drains color palette (visual effect)
        '👻 Phantom\'s Glitch': 'hex:phantom_glitch',       // Chaotic drawing coordinates
        '🎃 Pumpkin King\'s Seal': 'hex:pumpkin_seal',     // Massive circular orange stamp
        '🕷️ Spider Rain': 'hex:spider_rain',
        '💀 Death Mark': 'hex:death_mark',
        '⚰️ Coffin Drop': 'hex:coffin_drop',
        '🔥 Hellfire Breath': 'hex:hellfire_breath',
        '👁️ Evil Eye Curse': 'hex:evil_eye',
        '⛓️ Chains of Torment': 'hex:chains_torment',
        '🔪 Butcher\'s Block': 'hex:butchers_block',
        '🌑 Dark Vortex': 'hex:dark_vortex',
        '🌕 Lunatic Grin': 'hex:lunatic_grin',
        '🧪 Potion of Chaos': 'hex:potion_chaos',
        '⚡ Lightning Strike': 'hex:lightning_strike',
        '🩸 Blood Splatter': 'hex:blood_splatter'
    };

    // Auras (Efectos) de sabotaje persistente
    const SPECTRAL_AURAS = {
        'Ninguno': '',
        '🛡️ Spectral Ward': 'aura:spectral_ward',          // Green/purple shield (for consistency with original)
        '🌫️ Graveyard Fog': 'aura:graveyard_fog',          // Dims the canvas
        '🧪 Ectoplasmic Slime': 'aura:ectoplasm_slime',    // Shimmering green border
        '💀 Haunting Glare': 'aura:haunting_glare',
        '🕯️ Candlelight Flicker': 'aura:candlelight_flicker',
        '🌀 Poltergeist Spin': 'aura:poltergeist_spin',
        '⭐ Demonic Rune': 'aura:demonic_rune',
        '🌑 Void Distortion': 'aura:void_distortion'
    };

    const DEFAULT_HEX_NAME = 'Ninguno';
    const DEFAULT_AURA_NAME = 'Ninguno';

    /* ----------  CONSTANTES DE EFECTOS  ---------- */
    const EFFECT_DURATION_BASE = 100; // ms base entre frames

    /* ----------  SETUP BÁSICO Y SOCKET  ---------- */
    let socket;
    const canvas = document.getElementById('canvas');
    const ctx = canvas ? canvas.getContext('2d') : null;

    let stopSignal = false;
    let stopBtn;
    let activeEffectInterval = null;

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

    /* ----------  INTERFAZ DE USUARIO (CAULDRON OF CURSES)  ---------- */
    const container = document.createElement('div');
    container.style.cssText = `
        position:fixed; bottom:10px; right:10px; z-index:9999;
        background: radial-gradient(circle at top left, #330033 0%, #000000 100%);
        color:#ffcc00; padding:15px 20px; border-radius:15px;
        font-family: 'Creepster', 'Times New Roman', serif; font-size:14px;
        display:flex; flex-direction:column; gap:12px;
        box-shadow: 0 8px 30px rgba(100,0,100,0.9), inset 0 1px 0 rgba(255,100,255,0.1);
        border: 3px ridge #4b0082; /* Deep Purple/Indigo for spooky border */
        min-width: 320px;
        backdrop-filter: blur(5px);
        transform: rotateZ(1deg); /* Slight tilt for unsettling look */
    `;

    // Custom Font Styling (Optional: Requires loading a spooky font like 'Creepster')
    const fontLink = document.createElement('link');
    fontLink.href = 'https://fonts.googleapis.com/css2?family=Creepster&display=swap';
    fontLink.rel = 'stylesheet';
    document.head.appendChild(fontLink);

    const titleBar = document.createElement('div');
    titleBar.innerHTML = '⚰️ THE CAULDRON OF CURSES ⚰️';
    titleBar.style.cssText = `
        font-weight: bold; font-size: 20px; text-align: center; cursor: grab;
        background: linear-gradient(45deg, #8b0000, #ff00ff, #330033);
        -webkit-background-clip: text; -webkit-text-fill-color: transparent;
        text-shadow: 0 0 10px rgba(255, 0, 0, 0.7), 0 0 20px rgba(255, 100, 255, 0.5);
        margin: -15px -20px 10px -20px; padding: 15px 20px;
        border-bottom: 2px dashed #ff00ff;
        border-radius: 15px 15px 0 0;
        font-family: 'Creepster', cursive;
    `;
    container.appendChild(titleBar);

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

    const spookyInputStyle = `
        flex-grow: 1; padding: 10px 15px; border-radius: 5px;
        border: 2px solid #ff00ff; background: rgba(0, 0, 0, 0.7);
        color: #ffcc00; font-size: 14px; font-family: 'Creepster', monospace;
        transition: all 0.3s ease;
        &:focus { box-shadow: 0 0 15px rgba(255, 0, 255, 0.7); border-color: #ff0000; }
    `;

    function createSpookyRow(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: #ffcc00; font-weight: bold; min-width: 120px; text-shadow: 1px 1px 2px #000;`;
        wrapper.appendChild(label);
        wrapper.appendChild(inputElement);
        parent.appendChild(wrapper);
        return { wrapper, label, inputElement };
    }

    // Selector de jugadores (Victim)
    const playerSelect = document.createElement('select');
    playerSelect.style.cssText = spookyInputStyle;
    createSpookyRow(contentDiv, '💀 Victim:', playerSelect);

    // Selector de hexes
    const hexSelect = document.createElement('select');
    hexSelect.style.cssText = spookyInputStyle;
    for (const name in HALLOWEEN_HEXES) {
        const opt = document.createElement('option');
        opt.value = HALLOWEEN_HEXES[name];
        opt.textContent = name;
        hexSelect.appendChild(opt);
    }
    hexSelect.value = HALLOWEEN_HEXES[DEFAULT_HEX_NAME];
    createSpookyRow(contentDiv, '🔮 Hex:', hexSelect);

    // Selector de auras
    const auraSelect = document.createElement('select');
    auraSelect.style.cssText = spookyInputStyle;
    for (const name in SPECTRAL_AURAS) {
        const opt = document.createElement('option');
        opt.value = SPECTRAL_AURAS[name];
        opt.textContent = name;
        auraSelect.appendChild(opt);
    }
    auraSelect.value = SPECTRAL_AURAS[DEFAULT_AURA_NAME];
    createSpookyRow(contentDiv, '👻 Aura:', auraSelect);

    // Auto-reset de selectores
    hexSelect.addEventListener('change', () => {
        if (hexSelect.value !== '') auraSelect.value = SPECTRAL_AURAS['Ninguno'];
    });

    auraSelect.addEventListener('change', () => {
        if (auraSelect.value !== '') hexSelect.value = HALLOWEEN_HEXES['Ninguno'];
    });

    // Nivel de Potencia (Potency Level)
    const potencyInput = document.createElement('input');
    potencyInput.type = 'range';
    potencyInput.min = '1';
    potencyInput.max = '5';
    potencyInput.value = '3';
    potencyInput.style.cssText = `
        flex-grow: 1; accent-color: #ff0000;
        background: linear-gradient(to right, #ffcc00, #ff0000);
    `;

    const potencyLabel = document.createElement('span');
    potencyLabel.textContent = '🧪 Potency Level: (Mischief)';
    potencyLabel.style.cssText = `color: #ffcc00; font-weight: bold; min-width: 120px; text-shadow: 1px 1px 2px #000;`;

    potencyInput.addEventListener('input', () => {
        const levels = { 1: 'Mischief', 2: 'Prank', 3: 'Curse', 4: 'Hex', 5: 'Malice' };
        potencyLabel.textContent = `🧪 Potency Level: (${levels[potencyInput.value]})`;
    });

    const potencyWrapper = document.createElement('div');
    potencyWrapper.style.cssText = `display:flex; align-items:center; gap:12px;`;
    potencyWrapper.appendChild(potencyLabel);
    potencyWrapper.appendChild(potencyInput);
    contentDiv.appendChild(potencyWrapper);


    // Toggle de repetición (Eternal Torment)
    const repeatToggle = document.createElement('input');
    repeatToggle.type = 'checkbox';
    repeatToggle.style.cssText = `transform: scale(1.5); accent-color: #ff00ff;`;
    const repeatLabel = document.createElement('label');
    repeatLabel.textContent = ' ⚰️ Eternal Torment';
    repeatLabel.style.cssText = `color: #ff00ff; font-weight: bold; cursor: pointer; text-shadow: 0 0 5px rgba(255, 0, 255, 0.7);`;
    const repeatWrapper = document.createElement('div');
    repeatWrapper.style.cssText = `display:flex; align-items:center; gap:8px; justify-content: center; margin-top: 10px;`;
    repeatWrapper.appendChild(repeatToggle);
    repeatWrapper.appendChild(repeatLabel);
    contentDiv.appendChild(repeatWrapper);

    // Botón de activación
    const destroyBtn = document.createElement('button');
    destroyBtn.textContent = '🟢 UNLEASH THE HEX! 🟢';
    destroyBtn.disabled = true;
    destroyBtn.style.cssText = `
        padding: 12px 20px; border-radius: 10px; border: 2px solid #00ff00;
        background: linear-gradient(45deg, #008000, #004d00);
        color: white; font-weight: bold; font-size: 18px;
        cursor: pointer; transition: all 0.3s ease;
        box-shadow: 0 4px 15px rgba(0, 255, 0, 0.5);
        text-shadow: 0 0 5px #000;
        font-family: 'Creepster', sans-serif;
        &:hover {
            background: linear-gradient(45deg, #00ff00, #00b300);
            box-shadow: 0 6px 20px rgba(0, 255, 0, 0.8);
            transform: translateY(-2px);
        }
        &:disabled {
            background: #666; cursor: not-allowed; opacity: 0.5;
            box-shadow: none; transform: none;
        }
    `;
    contentDiv.appendChild(destroyBtn);

    // Botón de parada (Vanish Spirit)
    stopBtn = document.createElement('button');
    stopBtn.textContent = '🔥 VANISH SPIRIT 🔥';
    stopBtn.disabled = true;
    stopBtn.style.cssText = `
        margin-top: 8px; padding: 10px 16px; border-radius: 8px; border: 2px solid #ff0000;
        background: linear-gradient(45deg, #8b0000, #4d0000);
        color: white; font-weight: bold; font-size: 16px;
        cursor: pointer; transition: all 0.3s ease;
        box-shadow: 0 4px 10px rgba(255, 0, 0, 0.5);
        font-family: 'Creepster', sans-serif;
        &:hover {
            background: linear-gradient(45deg, #ff0000, #b30000);
            transform: translateY(-1px);
        }
        &:disabled {
            background: #666; cursor: not-allowed; opacity: 0.5;
            transform: none;
        }
    `;
    contentDiv.appendChild(stopBtn);

    document.body.appendChild(container);

    /* ----------  FUNCIONES DE SABOTAJE ESPECTRAL  ---------- */

    // Función base para dibujar/lanzar hex
    function castSpectralLine(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) {
            // Client-side draw (for visual feedback on own screen)
            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;

        // Server-side draw command (the actual sabotage)
        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);
        // Note: The thickness is sent as a *negative* value to Drawaria for thicker lines
        const cmd = `42["drawcmd",0,[${normX1},${normY1},${normX2},${normY2},false,${0 - thickness},"${color}",0,0,{}]]`;
        socket.send(cmd);
    }

    // Obtener coordenadas del jugador víctima
    function getPlayerCoords(playerId) {
        // Find the player's avatar on the canvas
        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
        };
    }

    /* ----------  HALLOWEEN HEXES  ---------- */

    // 1. Vampire's Kiss (Drains color palette)
    async function vampiresKiss(playerId, potency = 3) {
        if (stopSignal) return;
        console.log(`🧛 Casting Vampire's Kiss on victim ${playerId} (Potency: ${potency})`);

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

        const drainCount = 10 + (potency * 4);
        const colors = ['#8B0000', '#4B0082', '#000000']; // Deep red, indigo, black

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

            const startX = target.x + (Math.random() - 0.5) * 100;
            const startY = target.y - 100 + Math.random() * 50;
            const endX = target.x + (Math.random() - 0.5) * 20;
            const endY = target.y + (Math.random() - 0.5) * 10;

            const color = colors[Math.floor(Math.random() * colors.length)];
            const thickness = 2 + Math.random() * potency * 0.5;

            // Draw draining lines converging on the target
            castSpectralLine(startX, startY, endX, endY, color, thickness);

            await new Promise(r => setTimeout(r, 80 - (potency * 10)));
        }
    }

    // 2. Pumpkin King's Seal (Massive circular orange stamp)
    async function pumpkinKingsSeal(playerId, potency = 3) {
        if (stopSignal) return;
        console.log(`🎃 Sealing victim ${playerId} with the Pumpkin King's mark (Potency: ${potency})`);

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

        const sealCount = 5 + (potency * 3);
        const colors = ['#FF7518', '#FF4500', '#FFA500']; // Pumpkin Orange/Red/Yellow

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

            const centerX = target.x + (Math.random() - 0.5) * 50;
            const centerY = target.y + (Math.random() - 0.5) * 30;
            const radius = 30 + potency * 15;

            // Draw a massive circle stamp
            for (let angle = 0; angle < 16; angle++) {
                const radians = (angle / 16) * 2 * Math.PI;
                const x = centerX + radius * Math.cos(radians);
                const y = centerY + radius * Math.sin(radians);
                const color = colors[i % colors.length];

                // Draw lines from center to perimeter to simulate a solid circle/stamp
                castSpectralLine(centerX, centerY, x, y, color, 10 + potency);
            }

            await new Promise(r => setTimeout(r, 150 - (potency * 10)));
        }
    }

    // 3. Phantom's Glitch (Chaotic drawing coordinates)
    async function phantomsGlitch(playerId, potency = 3) {
        if (stopSignal) return;
        console.log(`👻 Initiating Phantom's Glitch on victim ${playerId} (Potency: ${potency})`);

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

        const glitchDuration = 1500 + potency * 500;
        const startTime = Date.now();
        const colors = ['#00FF00', '#00FFFF', '#FF00FF', '#FFFFFF']; // Neon, spectral colors

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

            const glitchCount = 5 + potency;
            const maxDisplacement = 50 + potency * 20;

            for (let i = 0; i < glitchCount; i++) {
                const startX = target.x + (Math.random() - 0.5) * maxDisplacement;
                const startY = target.y + (Math.random() - 0.5) * maxDisplacement;
                const endX = startX + (Math.random() - 0.5) * 30;
                const endY = startY + (Math.random() - 0.5) * 30;

                const color = colors[Math.floor(Math.random() * colors.length)];
                const thickness = 1 + Math.random() * potency * 0.5;

                // Draw short, chaotic, glowing lines
                castSpectralLine(startX, startY, endX, endY, color, thickness);
            }

            await new Promise(r => setTimeout(r, 50 - (potency * 5)));
        }
    }

    /* --- Placeholder Hexes (Mapping to existing logic for full menu) --- */
    // Reusing the original mod's structure for the other 12 hexes/auras by mapping them
    // to the three new core functions, adjusted by potency.

    // Helper to map hexes to functions
    const hexFunctionMap = {
        'hex:vampires_kiss': vampiresKiss,
        'hex:phantom_glitch': phantomsGlitch,
        'hex:pumpkin_seal': pumpkinKingsSeal,
        'hex:spider_rain': (id, p) => phantomsGlitch(id, p + 1),
        'hex:death_mark': (id, p) => pumpkinKingsSeal(id, p),
        'hex:coffin_drop': (id, p) => vampiresKiss(id, p * 2),
        'hex:hellfire_breath': (id, p) => pumpkinKingsSeal(id, p * 2),
        'hex:evil_eye': (id, p) => vampiresKiss(id, p + 1),
        'hex:chains_torment': (id, p) => phantomsGlitch(id, p + 1),
        'hex:butchers_block': (id, p) => pumpkinKingsSeal(id, p * 1.5),
        'hex:dark_vortex': (id, p) => phantomsGlitch(id, p * 2),
        'hex:lunatic_grin': (id, p) => vampiresKiss(id, p * 1.5),
        'hex:potion_chaos': (id, p) => phantomsGlitch(id, p * 1.5),
        'hex:lightning_strike': (id, p) => vampiresKiss(id, p),
        'hex:blood_splatter': (id, p) => pumpkinKingsSeal(id, p)
    };

    /* ----------  SPECTRAL AURAS (PERSISTENT EFFECTS)  ---------- */

    // 1. Graveyard Fog (Dims the canvas)
    async function graveyardFog(playerId, potency = 3) {
        if (stopSignal) return;
        console.log(`🌫️ Applying Graveyard Fog to victim ${playerId} (Potency: ${potency})`);

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

        // Draw a large, dark, semi-transparent box over the canvas repeatedly.
        const color = `rgba(0, 0, 0, ${0.1 + potency * 0.05})`; // Increasing darkness
        const thickness = canvas.width / 2; // Make it a large stroke to cover

        // We only cast a single dark line across the whole screen's center
        // to minimize spam, relying on the line thickness to cover the area.
        castSpectralLine(0, canvas.height / 2, canvas.width, canvas.height / 2, color, thickness);
    }

    // 2. Ectoplasmic Slime (Shimmering green border)
    async function ectoplasmicSlime(playerId, potency = 3) {
        if (stopSignal) return;
        console.log(`🧪 Applying Ectoplasmic Slime to canvas (Potency: ${potency})`);

        if (!canvas) return;

        const colors = ['#39ff14', '#00cc00', '#aaffaa']; // Neon green slime
        const thickness = 5 + potency * 2;
        const offset = Math.random() * 5; // Shimmer effect

        // Draw four lines to form a border
        // Top
        castSpectralLine(0 - offset, 0 - offset, canvas.width + offset, 0 - offset, colors[0], thickness);
        // Bottom
        castSpectralLine(0 - offset, canvas.height + offset, canvas.width + offset, canvas.height + offset, colors[1], thickness);
        // Left
        castSpectralLine(0 - offset, 0 - offset, 0 - offset, canvas.height + offset, colors[2], thickness);
        // Right
        castSpectralLine(canvas.width + offset, 0 - offset, canvas.width + offset, canvas.height + offset, colors[0], thickness);
    }

    // Helper to map auras to functions
    const auraFunctionMap = {
        'aura:spectral_ward': (id, p) => ectoplasmicSlime(id, p / 2),
        'aura:graveyard_fog': graveyardFog,
        'aura:ectoplasm_slime': ectoplasmicSlime,
        'aura:haunting_glare': (id, p) => graveyardFog(id, p * 1.5),
        'aura:candlelight_flicker': (id, p) => ectoplasmicSlime(id, p),
        'aura:poltergeist_spin': (id, p) => graveyardFog(id, p),
        'aura:demonic_rune': (id, p) => ectoplasmicSlime(id, p * 1.5),
        'aura:void_distortion': (id, p) => graveyardFog(id, p * 2)
    };

    /* ----------  SISTEMA DE GESTIÓN DE JUGADORES (VICTIMS)  ---------- */

    // (Player list logic remains the same, only renaming labels)
    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 || `Victim ${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 = playerSelect.value;

        playerSelect.innerHTML = '';

        playerRows.forEach(row => {
            if (row.dataset.self === 'true') return;
            if (row.dataset.playerid === '0') return;
            const name = row.querySelector('.playerlist-name a')?.textContent || `Victim ${row.dataset.playerid}`;
            const opt = document.createElement('option');
            opt.value = row.dataset.playerid;
            opt.textContent = `💀 ${name}`;
            playerSelect.appendChild(opt);
        });

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

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

    /* ----------  EVENTOS PRINCIPALES  ---------- */

    // Dragging logic (renamed for theme)
    let isDragging = false;
    let offsetX, offsetY;

    titleBar.addEventListener('mousedown', (e) => {
        isDragging = true;
        titleBar.style.cursor = 'grabbing';
        offsetX = e.clientX - container.getBoundingClientRect().left;
        offsetY = e.clientY - container.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 - container.offsetWidth));
        newY = Math.max(0, Math.min(newY, window.innerHeight - container.offsetHeight));
        container.style.left = newX + 'px';
        container.style.top = newY + 'px';
        container.style.right = 'auto'; // Disable right/bottom styles during drag
        container.style.bottom = 'auto';
    });

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

    // Botón de parada de emergencia (Vanish Spirit)
    stopBtn.addEventListener('click', () => {
        console.log('🔥 VANISH SPIRIT: Hexes Dispersed.');
        stopSignal = true;

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

        destroyBtn.textContent = '🟢 UNLEASH THE HEX! 🟢';
        destroyBtn.style.background = 'linear-gradient(45deg, #008000, #004d00)';
        destroyBtn.disabled = false;
        stopBtn.disabled = true;
    });

    // Botón principal de sabotaje (Unleash the Hex!)
    destroyBtn.addEventListener('click', async () => {
        const playerId = playerSelect.value;
        if (!playerId) {
            alert('💀 Please select a victim first!');
            return;
        }

        const selectedHex = hexSelect.value;
        const selectedAura = auraSelect.value;
        const potency = parseInt(potencyInput.value);

        // Toggle Continuous/Eternal Torment off if already running
        if (activeEffectInterval) {
            console.log('Stopping Eternal Torment...');
            stopSignal = true;
            clearInterval(activeEffectInterval);
            activeEffectInterval = null;
            destroyBtn.textContent = '🟢 UNLEASH THE HEX! 🟢';
            destroyBtn.style.background = 'linear-gradient(45deg, #008000, #004d00)';
            stopBtn.disabled = true;
            return;
        }

        let actionToExecute = null;

        // Select Hex or Aura
        if (selectedHex && selectedHex.startsWith('hex:')) {
            actionToExecute = hexFunctionMap[selectedHex];
        } else if (selectedAura && selectedAura.startsWith('aura:')) {
            actionToExecute = auraFunctionMap[selectedAura];
        } else {
            alert('🔮 Please select a Hex or Aura to unleash!');
            return;
        }

        if (!actionToExecute) {
            alert('⚠️ Curse not implemented! The spirits refuse.');
            return;
        }

        stopSignal = false;
        destroyBtn.disabled = true;
        stopBtn.disabled = false;

        try {
            if (repeatToggle.checked) {
                destroyBtn.textContent = '💀 END TORMENT 💀';
                destroyBtn.style.background = 'linear-gradient(45deg, #8b0000, #ff0000)';
                destroyBtn.disabled = false;

                console.log('🔥 Initiating Eternal Torment...');

                const continuousTorment = async () => {
                    if (stopSignal || !repeatToggle.checked) {
                        if (activeEffectInterval) clearInterval(activeEffectInterval);
                        activeEffectInterval = null;
                        destroyBtn.textContent = '🟢 UNLEASH THE HEX! 🟢';
                        destroyBtn.style.background = 'linear-gradient(45deg, #008000, #004d00)';
                        stopBtn.disabled = true;
                        return;
                    }

                    try {
                        await actionToExecute(playerId, potency);
                    } catch (error) {
                        console.error('Error during Eternal Torment:', error);
                    }
                };

                await continuousTorment(); // First execution
                if (!stopSignal) {
                    // Repeat at a speed based on potency for non-aura effects
                    const intervalSpeed = selectedHex ? 3000 - (potency * 400) : 500;
                    activeEffectInterval = setInterval(continuousTorment, intervalSpeed);
                }
            } else {
                console.log('💥 Executing One-Shot Curse...');
                await actionToExecute(playerId, potency);
            }
        } finally {
            if (!activeEffectInterval) {
                destroyBtn.disabled = false;
                stopBtn.disabled = true;
            }
        }
    });

    // Observar cambios en la lista de jugadores
    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
    window.addEventListener('beforeunload', () => {
        if (activeEffectInterval) {
            clearInterval(activeEffectInterval);
            activeEffectInterval = null;
        }
        stopSignal = true;
    });

    // Inicialización
    refreshPlayerList();
    potencyLabel.textContent = `🧪 Potency Level: (Curse)`; // Set default label
    console.log('⚰️ The Cauldron of Curses Mod loaded successfully! ⚰️');

})();