您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Use the Smash Attack, throw Poké Balls, and use the Hammer! Turn Drawaria into a Smash Bros. battlefield.
// ==UserScript== // @name 🎮 Smash Companion Mod (Super Smash Bros. Edition) // @namespace http://tampermonkey.net/ // @version 1.0 // @description Use the Smash Attack, throw Poké Balls, and use the Hammer! Turn Drawaria into a Smash Bros. battlefield. // @author YouTubeDrawaria // @match https://drawaria.online/* // @match https://*.drawaria.online/* // @icon https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/e558db9c-ca9a-4fb7-af65-60c6c53244b8/dhduvrg-6a9727d6-2bfe-4ae2-87b5-61e394a89b6c.png/v1/fill/w_894,h_894/super_smash_bros_ultimate_dock_icon_by_lexiloo826_dhduvrg-pre.png?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7ImhlaWdodCI6Ijw9OTAwIiwicGF0aCI6Ii9mL2U1NThkYjljLWNhOWEtNGZiNy1hZjY1LTYwYzZjNTMyNDRiOC9kaGR1dnJnLTZhOTcyN2Q2LTJiZmUtNGFlMi04N2I1LTYxZTM5NGE4OWI2Yy5wbmciLCJ3aWR0aCI6Ijw9OTAwIn1dXSwiYXVkIjpbInVybjpzZXJ2aWNlOmltYWdlLm9wZXJhdGlvbnMiXX0.y8Gr96_NJdBcU6cxuCE0m_lnE6tnd-Bcxo8J_jipKAU // @grant GM_xmlhttpRequest // @license MIT // ==/UserScript== (function () { 'use strict'; /* ---------------------------------------------------------------------------------- // CONFIGURACIÓN Y ASSETS DE SUPER SMASH BROS. // ---------------------------------------------------------------------------------- */ // Colores de la paleta Smash (Ataques, Daño, Ítems y Efectos) const SSB_COLORS = { 'R': '#FF0000', // Rojo (Daño Alto / Explosión) 'B': '#0000FF', // Azul (Ataque de Hielo / Escudo) 'Y': '#FFFF00', // Amarillo (Estrellas / Impacto) 'P': '#FF00FF', // Rosa/Fucsia (Efecto de Hada / Curación) 'G': '#00FF00', // Verde (Curación/Vida) 'K': '#000000', // Negro (Bordes / Humo) 'W': '#FFFFFF', // Blanco (Brillo / Rayo) 'S': '#A9A9A9' // Gris Plata (Escudo Roto / Martillo) }; // Estructuras de Pixel Art detalladas (Iconos de Batalla e Ítems) const SSB_PIXEL_ASSETS = { // Estrellas de KO (Impacto) 'KO_STARS': { art: [ " Y Y ", " Y Y Y ", "Y Y W Y Y", " Y Y Y ", " Y Y " ], colors: { 'Y': SSB_COLORS.Y, 'W': SSB_COLORS.W, 'K': SSB_COLORS.K } }, // Pokebola (Lanzamiento) 'POKEBALL': { art: [ " R R ", " R W R ", "R W K W R", " R K R ", " K K " ], colors: { 'R': SSB_COLORS.R, 'W': SSB_COLORS.W, 'K': SSB_COLORS.K } }, // Martillo (Item) 'HAMMER_HEAD': { art: [ " S S S ", "S S S S", " S S S ", " S G S ", " S G S " ], colors: { 'S': SSB_COLORS.S, 'G': SSB_COLORS.G } } }; // Ataques Especiales (Special Moves) const SSB_ATTACKS = { 'Ninguno': '', '🤜 Ataque Smash (KO)': 'attack:smash_fist_ko', '🔥 Bola de Fuego (Mario/MegaMan)': 'attack:fireball_flinch', '🧊 Ataque de Hielo (Ice Climbers)': 'attack:ice_blast_freeze', }; // Ítems y Buffs (Items & Status) const SSB_ITEMS = { 'Ninguno': '', '💊 Cápsula de Curación': 'item:capsule_heal', '🔨 Martillo (Furia)': 'item:hammer_fury', '🌟 Estrella de Invencibilidad': 'item:star_invincibility', '📦 Pokebola (Lanzamiento)': 'item:pokeball_launch', }; const DAMAGE_PERCENT_LABELS = ['0% (Verde)', '50% (Amarillo)', '100% (Naranja)', '150% (Rojo)', '300% (Mortal)']; /* ---------------------------------------------------------------------------------- // SETUP BASE (Conexión y Canvas) // ---------------------------------------------------------------------------------- */ let socket; const canvas = document.getElementById('canvas'); const ctx = canvas ? canvas.getContext('2d') : null; let stopSignal = false; let activePowerInterval = null; let stopBtn; const originalSend = WebSocket.prototype.send; WebSocket.prototype.send = function (...args) { if (!socket) socket = this; return originalSend.apply(this, args); }; function getPlayerCoords(playerId) { const avatar = document.querySelector(`.spawnedavatar[data-playerid="${playerId}"]`); if (!avatar || !canvas) return null; const cRect = canvas.getBoundingClientRect(); const aRect = avatar.getBoundingClientRect(); return { x: Math.round((aRect.left - cRect.left) + (aRect.width / 2)), y: Math.round((aRect.top - cRect.top) + (aRect.height / 2)), width: aRect.width, height: aRect.height }; } /* ---------------------------------------------------------------------------------- // NÚCLEO DE DIBUJO: DETALLE Y SINCRONIZACIÓN (PIXEL ART) // ---------------------------------------------------------------------------------- */ function drawLocalLine(x1, y1, x2, y2, color, thickness) { if (!ctx) return; const actualThickness = Math.abs(thickness); ctx.beginPath(); ctx.strokeStyle = color; ctx.lineWidth = actualThickness; ctx.lineCap = 'butt'; ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); ctx.closePath(); } function sendRemoteDrawCommand(x1, y1, x2, y2, color, thickness) { x1 = Math.round(x1); y1 = Math.round(y1); x2 = Math.round(x2); y2 = Math.round(y2); if (!socket || !canvas) 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); // Usa grosor NEGATIVO para Drawaria (modo pincel/spray) const cmd = `42["drawcmd",0,[${normX1},${normY1},${normX2},${normY2},false,${0 - thickness},"${color}",0,0,{}]]`; socket.send(cmd); } function sendAndDrawCommand(x1, y1, x2, y2, color, thickness) { drawLocalLine(x1, y1, x2, y2, color, thickness); sendRemoteDrawCommand(x1, y1, x2, y2, color, thickness); } /** * Dibuja pixel art detallado (simulando sprites de ítems). */ function drawPixelArt(x, y, asset, sizeMultiplier = 1) { const { art, colors } = asset; const basePixelSize = 6; const pixelSize = basePixelSize * sizeMultiplier; const height = art.length; const width = art[0].length; const startX = x - (width * pixelSize) / 2; const startY = y - (height * pixelSize) / 2; for (let row = 0; row < height; row++) { for (let col = 0; col < width; col++) { const char = art[row][col]; const color = colors[char] || SSB_COLORS[char]; if (color && char !== ' ') { const pX1 = startX + col * pixelSize; const pY1 = startY + row * pixelSize; const pX2 = pX1 + pixelSize; const pY2 = pY1 + pixelSize; // Relleno del pixel for (let i = 0; i < pixelSize; i += 2) { sendAndDrawCommand(pX1, pY1 + i, pX2, pY1 + i, color, 2); } // Borde negro (definición del pixel art) sendAndDrawCommand(pX1, pY1, pX2, pY1, SSB_COLORS.K, 1); } } } } /* ---------------------------------------------------------------------------------- // FUNCIONES DE ATAQUE (SPECIAL MOVES) SUPER SMASH BROS. // ---------------------------------------------------------------------------------- */ // 1. Ataque Smash (Efecto KO) async function smashFistKO(playerId, intensity = 3) { if (stopSignal) return; const target = getPlayerCoords(playerId); if (!target) return; const endX = target.x; const endY = target.y; const damageColor = SSB_COLORS.R; const impactDuration = 800; const startTime = Date.now(); const thickness = 10 + intensity * 5; // 1. Efecto de carga (rojo) for (let i = 0; i < 5; i++) { if (stopSignal) break; const r = 5 + i * 5; const x = endX + r; const y = endY + r; sendAndDrawCommand(endX, endY, x, y, damageColor, 3); await new Promise(r => setTimeout(r, 50)); } // 2. Impacto (Explosión y Estrellas de KO) while (Date.now() - startTime < impactDuration) { if (stopSignal) break; // Gran círculo rojo de impacto for (let i = 0; i < 15; i++) { const angle = Math.random() * Math.PI * 2; const r = 30 + Math.random() * 20; const x = endX + r * Math.cos(angle); const y = endY + r * Math.sin(angle); sendAndDrawCommand(endX, endY, x, y, damageColor, thickness); } // Dibuja Estrellas de KO drawPixelArt(endX + 50, endY - 50, SSB_PIXEL_ASSETS.KO_STARS, 1 + intensity * 0.2); await new Promise(r => setTimeout(r, 100)); } } // 2. Rayo (Stun) async function thunderJoltStun(playerId, intensity = 3) { if (stopSignal) return; const target = getPlayerCoords(playerId); if (!target) return; const endX = target.x; const endY = target.y; const lightningColor = SSB_COLORS.Y; // Amarillo/Eléctrico const duration = 1200; const startTime = Date.now(); // Rayo que golpea desde arriba while (Date.now() - startTime < duration) { if (stopSignal) break; const count = 10 + intensity * 5; // Líneas de rayo zigzagueantes let currentX = endX; let currentY = endY - 100; for (let i = 0; i < 10; i++) { const nextX = currentX + (Math.random() - 0.5) * 20; const nextY = currentY + 10; sendAndDrawCommand(currentX, currentY, nextX, nextY, lightningColor, 5); currentX = nextX; currentY = nextY; } // Efecto de parálisis (Brillo blanco) sendAndDrawCommand(endX, endY, endX, endY, SSB_COLORS.W, 20); await new Promise(r => setTimeout(r, 50)); } } // 3. Bola de Fuego (Flinch/Empuje) async function fireballFlinch(playerId, intensity = 3) { if (stopSignal) return; const target = getPlayerCoords(playerId); if (!target) return; const endX = target.x; const endY = target.y; const fireColor = SSB_COLORS.R; const startX = endX - 100; // Trayectoria de la bola de fuego (Horizontal) for (let i = 0; i < 15; i++) { if (stopSignal) break; const progress = i / 14; const currentX = startX + (endX - startX) * progress; const thickness = 5 + intensity * 2; // Fuego (rojo y amarillo) for (let j = 0; j < 5; j++) { const offset = (Math.random() - 0.5) * 10; const color = (Math.random() > 0.5) ? fireColor : SSB_COLORS.Y; sendAndDrawCommand(currentX + offset, endY + offset, currentX + offset, endY + offset, color, thickness); } await new Promise(r => setTimeout(r, 40)); } // Impacto de empuje sendAndDrawCommand(endX, endY, endX + 50, endY, SSB_COLORS.R, 5); } // 4. Ataque de Hielo (Freeze) async function iceBlastFreeze(playerId, intensity = 3) { if (stopSignal) return; const target = getPlayerCoords(playerId); if (!target) return; const endX = target.x; const endY = target.y; const iceColor = SSB_COLORS.B; // Azul const duration = 1500; const startTime = Date.now(); // Efecto de congelación (partículas azules y líneas de hielo) while (Date.now() - startTime < duration) { if (stopSignal) break; const count = 8 + intensity * 3; const maxRadius = 50; // Partículas de hielo azules que rodean al objetivo for (let i = 0; i < count; i++) { const r = maxRadius * Math.random(); const angle = Math.random() * Math.PI * 2; const x = endX + r * Math.cos(angle); const y = endY + r * Math.sin(angle); const color = (Math.random() > 0.5) ? iceColor : SSB_COLORS.W; sendAndDrawCommand(x, y, x, y, 5); // Puntos de hielo } // Dibuja un "bloque" de hielo alrededor sendAndDrawCommand(endX - maxRadius, endY - maxRadius, endX + maxRadius, endY - maxRadius, iceColor, 3); sendAndDrawCommand(endX - maxRadius, endY - maxRadius, endX - maxRadius, endY + maxRadius, iceColor, 3); await new Promise(r => setTimeout(r, 100)); } } /* ---------------------------------------------------------------------------------- // FUNCIONES DE ÍTEMS Y BUFFS (ITEMS) SUPER SMASH BROS. // ---------------------------------------------------------------------------------- */ // 5. Cápsula de Curación async function capsuleHeal(playerId, intensity = 3) { if (stopSignal) return; const target = getPlayerCoords(playerId); if (!target) return; const duration = 1000; const startTime = Date.now(); const healColor = SSB_COLORS.P; // Rosa/Fucsia (Efecto de Hada/Curación) // Partículas rosas que descienden sobre el objetivo while (Date.now() - startTime < duration) { if (stopSignal) break; const count = 10 + intensity * 3; for (let i = 0; i < count; i++) { const x = target.x + (Math.random() - 0.5) * 40; const startY = target.y - 50; const endY = target.y + 20; const currentY = startY + (endY - startY) * (Math.random()); sendAndDrawCommand(x, currentY, x, currentY + 5, healColor, 4); } await new Promise(r => setTimeout(r, 80)); } } // 6. Martillo (Furia) async function hammerFury(playerId, intensity = 3) { if (stopSignal) return; const target = getPlayerCoords(playerId); if (!target) return; const duration = 2000; const startTime = Date.now(); const furyColor = SSB_COLORS.S; // Plata (Cabeza de martillo) // Martillo golpeando repetidamente sobre el objetivo while (Date.now() - startTime < duration) { if (stopSignal) break; const swingX = target.x + (Math.sin(Date.now() * 0.02) * 50); const swingY = target.y - 50; // Dibuja el Martillo drawPixelArt(swingX, swingY, SSB_PIXEL_ASSETS.HAMMER_HEAD, 1.5); // Efecto de onda de choque al golpear sendAndDrawCommand(target.x - 30, target.y, target.x + 30, target.y, furyColor, 10); await new Promise(r => setTimeout(r, 150 - intensity * 15)); } } // 7. Estrella de Invencibilidad async function starInvincibility(playerId, intensity = 3) { if (stopSignal) return; const target = getPlayerCoords(playerId); if (!target) return; const duration = 3000; const startTime = Date.now(); const starColors = [SSB_COLORS.R, SSB_COLORS.Y, SSB_COLORS.B]; // Ráfaga de colores brillantes alrededor del objetivo while (Date.now() - startTime < duration) { if (stopSignal) break; const count = 15 + intensity * 5; const maxRadius = 60; for (let i = 0; i < count; i++) { const r = maxRadius * Math.random(); const angle = Math.random() * Math.PI * 2; const x = target.x + r * Math.cos(angle); const y = target.y + r * Math.sin(angle); const color = starColors[Math.floor(Math.random() * 3)]; sendAndDrawCommand(target.x, target.y, x, y, color, 3); } await new Promise(r => setTimeout(r, 80)); } } // 8. Pokebola (Lanzamiento) async function pokeballLaunch(playerId, intensity = 3) { if (stopSignal) return; const target = getPlayerCoords(playerId); if (!target) return; const endX = target.x; const endY = target.y; const startX = canvas.width * 0.2; const startY = canvas.height * 0.8; // Trayectoria parabólica de la Pokebola for (let i = 0; i < 20; i++) { if (stopSignal) break; const progress = i / 19; const currentX = startX + (endX - startX) * progress; // Simulación de parábola (curva en Y) const parabolaFactor = Math.sin(progress * Math.PI); const currentY = startY + (endY - startY) * progress - 100 * parabolaFactor; // Dibuja la Pokebola drawPixelArt(currentX, currentY, SSB_PIXEL_ASSETS.POKEBALL, 1.2); await new Promise(r => setTimeout(r, 40)); } // Efecto de salida del Pokémon (gran destello de luz) sendAndDrawCommand(endX, endY, endX, endY, SSB_COLORS.W, 50); } /* ---------------------------------------------------------------------------------- // INTERFAZ DE USUARIO Y GESTIÓN DE EVENTOS // ---------------------------------------------------------------------------------- */ const ssbContainer = document.createElement('div'); ssbContainer.id = 'SmashCompanionUI'; ssbContainer.style.cssText = ` position:fixed; bottom:10px; right:10px; z-index:9999; background:rgba(0, 0, 0, 0.95); /* Negro (Fondo de Pantalla de VS) */ color:#FFFFFF; padding:15px 20px; border-radius:10px; font-family: 'Arial Black', 'Impact', sans-serif; font-size:12px; display:flex; flex-direction:column; gap:10px; box-shadow: 0 5px 20px rgba(0,0,0,0.9), 0 0 15px rgba(255, 0, 0, 0.6); border: 3px solid #FF0000; /* Rojo Daño */ min-width: 250px; backdrop-filter: blur(5px); `; const titleBar = document.createElement('div'); titleBar.innerHTML = '🎮 SMASH COMPANION MOD 💥'; titleBar.style.cssText = ` font-weight: bold; font-size: 14px; text-align: center; cursor: grab; color: #FFFF00; /* Amarillo Impacto */ background: rgba(169, 169, 169, 0.7); /* Gris Plata */ text-shadow: 0 0 5px #FF0000; margin: -15px -20px 8px -20px; padding: 10px 20px; border-bottom: 2px solid #FFFF00; border-radius: 7px 7px 0 0; `; ssbContainer.appendChild(titleBar); const contentDiv = document.createElement('div'); contentDiv.style.cssText = `display:flex; flex-direction:column; gap:8px;`; ssbContainer.appendChild(contentDiv); const ssbInputStyle = ` flex-grow: 1; padding: 6px 10px; border-radius: 5px; border: 2px solid #FF0000; background: rgba(0, 0, 0, 0.7); color: #FFFFFF; font-size: 11px; font-family: monospace; transition: all 0.2s ease; `; function createSsbRow(parent, labelText, inputElement) { const wrapper = document.createElement('div'); wrapper.style.cssText = `display:flex; align-items:center; gap:8px;`; const label = document.createElement('span'); label.textContent = labelText; label.style.cssText = `color: #FFFFFF; font-weight: bold; min-width: 80px;`; wrapper.appendChild(label); wrapper.appendChild(inputElement); parent.appendChild(wrapper); return wrapper; } // Selector de Oponente (Target) const enemySelect = document.createElement('select'); enemySelect.style.cssText = ssbInputStyle; createSsbRow(contentDiv, '👤 Oponente:', enemySelect); // Selector de Ataques const attackSelect = document.createElement('select'); attackSelect.style.cssText = ssbInputStyle; for (const name in SSB_ATTACKS) { const opt = document.createElement('option'); opt.value = SSB_ATTACKS[name]; opt.textContent = name; attackSelect.appendChild(opt); } attackSelect.value = SSB_ATTACKS['Ninguno']; createSsbRow(contentDiv, '⚔️ SPECIAL:', attackSelect); // Selector de Ítems const itemSelect = document.createElement('select'); itemSelect.style.cssText = ssbInputStyle; for (const name in SSB_ITEMS) { const opt = document.createElement('option'); opt.value = SSB_ITEMS[name]; opt.textContent = name; itemSelect.appendChild(opt); } itemSelect.value = SSB_ITEMS['Ninguno']; createSsbRow(contentDiv, '📦 ÍTEM:', itemSelect); // Auto-reset de selectores (solo uno a la vez) attackSelect.addEventListener('change', () => { if (attackSelect.value !== '') itemSelect.value = SSB_ITEMS['Ninguno']; }); itemSelect.addEventListener('change', () => { if (itemSelect.value !== '') attackSelect.value = SSB_ATTACKS['Ninguno']; }); // Medidor de Daño/Intensidad const powerInput = document.createElement('input'); powerInput.type = 'range'; powerInput.min = '1'; powerInput.max = '5'; powerInput.value = '3'; powerInput.style.cssText = `flex-grow: 1; accent-color: ${SSB_COLORS.R};`; createSsbRow(contentDiv, '🩸 Daño %:', powerInput); const powerLabel = document.createElement('span'); powerLabel.style.cssText = `color: ${SSB_COLORS.Y}; font-size: 10px; text-align: center; margin-top: -5px;`; powerLabel.textContent = `Daño Simul.: ${DAMAGE_PERCENT_LABELS[powerInput.value - 1]}`; contentDiv.appendChild(powerLabel); powerInput.addEventListener('input', () => { powerLabel.textContent = `Daño Simul.: ${DAMAGE_PERCENT_LABELS[powerInput.value - 1]}`; }); // Toggle de Repetición ("Lucha Continua") const repeatToggle = document.createElement('input'); repeatToggle.type = 'checkbox'; repeatToggle.style.cssText = `transform: scale(1.2); accent-color: ${SSB_COLORS.R};`; const repeatLabel = document.createElement('label'); repeatLabel.textContent = ' 🔄 Lucha Continua (Spam)'; repeatLabel.style.cssText = `color: ${SSB_COLORS.R}; font-weight: bold; cursor: pointer;`; const repeatWrapper = document.createElement('div'); repeatWrapper.style.cssText = `display:flex; align-items:center; gap:8px; justify-content: center;`; repeatWrapper.appendChild(repeatToggle); repeatWrapper.appendChild(repeatLabel); contentDiv.appendChild(repeatWrapper); // Botón de Activación const activateBtn = document.createElement('button'); activateBtn.textContent = '💥 SMASH ATTACK / USAR ÍTEM 📦'; activateBtn.disabled = true; activateBtn.style.cssText = ` padding: 10px 15px; border-radius: 8px; border: none; background: linear-gradient(45deg, ${SSB_COLORS.R}, ${SSB_COLORS.K}); color: ${SSB_COLORS.Y}; font-weight: bold; font-size: 14px; cursor: pointer; transition: all 0.2s ease; box-shadow: 0 3px 10px rgba(255, 0, 0, 0.5); font-family: 'Impact', sans-serif; &:hover { background: linear-gradient(45deg, ${SSB_COLORS.K}, ${SSB_COLORS.R}); transform: translateY(-1px); } &:disabled { background: #666; cursor: not-allowed; opacity: 0.5; transform: none; } `; contentDiv.appendChild(activateBtn); // Botón de Parada stopBtn = document.createElement('button'); stopBtn.textContent = '⛔ TERMINAR PARTIDA (Stop)'; stopBtn.disabled = true; stopBtn.style.cssText = ` margin-top: 5px; padding: 8px 12px; border-radius: 6px; border: none; background: linear-gradient(45deg, ${SSB_COLORS.B}, ${SSB_COLORS.K}); color: white; font-weight: bold; font-size: 12px; cursor: pointer; transition: all 0.2s ease; box-shadow: 0 2px 8px rgba(0, 0, 255, 0.5); font-family: 'Impact', sans-serif; &:hover { background: linear-gradient(45deg, ${SSB_COLORS.K}, ${SSB_COLORS.B}); transform: translateY(-1px); } &:disabled { background: #666; cursor: not-allowed; opacity: 0.5; transform: none; } `; contentDiv.appendChild(stopBtn); document.body.appendChild(ssbContainer); // --- Lógica de Gestión de Jugadores --- let lastPlayerList = new Set(); let isUpdatingList = false; function refreshPlayerList() { if (isUpdatingList) return; const currentPlayers = new Set(); const playerRows = document.querySelectorAll('.playerlist-row[data-playerid]'); playerRows.forEach(row => { if (row.dataset.self !== 'true' && row.dataset.playerid !== '0') { const name = row.querySelector('.playerlist-name a')?.textContent || `Player ${row.dataset.playerid}`; currentPlayers.add(`${row.dataset.playerid}:${name}`); } }); const playersChanged = currentPlayers.size !== lastPlayerList.size || ![...currentPlayers].every(player => lastPlayerList.has(player)); if (!playersChanged) return; isUpdatingList = true; const previousSelection = enemySelect.value; enemySelect.innerHTML = ''; enemySelect.textContent = '🔴 Tú (Jugador 1)'; playerRows.forEach(row => { if (row.dataset.self === 'true') return; if (row.dataset.playerid === '0') return; const name = row.querySelector('.playerlist-name a')?.textContent || `Enemy ${row.dataset.playerid}`; const opt = document.createElement('option'); opt.value = row.dataset.playerid; // Asigna un personaje genérico const ssbName = name.includes('Police') ? '🎯 Captain Falcon' : '🎯 Bowser'; opt.textContent = `${ssbName} (${name})`; enemySelect.appendChild(opt); }); if (previousSelection) { enemySelect.value = previousSelection; } lastPlayerList = new Set(currentPlayers); activateBtn.disabled = enemySelect.children.length === 0; isUpdatingList = false; } // --- Eventos Principales --- // Arrastrar ventana let isDragging = false; let dragOffsetX, dragOffsetY; titleBar.addEventListener('mousedown', (e) => { isDragging = true; dragOffsetX = e.clientX - ssbContainer.getBoundingClientRect().left; dragOffsetY = e.clientY - ssbContainer.getBoundingClientRect().top; titleBar.style.cursor = 'grabbing'; }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; let newX = e.clientX - dragOffsetX; let newY = e.clientY - dragOffsetY; newX = Math.max(0, Math.min(newX, window.innerWidth - ssbContainer.offsetWidth)); newY = Math.max(0, Math.min(newY, window.innerHeight - ssbContainer.offsetHeight)); ssbContainer.style.left = newX + 'px'; ssbContainer.style.top = newY + 'px'; ssbContainer.style.right = 'auto'; ssbContainer.style.bottom = 'auto'; }); document.addEventListener('mouseup', () => { isDragging = false; titleBar.style.cursor = 'grab'; }); // Botón de parada stopBtn.addEventListener('click', () => { console.log('⛔ Partida terminada. ¡Buen juego!'); stopSignal = true; if (activePowerInterval) { clearInterval(activePowerInterval); activePowerInterval = null; } activateBtn.textContent = '💥 SMASH ATTACK / USAR ÍTEM 📦'; activateBtn.style.background = `linear-gradient(45deg, ${SSB_COLORS.R}, ${SSB_COLORS.K})`; activateBtn.disabled = false; stopBtn.disabled = true; }); // Botón principal de activación activateBtn.addEventListener('click', async () => { const playerId = enemySelect.value; if (!playerId) { alert('🎯 ¡Escoge un Oponente!'); return; } const selectedAttack = attackSelect.value; const selectedItem = itemSelect.value; const intensity = parseInt(powerInput.value); if (activePowerInterval) { stopBtn.click(); return; } let actionToExecute = null; let actionName = ''; if (selectedAttack && selectedAttack.startsWith('attack:')) { // Ataque Especial switch (selectedAttack) { case 'attack:smash_fist_ko': actionToExecute = () => smashFistKO(playerId, intensity); actionName = 'Ataque Smash KO'; break; case 'attack:thunder_jolt_stun': actionToExecute = () => thunderJoltStun(playerId, intensity); actionName = 'Rayo Stun'; break; case 'attack:fireball_flinch': actionToExecute = () => fireballFlinch(playerId, intensity); actionName = 'Bola de Fuego'; break; case 'attack:ice_blast_freeze': actionToExecute = () => iceBlastFreeze(playerId, intensity); actionName = 'Ataque de Hielo'; break; default: return; } } else if (selectedItem && selectedItem.startsWith('item:')) { // Uso de Ítem switch (selectedItem) { case 'item:capsule_heal': actionToExecute = () => capsuleHeal(playerId, intensity); actionName = 'Cápsula de Curación'; break; case 'item:hammer_fury': actionToExecute = () => hammerFury(playerId, intensity); actionName = 'Martillo'; break; case 'item:star_invincibility': actionToExecute = () => starInvincibility(playerId, intensity); actionName = 'Estrella de Invencibilidad'; break; case 'item:pokeball_launch': actionToExecute = () => pokeballLaunch(playerId, intensity); actionName = 'Pokebola'; break; default: return; } } else { alert('🔺 ¡Debes seleccionar un Ataque o un Ítem!'); return; } stopSignal = false; activateBtn.disabled = true; stopBtn.disabled = false; try { if (repeatToggle.checked) { activateBtn.textContent = '🔄 DETENER LUCHA CONTINUA'; activateBtn.style.background = `linear-gradient(45deg, ${SSB_COLORS.B}, ${SSB_COLORS.K})`; activateBtn.disabled = false; console.log(`🔥 ¡Iniciando Lucha Continua con ${actionName}! ¡No hay piedad!`); const continuousAction = async () => { if (stopSignal || !repeatToggle.checked) { if (activePowerInterval) clearInterval(activePowerInterval); activePowerInterval = null; activateBtn.textContent = '💥 SMASH ATTACK / USAR ÍTEM 📦'; activateBtn.style.background = `linear-gradient(45deg, ${SSB_COLORS.R}, ${SSB_COLORS.K})`; stopBtn.disabled = true; return; } try { await actionToExecute(); } catch (error) { console.error(`Error durante la Lucha Continua (${actionName}):`, error); } }; await continuousAction(); if (!stopSignal) { activePowerInterval = setInterval(continuousAction, 1500); // Rápido para simular spam } } else { console.log(`💥 Ejecutando ${actionName} una sola vez...`); await actionToExecute(); } } finally { if (!activePowerInterval) { activateBtn.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 (activePowerInterval) { clearInterval(activePowerInterval); activePowerInterval = null; } stopSignal = true; console.log('¡GRACIAS POR JUGAR! ¡GAME SET! -Super Smash Bros.'); }); // Inicialización refreshPlayerList(); console.log('✨ Smash Companion Mod cargado. ¡A luchar! ✨'); })();