Super Drawaria Smash - Rest Area

Rest Area de Super Drawaria Smash, asegurando la carga en toda la pantalla.

// ==UserScript==
// @name         Super Drawaria Smash - Rest Area
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Rest Area de Super Drawaria Smash, asegurando la carga en toda la pantalla.
// @author       YouTubeDrawaria
// @match	     https://drawaria.online/*
// @include	     https://drawaria.online
// @include      https://*.drawaria.online/*
// @icon         https://m.media-amazon.com/images/I/51P8Uyw+6UL._UF894,1000_QL80_.jpg
// @grant        none
// @license      MIT
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // ----------------------------------------------------
    // PASO 1: Inyección de CSS (Fundamental para la superposición)
    // ----------------------------------------------------
    function injectCSS() {
        const style = document.createElement('style');
        style.textContent = `
            /* Los estilos originales */
            body { margin: 0; overflow: hidden !important; background-color: #000000 !important; }
            #game-canvas {
                display: block;
                position: fixed;
                top: 0;
                left: 0;
                /* Z-INDEX EXTREMADAMENTE ALTO: Asegura que el canvas cubra cualquier contenido */
                z-index: 2147483647;
            }
            audio { display: none; }
        `;
        document.head.appendChild(style);

        // Inyectar el favicon
        const link = document.createElement('link');
        link.rel = 'icon';
        link.href = 'https://m.media-amazon.com/images/I/51P8Uyw+6UL._UF894,1000_QL80_.jpg';
        link.type = 'image/x-icon';
        document.head.appendChild(link);
    }

    // ----------------------------------------------------
    // PASO 2: Inyección de HTML (Canvas y Audios)
    // ----------------------------------------------------
    function injectHTML() {
        // Crear Canvas
        const canvas = document.createElement('canvas');
        canvas.id = 'game-canvas';
        document.body.appendChild(canvas);

        // Definiciones de Audio (Extraídas del HTML original)
        const audioData = [
            { id: 'menu-music', src: '', loop: true },
            { id: 'select-music', src: 'https://www.myinstants.com/media/sounds/drawaria-legends-select.mp3', loop: true },
            { id: 'mario-music', src: 'https://www.myinstants.com/media/sounds/super-mario-bros_8nlGIsH.mp3', loop: true },
            { id: 'kirby-music', src: 'https://www.myinstants.com/media/sounds/scaralie-intro.mp3', loop: true },
            { id: 'metroid-music', src: 'https://www.myinstants.com/media/sounds/noods-boss-2.mp3', loop: true },
            { id: 'zelda-music', src: 'https://www.myinstants.com/media/sounds/noods-boss-5.mp3', loop: true },
            { id: 'sonic-music', src: 'https://www.myinstants.com/media/sounds/noods-boss-8.mp3', loop: true },
            { id: 'pokemon-music', src: 'https://www.myinstants.com/media/sounds/noods-boss-3.mp3', loop: true },
            { id: 'drawaria-music', src: 'https://www.myinstants.com/media/sounds/scaralie.mp3', loop: true },
            { id: 'hit-sfx', src: 'https://www.myinstants.com/media/sounds/selection.mp3' },
            { id: 'ko-sfx', src: 'https://www.myinstants.com/media/sounds/wilhelm.mp3' },
            { id: 'bg-music', src: 'https://www.myinstants.com/media/sounds/rest-area-melee.mp3', loop: true }
        ];

        audioData.forEach(data => {
            const audio = document.createElement('audio');
            audio.id = data.id;
            audio.src = data.src;
            if (data.loop) audio.loop = true;
            document.body.appendChild(audio);
        });
    }

    // ----------------------------------------------------
    // PASO 3: Inyección del Código JavaScript del Juego
    // ----------------------------------------------------
    function injectGameScript() {
        /*
         * Se usa una función autoejecutable (IIFE) para aislar el código,
         * pero se ejecuta en el ámbito de la ventana (window) para que el canvas y los audios
         * sean accesibles por ID.
         */
        const scriptContent = `
            // =====================================================================
            // CONFIGURACIÓN GLOBAL Y CONSTANTES DE FÍSICA
            // (TODO EL CÓDIGO JS EXTRAÍDO DEL FICHERO ORIGINAL)
            // =====================================================================
            const CONFIG = {
                WIDTH: 0,
                HEIGHT: 0,
                TIME: 0,
                SCALE: 1.0,
                STATE: 'REST_AREA', // <--- INICIAMOS DIRECTAMENTE EN EL REST AREA
                GRAVITY: 9.8,
                MAX_FALL_SPEED: 25,
                FIGHTER_SPEED: 8,
                JUMP_VELOCITY: 15,
                KNOCKBACK_FACTOR: 0.15,
                MAX_STOCK: 3,
                STAGE_FADE_DURATION: 3,
                NPC_MODE: 'RANDOM',
                SELECTED_FIGHTERS: [null, null],
                FIGHTER_LIST: [],
                STAGE_ID: 'MARIO_STAGE',
                FADE_TIMER: 0,

                // --- PROPIEDADES PARA REST AREA ---
                ACTIVE_FIGHTER_DATA: null,
                REST_AREA_TIMER: 21.38, // 00:21 38 como en la imagen
                // ----------------------------------
            };

            // =====================================================================
            // CLASES DE PERSONAJES (ADAPTADAS Y MAXIMIZADAS)
            // =====================================================================

            // --- Extracción y adaptación de Personaje de Mario Articulado 2D.txt ---
            class MarioArticulado {
                constructor(ctx) {
                    this.ctx = ctx;
                    this.pose = {
                        torsoAngle: 0, armL: { x: -40, y: -80, angle: 0 }, forearmL: { x: 0, y: 30, angle: -0.2 }, handL: { x: 0, y: 25, angle: 0 },
                        armR: { x: 40, y: -80, angle: 0.1 }, forearmR: { x: 0, y: 30, angle: 0.3 }, handR: { x: 0, y: 25, angle: 0 },
                        thighL: { x: -20, y: 5, angle: 0.1 }, shinL: { x: 0, y: 40, angle: -0.1 }, footL: { x: 0, y: 40, angle: 0 },
                        thighR: { x: 20, y: 5, angle: -0.1 }, shinR: { x: 0, y: 40, angle: 0.1 }, footR: { x: 0, y: 40, angle: 0 },
                    };
                }
                _adjustColor(hex, lum) { hex = hex.replace(/[^0-9a-f]/gi, ''); if (hex.length < 6) { hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; } let rgb = "#", c, i; for (i = 0; i < 3; i++) { c = parseInt(hex.substr(i * 2, 2), 16); c = Math.round(Math.min(255, Math.max(0, c + lum))).toString(16); while (c.length < 2) c = "0" + c; rgb += c; } return rgb; }
                _drawShadedRect(colorBase, x, y, w, h, radius = 0) { const ctx = this.ctx; const bodyGrad = ctx.createLinearGradient(x - w / 2, y, x + w / 2, y); bodyGrad.addColorStop(0.0, this._adjustColor(colorBase, -40)); bodyGrad.addColorStop(0.4, colorBase); bodyGrad.addColorStop(0.6, colorBase); bodyGrad.addColorStop(1.0, this._adjustColor(colorBase, 20)); ctx.fillStyle = bodyGrad; if (radius > 0) { ctx.beginPath(); ctx.moveTo(x - w / 2 + radius, y - h / 2); ctx.lineTo(x + w / 2 - radius, y - h / 2); ctx.quadraticCurveTo(x + w / 2, y - h / 2, x + w / 2, y - h / 2 + radius); ctx.lineTo(x + w / 2, y + h / 2 - radius); ctx.quadraticCurveTo(x + w / 2, y + h / 2, x + w / 2 - radius, y + h / 2); ctx.lineTo(x - w / 2 + radius, y + h / 2); ctx.quadraticCurveTo(x - w / 2, y + h / 2, x - w / 2, y + h / 2 - radius); ctx.lineTo(x - w / 2, y - h / 2 + radius); ctx.quadraticCurveTo(x - w / 2, y - h / 2, x - w / 2 + radius, y - h / 2); ctx.closePath(); ctx.fill(); } else { ctx.fillRect(x - w / 2, y - h / 2, w, h); } }
                _drawHead(ctx) { const faceColor = '#FFDBA5'; const hatRed = '#FF0000'; ctx.save(); ctx.fillStyle = faceColor; ctx.beginPath(); ctx.arc(-22, 0, 8, 0, Math.PI * 2); ctx.arc(22, 0, 8, 0, Math.PI * 2); ctx.fill(); this._drawShadedRect(faceColor, 0, 0, 40, 50, 25); ctx.fillStyle = 'white'; ctx.beginPath(); ctx.ellipse(-10, -5, 8, 10, 0, 0, Math.PI * 2); ctx.ellipse(10, -5, 8, 10, 0, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = '#1E90FF'; ctx.beginPath(); ctx.arc(-10, -5, 4, 0, Math.PI * 2); ctx.arc(10, -5, 4, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = 'black'; ctx.beginPath(); ctx.arc(-10, -5, 2, 0, Math.PI * 2); ctx.arc(10, -5, 2, 0, Math.PI * 2); ctx.fill(); this._drawShadedRect(faceColor, 0, 5, 12, 10, 5); ctx.fillStyle = '#654321'; ctx.beginPath(); ctx.moveTo(-25, 15); ctx.bezierCurveTo(-15, 25, 15, 25, 25, 15); ctx.lineTo(25, 20); ctx.bezierCurveTo(15, 30, -15, 30, -25, 20); ctx.closePath(); ctx.fill(); ctx.fillStyle = '#654321'; ctx.beginPath(); ctx.arc(-15, -15, 10, 0, Math.PI * 2); ctx.arc(15, -15, 10, 0, Math.PI * 2); ctx.fill(); this._drawShadedRect(hatRed, 0, -35, 60, 30, 15); ctx.fillStyle = this._adjustColor(hatRed, -10); ctx.beginPath(); ctx.ellipse(5, -25, 40, 20, 0, 0, Math.PI, true); ctx.fill(); ctx.fillStyle = 'white'; ctx.beginPath(); ctx.arc(0, -35, 15, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = hatRed; ctx.font = 'bold 25px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText('M', 0, -35); ctx.restore(); }
                _drawTorso(ctx) { const shirtRed = '#FF0000'; const overallsBlue = '#1E90FF'; ctx.save(); this._drawShadedRect(shirtRed, 0, -40, 80, 50, 10); this._drawShadedRect(overallsBlue, 0, 0, 90, 80, 15); ctx.lineWidth = 10; ctx.strokeStyle = this._adjustColor(overallsBlue, -20); ctx.beginPath(); ctx.moveTo(-35, -20); ctx.lineTo(-20, -60); ctx.moveTo(35, -20); ctx.lineTo(20, -60); ctx.stroke(); ctx.fillStyle = '#FFD700'; ctx.beginPath(); ctx.arc(-20, -15, 8, 0, Math.PI * 2); ctx.arc(20, -15, 8, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = 'rgba(0, 0, 0, 0.2)'; ctx.beginPath(); ctx.ellipse(0, 0, 30, 15, 0, 0, Math.PI, false); ctx.fill(); ctx.restore(); }
                _drawLimb(ctx, isArm, w, h, angle) { const color = isArm ? '#FF0000' : '#1E90FF'; ctx.save(); ctx.rotate(angle); this._drawShadedRect(color, 0, h / 2, w, h, w / 4); ctx.restore(); }
                _drawHand(ctx) { const gloveWhite = '#FFFFFF'; ctx.save(); this._drawShadedRect(gloveWhite, 0, 0, 30, 25, 10); ctx.fillStyle = this._adjustColor(gloveWhite, -30); ctx.beginPath(); ctx.arc(10, -5, 5, 0, Math.PI * 2); ctx.fill(); ctx.restore(); }
                _drawFoot(ctx) { const shoeBrown = '#8B4513'; ctx.save(); this._drawShadedRect(shoeBrown, 0, 0, 20, 40, 10); ctx.fillStyle = '#654321'; ctx.fillRect(-15, 15, 30, 10); ctx.fillStyle = shoeBrown; ctx.beginPath(); ctx.ellipse(0, 0, 15, 20, 0, 0, Math.PI * 2); ctx.fill(); ctx.restore(); }
                _drawLimbSet(joint1, joint2, joint3, isFront, isArm) { const ctx = this.ctx; const limbW = isArm ? 20 : 35; const limbH1 = isArm ? 30 : 40; const limbH2 = isArm ? 25 : 40; ctx.save(); ctx.translate(joint1.x, joint1.y); this._drawLimb(ctx, isArm, limbW, limbH1, joint1.angle); ctx.translate(Math.sin(joint1.angle) * limbH1, Math.cos(joint1.angle) * limbH1); this._drawLimb(ctx, isArm, limbW * 0.9, limbH2, joint2.angle); ctx.translate(Math.sin(joint2.angle) * limbH2, Math.cos(joint2.angle) * limbH2); if (isArm) { this._drawHand(ctx); } else { this._drawFoot(ctx); } ctx.restore(); }
                draw(ctx) { ctx.save(); ctx.rotate(this.pose.torsoAngle); this._drawLimbSet(this.pose.thighL, this.pose.shinL, this.pose.footL, true, false); this._drawLimbSet(this.pose.thighR, this.pose.shinR, this.pose.footR, false, false); this._drawLimbSet(this.pose.armL, this.pose.forearmL, this.pose.handL, false, true); ctx.save(); this._drawTorso(ctx); ctx.translate(0, -100); this._drawHead(ctx); ctx.restore(); this._drawLimbSet(this.pose.armR, this.pose.forearmR, this.pose.handR, true, true); ctx.restore(); }
            }

            // --- Extracción y adaptación de personaje-de-kirby-articulado-2d.txt ---
            class KirbyArticulado {
                constructor(ctx) { this.ctx = ctx; this.pose = { bodyAngle: 0, armL: { x: -60, y: -20, angle: 0.2 }, armR: { x: 60, y: -20, angle: -0.2 }, footL: { x: -25, y: 70, angle: 0.1 }, footR: { x: 25, y: 70, angle: -0.1 }, }; }
                _adjustColor(hex, lum) { hex = hex.replace(/[^0-9a-f]/gi, ''); if (hex.length < 6) { hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; } let rgb = "#", c, i; for (i = 0; i < 3; i++) { c = parseInt(hex.substr(i * 2, 2), 16); c = Math.round(Math.min(255, Math.max(0, c + lum))).toString(16); while (c.length < 2) c = "0" + c; rgb += c; } return rgb; }
                _drawShadedSphere(colorBase, rx, ry) { const ctx = this.ctx; const grad = ctx.createRadialGradient(-rx * 0.3, -ry * 0.3, rx * 0.1, 0, 0, Math.max(rx, ry)); grad.addColorStop(0.0, this._adjustColor(colorBase, 40)); grad.addColorStop(0.5, colorBase); grad.addColorStop(1.0, this._adjustColor(colorBase, -40)); ctx.fillStyle = grad; ctx.beginPath(); ctx.ellipse(0, 0, rx, ry, 0, 0, Math.PI * 2); ctx.fill(); }
                _drawBody(ctx) { const pink = '#FFC0CB'; const blushPink = '#FFB6C1'; ctx.save(); ctx.rotate(this.pose.bodyAngle); this._drawShadedSphere(pink, 80, 80, true); ctx.fillStyle = blushPink; ctx.beginPath(); ctx.ellipse(-35, 10, 15, 10, -0.2, 0, Math.PI * 2); ctx.ellipse(35, 10, 15, 10, 0.2, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = 'white'; ctx.beginPath(); ctx.ellipse(-20, -20, 12, 20, 0, 0, Math.PI * 2); ctx.ellipse(20, -20, 12, 20, 0, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = '#00008B'; ctx.beginPath(); ctx.ellipse(-20, -15, 8, 12, 0, 0, Math.PI * 2); ctx.ellipse(20, -15, 8, 12, 0, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = 'black'; ctx.beginPath(); ctx.arc(-20, -10, 4, 0, Math.PI * 2); ctx.arc(20, -10, 4, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = 'white'; ctx.beginPath(); ctx.arc(-25, -25, 3, 0, Math.PI * 2); ctx.arc(15, -25, 3, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = '#654321'; ctx.beginPath(); ctx.ellipse(0, 25, 8, 5, 0, 0, Math.PI * 2); ctx.fill(); ctx.restore(); }
                _drawArm(ctx, angle) { const pink = '#FFC0CB'; const armRX = 30; const armRY = 20; ctx.save(); ctx.rotate(angle); this._drawShadedSphere(pink, armRX, armRY); ctx.restore(); }
                _drawFoot(ctx, angle) { const red = '#FF0000'; const footRX = 40; const footRY = 30; ctx.save(); ctx.rotate(angle); this._drawShadedSphere(red, footRX, footRY); ctx.restore(); }
                draw(ctx) { this._drawBody(ctx); ctx.save(); ctx.translate(this.pose.armL.x, this.pose.armL.y); this._drawArm(ctx, this.pose.armL.angle); ctx.restore(); ctx.save(); ctx.translate(this.pose.armR.x, this.pose.armR.y); this._drawArm(ctx, this.pose.armR.angle); ctx.restore(); ctx.save(); ctx.translate(this.pose.footL.x, this.pose.footL.y); this._drawFoot(ctx, this.pose.footL.angle); ctx.restore(); ctx.save(); ctx.translate(this.pose.footR.x, this.pose.footR.y); this._drawFoot(ctx, this.pose.footR.angle); ctx.restore(); }
            }

            // --- Extracción y adaptación de pikachu-articulated-2d-character-detalle-mximo-html-canvas.html ---
            class PikachuArticulado {
                constructor(ctx) { this.ctx = ctx; this.pose = { torsoAngle: 0, headAngle: 0, armL: { x: -35, y: -20, angle: 0.1 }, armR: { x: 35, y: -20, angle: -0.1 }, thighL: { x: -20, y: 80, angle: 0.1 }, thighR: { x: 20, y: 80, angle: -0.1 }, earL: { x: -25, y: -80, angle: -0.2 }, earR: { x: 25, y: -80, angle: 0.2 }, }; }
                _adjustColor(hex, lum) { hex = hex.replace(/[^0-9a-f]/gi, ''); if (hex.length < 6) { hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; } let rgb = "#", c, i; for (i = 0; i < 3; i++) { c = parseInt(hex.substr(i * 2, 2), 16); c = Math.round(Math.min(255, Math.max(0, c + lum))).toString(16); while (c.length < 2) c = "0" + c; rgb += c; } return rgb; }
                _drawShadedShape(colorBase, w, h, radius, lightDirection = 'vertical') { const ctx = this.ctx; let grad; if (lightDirection === 'vertical') { grad = ctx.createLinearGradient(0, -h / 2, 0, h / 2); grad.addColorStop(0.0, this._adjustColor(colorBase, 20)); grad.addColorStop(0.5, colorBase); grad.addColorStop(1.0, this._adjustColor(colorBase, -30)); } else { grad = ctx.createLinearGradient(-w / 2, 0, w / 2, 0); grad.addColorStop(0.0, this._adjustColor(colorBase, -20)); grad.addColorStop(0.5, colorBase); grad.addColorStop(1.0, this._adjustColor(colorBase, 15)); } ctx.fillStyle = grad; ctx.beginPath(); ctx.moveTo(-w / 2 + radius, -h / 2); ctx.lineTo(w / 2 - radius, -h / 2); ctx.quadraticCurveTo(w / 2, -h / 2, w / 2, -h / 2 + radius); ctx.lineTo(w / 2, h / 2 - radius); ctx.quadraticCurveTo(w / 2, h / 2, w / 2 - radius, h / 2); ctx.lineTo(-w / 2 + radius, h / 2); ctx.quadraticCurveTo(-w / 2, h / 2, -w / 2, h / 2 - radius); ctx.lineTo(-w / 2, -h / 2 + radius); ctx.quadraticCurveTo(-w / 2, -h / 2, -w / 2 + radius, -h / 2); ctx.closePath(); ctx.fill(); }
                _drawBody(ctx) { const yellow = '#FFD700'; ctx.save(); const bodyW = 100; const bodyH = 150; this._drawShadedShape(yellow, bodyW, bodyH, 50, 'vertical'); ctx.save(); ctx.translate(0, bodyH / 2 - 20); ctx.rotate(Math.sin(CONFIG.TIME * 1.5) * 0.1); this._drawTail(ctx); ctx.restore(); ctx.restore(); }
                _drawHeadDetails(ctx) { const redCheeks = '#DC143C'; ctx.save(); ctx.rotate(this.pose.headAngle); ctx.translate(-35, 10); this._drawShadedShape(redCheeks, 30, 30, 15, 'vertical'); ctx.translate(70, 0); this._drawShadedShape(redCheeks, 30, 30, 15, 'vertical'); ctx.translate(-35, -10); ctx.fillStyle = '#654321'; ctx.beginPath(); ctx.arc(-15, -20, 10, 0, Math.PI * 2); ctx.arc(15, -20, 10, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = 'black'; ctx.beginPath(); ctx.arc(-15, -20, 4, 0, Math.PI * 2); ctx.arc(15, -20, 4, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = 'white'; ctx.beginPath(); ctx.arc(-18, -23, 2, 0, Math.PI * 2); ctx.arc(12, -23, 2, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = 'black'; ctx.beginPath(); ctx.arc(0, -5, 5, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = '#FF69B4'; ctx.beginPath(); ctx.arc(0, 5, 8, 0, Math.PI); ctx.fill(); ctx.restore(); }
                _drawEar(ctx, angle) { const yellow = '#FFD700'; const tipBlack = 'black'; const earW = 25; const earH = 80; ctx.save(); ctx.rotate(angle); ctx.translate(0, -earH / 2); this._drawShadedShape(yellow, earW, earH, 10, 'vertical'); ctx.fillStyle = tipBlack; ctx.beginPath(); ctx.moveTo(-earW / 2, -earH / 2); ctx.lineTo(earW / 2, -earH / 2); ctx.lineTo(0, -earH); ctx.closePath(); ctx.fill(); ctx.restore(); }
                _drawArm(ctx, angle) { const yellow = '#FFD700'; const armW = 25; const armH = 60; ctx.save(); ctx.rotate(angle); this._drawShadedShape(yellow, armW, armH, 10, 'horizontal'); ctx.translate(0, armH / 2); ctx.rotate(0.1); this._drawShadedShape(yellow, armW * 1.2, 15, 7); ctx.restore(); }
                _drawLeg(ctx, angle) { const yellow = '#FFD700'; const legW = 30; const legH = 40; ctx.save(); ctx.rotate(angle); ctx.translate(0, legH / 2); this._drawShadedShape(yellow, legW, legH, 15, 'horizontal'); ctx.translate(0, legH / 2); ctx.rotate(-0.1); this._drawShapedFoot(ctx, legW * 1.3, 10); ctx.restore(); }
                _drawShapedFoot(ctx, w, h) { const yellow = '#FFD700'; const toeBlack = '#654321'; ctx.save(); this._drawShadedShape(yellow, w, h, h / 2); ctx.fillStyle = toeBlack; ctx.beginPath(); ctx.arc(-w * 0.3, 0, 3, 0, Math.PI * 2); ctx.arc(0, 0, 3, 0, Math.PI * 2); ctx.arc(w * 0.3, 0, 3, 0, Math.PI * 2); ctx.fill(); ctx.restore(); }
                _drawTail(ctx) { const yellow = '#FFD700'; const brown = '#8B4513'; const segments = 4; const segmentSize = 25; ctx.save(); ctx.fillStyle = brown; ctx.fillRect(-15, 0, 30, 10); ctx.translate(0, 10); for(let i=0; i<segments; i++) { ctx.rotate(Math.sin(CONFIG.TIME * 5 + i * 2) * 0.05); this._drawShadedShape(yellow, segmentSize, segmentSize, 5); ctx.translate(segmentSize * 0.1, segmentSize); } ctx.fillStyle = yellow; ctx.beginPath(); ctx.moveTo(-segmentSize, 0); ctx.lineTo(segmentSize, 0); ctx.lineTo(segmentSize * 0.5, segmentSize * 0.5); ctx.lineTo(0, 0); ctx.lineTo(-segmentSize * 0.5, segmentSize * 0.5); ctx.closePath(); ctx.fill(); ctx.restore(); }
                draw(ctx) { ctx.save(); ctx.translate(this.pose.armL.x, this.pose.armL.y); this._drawArm(ctx, this.pose.armL.angle); ctx.restore(); ctx.save(); ctx.translate(this.pose.armR.x, this.pose.armR.y); this._drawArm(ctx, this.pose.armR.angle); ctx.restore(); ctx.save(); ctx.translate(this.pose.thighL.x, this.pose.thighL.y); this._drawLeg(ctx, this.pose.thighL.angle); ctx.restore(); ctx.save(); ctx.translate(this.pose.thighR.x, this.pose.thighR.y); this._drawLeg(ctx, this.pose.thighR.angle); ctx.restore(); this._drawBody(ctx); ctx.save(); ctx.translate(this.pose.earL.x, this.pose.earL.y); this._drawEar(ctx, this.pose.earL.angle); ctx.restore(); ctx.save(); ctx.translate(this.pose.earR.x, this.pose.earR.y); this._drawEar(ctx, this.pose.earR.angle); ctx.restore(); ctx.translate(0, -30); this._drawHeadDetails(ctx); }
            }

            // --- Extracción y adaptación de personaje-de-link-articulado-2d-detalle-mximo.html ---
            class LinkArticulado {
                constructor(ctx) { this.ctx = ctx; this.pose = { torsoAngle: 0, armL: { x: -30, y: -70, angle: 0.1 }, forearmL: { x: 0, y: 35, angle: 0.3 }, handL: { x: 0, y: 30, angle: 0 }, armR: { x: 30, y: -70, angle: -0.1 }, forearmR: { x: 0, y: 35, angle: -0.3 }, handR: { x: 0, y: 30, angle: 0 }, thighL: { x: -15, y: 15, angle: -0.05 }, shinL: { x: 0, y: 45, angle: 0.1 }, footL: { x: 0, y: 45, angle: 0 }, thighR: { x: 15, y: 15, angle: 0.05 }, shinR: { x: 0, y: 45, angle: -0.1 }, footR: { x: 0, y: 45, angle: 0 }, }; }
                _adjustColor(hex, lum) { hex = hex.replace(/[^0-9a-f]/gi, ''); if (hex.length < 6) { hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; } let rgb = "#", c, i; for (i = 0; i < 3; i++) { c = parseInt(hex.substr(i * 2, 2), 16); c = Math.round(Math.min(255, Math.max(0, c + lum))).toString(16); while (c.length < 2) c = "0" + c; rgb += c; } return rgb; }
                _drawShadedRect(colorBase, x, y, w, h, radius = 0, isVertical = false) { const ctx = this.ctx; let grad; if (isVertical) { grad = ctx.createLinearGradient(x - w / 2, y, x + w / 2, y); grad.addColorStop(0.0, this._adjustColor(colorBase, -40)); grad.addColorStop(0.5, colorBase); grad.addColorStop(1.0, this._adjustColor(colorBase, 20)); } else { grad = ctx.createLinearGradient(x, y - h / 2, x, y + h / 2); grad.addColorStop(0.0, this._adjustColor(colorBase, 20)); grad.addColorStop(0.5, colorBase); grad.addColorStop(1.0, this._adjustColor(colorBase, -40)); } ctx.fillStyle = grad; ctx.beginPath(); if (radius > 0) { const x0 = x - w / 2; const y0 = y - h / 2; ctx.moveTo(x0 + radius, y0); ctx.arcTo(x0 + w, y0, x0 + w, y0 + h, radius); ctx.arcTo(x0 + w, y0 + h, x0, y0 + h, radius); ctx.arcTo(x0, y0 + h, x0, y0, radius); ctx.arcTo(x0, y0, x0 + w, y0, radius); ctx.closePath(); ctx.fill(); } else { ctx.fillRect(x - w / 2, y - h / 2, w, h); } }
                _drawHead(ctx) { const faceColor = '#FFDBA5'; const hairColor = '#FFD700'; const capGreen = '#228B22'; ctx.save(); ctx.fillStyle = hairColor; ctx.beginPath(); ctx.arc(0, 0, 35, 0, Math.PI * 2); ctx.fill(); this._drawShadedRect(faceColor, 0, 10, 35, 45, 10); ctx.fillStyle = 'white'; ctx.beginPath(); ctx.ellipse(-8, 5, 5, 8, 0, 0, Math.PI * 2); ctx.ellipse(8, 5, 5, 8, 0, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = '#1E90FF'; ctx.beginPath(); ctx.arc(-8, 5, 2.5, 0, Math.PI * 2); ctx.arc(8, 5, 2.5, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = this._adjustColor(faceColor, -10); ctx.beginPath(); ctx.arc(0, 15, 3, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = faceColor; ctx.beginPath(); ctx.moveTo(25, 10); ctx.lineTo(35, 0); ctx.lineTo(25, -10); ctx.fill(); ctx.fillStyle = capGreen; ctx.beginPath(); ctx.moveTo(-30, -10); ctx.lineTo(30, -10); ctx.lineTo(0, -60); ctx.closePath(); ctx.fill(); ctx.restore(); }
                _drawTorso(ctx) { const tunicGreen = '#3CB371'; const beltBrown = '#8B4513'; ctx.save(); this._drawShadedRect(tunicGreen, 0, -40, 60, 80, 5); ctx.fillStyle = '#FFFFFF'; ctx.beginPath(); ctx.moveTo(-15, -80); ctx.lineTo(15, -80); ctx.lineTo(0, -50); ctx.closePath(); ctx.fill(); ctx.fillStyle = tunicGreen; ctx.beginPath(); ctx.moveTo(-40, 0); ctx.lineTo(40, 0); ctx.lineTo(60, 40); ctx.lineTo(-60, 40); ctx.closePath(); ctx.fill(); ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; ctx.beginPath(); ctx.moveTo(0, 5); ctx.bezierCurveTo(-30, 10, 30, 10, 0, 40); ctx.fill(); ctx.fillStyle = beltBrown; ctx.fillRect(-60, -10, 120, 10); ctx.fillStyle = '#FF0000'; ctx.beginPath(); ctx.arc(0, -5, 5, 0, Math.PI * 2); ctx.fill(); ctx.restore(); }
                _drawLimb(ctx, isArm, h, angle) { const color = isArm ? '#FFFFFF' : '#FFFFFF'; const w = isArm ? 15 : 25; ctx.save(); ctx.rotate(angle); this._drawShadedRect(color, 0, h / 2, w, h, w / 4, true); ctx.restore(); }
                _drawHand(ctx) { const gloveBrown = '#A0522D'; const handW = 25; const handH = 35; ctx.save(); this._drawShadedRect('#FFFFFF', 0, -5, handW, 10, 5, true); this._drawShadedRect(gloveBrown, 0, handH / 2 + 5, handW + 5, handH, 10, true); ctx.fillStyle = '#FF0000'; ctx.fillRect(-handW / 2, 5, handW, 5); ctx.restore(); }
                _drawFoot(ctx) { const bootBrown = '#8B4513'; const footW = 35; const footH = 20; ctx.save(); this._drawShadedRect(bootBrown, 0, -10, footW, 30, 10, true); ctx.fillStyle = bootBrown; ctx.beginPath(); ctx.ellipse(0, 15, footW * 0.7, footH, 0, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = '#FFD700'; ctx.fillRect(-footW / 2 + 5, -15, footW - 10, 5); ctx.restore(); }
                _drawLimbSet(joint1, joint2, joint3, isFront, isArm) { const ctx = this.ctx; const limbH1 = isArm ? 35 : 45; const limbH2 = isArm ? 35 : 45; ctx.save(); ctx.translate(joint1.x, joint1.y); this._drawLimb(ctx, isArm, limbH1, joint1.angle); ctx.translate(Math.sin(joint1.angle) * limbH1, Math.cos(joint1.angle) * limbH1); this._drawLimb(ctx, isArm, limbH2, joint2.angle); ctx.translate(Math.sin(joint2.angle) * limbH2, Math.cos(joint2.angle) * limbH2); if (isArm) { this._drawHand(ctx); } else { this._drawFoot(ctx); } ctx.restore(); }
                draw(ctx) { ctx.translate(0, -60); this._drawLimbSet(this.pose.thighR, this.pose.shinR, this.pose.footR, false, false); this._drawLimbSet(this.pose.thighL, this.pose.shinL, this.pose.footL, true, false); ctx.save(); ctx.rotate(this.pose.torsoAngle); this._drawTorso(ctx); ctx.translate(0, -90); this._drawHead(ctx); ctx.restore(); this._drawLimbSet(this.pose.armL, this.pose.forearmL, this.pose.handL, false, true); this._drawLimbSet(this.pose.armR, this.pose.forearmR, this.pose.handR, true, true); }
            }

            // --- Extracción y adaptación de samus-aran-2d-articulated-power-suit-detalle-mximo.html ---
            class SamusArticulada {
                constructor(ctx) { this.ctx = ctx; this.pose = { torsoAngle: 0, shoulderL: { x: -45, y: -65, angle: 0.2 }, armL: { x: 0, y: 30, angle: 0.1 }, forearmL: { x: 0, y: 35, angle: -0.1 }, shoulderR: { x: 45, y: -65, angle: -0.2 }, armR: { x: 0, y: 30, angle: -0.1 }, forearmR: { x: 0, y: 35, angle: 0.1 }, handR: { x: 0, y: 30, angle: 0 }, thighL: { x: -25, y: 30, angle: -0.05 }, shinL: { x: 0, y: 55, angle: 0.1 }, footL: { x: 0, y: 50, angle: 0 }, thighR: { x: 25, y: 30, angle: 0.05 }, shinR: { x: 0, y: 55, angle: -0.1 }, footR: { x: 0, y: 50, angle: 0 }, }; }
                _adjustColor(hex, lum) { hex = hex.replace(/[^0-9a-f]/gi, ''); if (hex.length < 6) { hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; } let rgb = "#", c, i; for (i = 0; i < 3; i++) { c = parseInt(hex.substr(i * 2, 2), 16); c = Math.round(Math.min(255, Math.max(0, c + lum))).toString(16); while (c.length < 2) c = "0" + c; rgb += c; } return rgb; }
                _drawShadedPlate(colorBase, w, h, radius = 5, isVertical = false) { const ctx = this.ctx; let grad; if (isVertical) { grad = ctx.createLinearGradient(-w / 2, 0, w / 2, 0); grad.addColorStop(0.0, this._adjustColor(colorBase, -40)); grad.addColorStop(0.3, this._adjustColor(colorBase, 0)); grad.addColorStop(0.7, this._adjustColor(colorBase, 50)); grad.addColorStop(1.0, this._adjustColor(colorBase, -20)); } else { grad = ctx.createLinearGradient(0, -h / 2, 0, h / 2); grad.addColorStop(0.0, this._adjustColor(colorBase, 50)); grad.addColorStop(0.3, this._adjustColor(colorBase, 0)); grad.addColorStop(0.8, this._adjustColor(colorBase, -40)); } ctx.fillStyle = grad; ctx.beginPath(); ctx.moveTo(-w / 2 + radius, -h / 2); ctx.lineTo(w / 2 - radius, -h / 2); ctx.quadraticCurveTo(w / 2, -h / 2, w / 2, -h / 2 + radius); ctx.lineTo(w / 2, h / 2 - radius); ctx.quadraticCurveTo(w / 2, h / 2, w / 2 - radius, h / 2); ctx.lineTo(-w / 2 + radius, h / 2); ctx.quadraticCurveTo(-w / 2, h / 2, -w / 2, h / 2 - radius); ctx.lineTo(-w / 2, -h / 2 + radius); ctx.quadraticCurveTo(-w / 2, -h / 2, -w / 2 + radius, -h / 2); ctx.closePath(); ctx.fill(); ctx.strokeStyle = 'rgba(0, 0, 0, 0.6)'; ctx.lineWidth = 1; ctx.stroke(); }
                _drawHelmet(ctx) { const orange = '#FF4500'; const red = '#CC0000'; const green = '#3CB371'; ctx.save(); ctx.beginPath(); ctx.ellipse(0, 0, 35, 40, 0, 0, Math.PI * 2); ctx.fillStyle = this._adjustColor(orange, -10); ctx.fill(); ctx.beginPath(); ctx.moveTo(-35, 0); ctx.lineTo(35, 0); ctx.arc(0, 0, 35, 0, Math.PI, true); ctx.fillStyle = this._adjustColor(red, 0); ctx.fill(); ctx.fillStyle = green; ctx.beginPath(); ctx.moveTo(-20, 5); ctx.lineTo(-10, 15); ctx.lineTo(10, 15); ctx.lineTo(20, 5); ctx.lineTo(15, 0); ctx.lineTo(-15, 0); ctx.closePath(); ctx.fill(); ctx.fillStyle = orange; ctx.fillRect(-25, 40, 50, 10); ctx.restore(); }
                _drawTorso(ctx) { const orange = '#FF4500'; const yellow = '#FFD700'; ctx.save(); ctx.rotate(this.pose.torsoAngle); this._drawShadedPlate(orange, 80, 100, 25); ctx.fillStyle = yellow; ctx.beginPath(); ctx.ellipse(0, 55, 30, 15, 0, 0, Math.PI * 2); ctx.fill(); ctx.beginPath(); ctx.arc(0, -30, 10, 0, Math.PI * 2); ctx.fillStyle = '#1E90FF'; ctx.fill(); ctx.restore(); }
                _drawLimbPlate(color, w, h, angle) { const ctx = this.ctx; ctx.save(); ctx.rotate(angle); this._drawShadedPlate(color, w, h, w / 2, true); ctx.restore(); }
                _drawShoulder(ctx, isCannon = false) { const orange = '#FF4500'; const jointColor = '#808080'; ctx.save(); ctx.beginPath(); ctx.arc(0, 0, 20, 0, Math.PI * 2); ctx.fillStyle = this._adjustColor(jointColor, -10); ctx.fill(); ctx.translate(0, -10); this._drawShadedPlate(orange, 50, 40, 20); ctx.strokeStyle = '#FFFFFF'; ctx.lineWidth = 2; ctx.stroke(); ctx.restore(); }
                _drawCannon(ctx) { const green = '#3CB371'; const blue = '#1E90FF'; const orange = '#FF4500'; ctx.save(); this._drawLimbPlate(orange, 30, 20, 0); ctx.translate(0, 40); this._drawLimbPlate(green, 40, 60, 0); ctx.translate(0, 30); ctx.beginPath(); ctx.ellipse(0, 0, 30, 10, 0, 0, Math.PI * 2); ctx.fillStyle = this._adjustColor(blue, 30); ctx.fill(); ctx.restore(); }
                _drawHand(ctx) { const orange = '#FF4500'; ctx.save(); this._drawLimbPlate(orange, 25, 30, 0); ctx.translate(0, 15); ctx.beginPath(); ctx.arc(0, 0, 15, 0, Math.PI * 2); ctx.fillStyle = this._adjustColor(orange, -20); ctx.fill(); ctx.restore(); }
                _drawBoot(ctx) { const orange = '#FF4500'; const yellow = '#FFD700'; ctx.save(); ctx.translate(0, -10); this._drawShadedPlate(orange, 40, 30, 15); ctx.translate(0, 40); ctx.fillStyle = orange; ctx.beginPath(); ctx.moveTo(-30, -30); ctx.lineTo(30, -30); ctx.lineTo(40, 20); ctx.lineTo(-40, 20); ctx.closePath(); ctx.fill(); ctx.fillStyle = yellow; ctx.fillRect(-40, 15, 80, 5); ctx.restore(); }
                _drawLimbSet(joint1, joint2, joint3, isFront, isArm, shoulderJoint = null, isCannon = false) { const ctx = this.ctx; const orange = '#FF4500'; const yellow = '#FFD700'; const limbH1 = isArm ? 30 : 55; const limbH2 = isArm ? 35 : 55; const limbW = isArm ? 25 : 35; ctx.save(); ctx.translate(joint1.x, joint1.y); if (shoulderJoint) { this._drawShoulder(ctx, isCannon); } if (!isArm) { this._drawLimbPlate(orange, limbW, limbH1, joint1.angle); ctx.save(); ctx.rotate(joint1.angle); ctx.translate(0, limbH1); ctx.beginPath(); ctx.arc(0, 0, 10, 0, Math.PI * 2); ctx.fillStyle = this._adjustColor(yellow, -20); ctx.fill(); ctx.restore(); } else if (!shoulderJoint) { this._drawLimbPlate(orange, limbW, limbH1, joint1.angle); } ctx.translate(Math.sin(joint1.angle) * limbH1, Math.cos(joint1.angle) * limbH1); if (isArm && !isCannon) { this._drawLimbPlate(orange, limbW, limbH2, joint2.angle); } else if (!isArm) { this._drawLimbPlate(orange, limbW, limbH2, joint2.angle); } ctx.translate(Math.sin(joint2.angle) * limbH2, Math.cos(joint2.angle) * limbH2); if (isCannon) { this._drawCannon(ctx); } else if (isArm && joint3) { this._drawHand(ctx); } else if (!isArm) { this._drawBoot(ctx); } ctx.restore(); }
                draw(ctx) { ctx.translate(0, -100); this._drawLimbSet(this.pose.thighR, this.pose.shinR, this.pose.footR, false, false); this._drawLimbSet(this.pose.thighL, this.pose.shinL, this.pose.footL, true, false); ctx.save(); this._drawTorso(ctx); ctx.translate(0, -110); this._drawHelmet(ctx); ctx.restore(); this._drawLimbSet(this.pose.armR, this.pose.forearmR, this.pose.handR, false, true, this.pose.shoulderR); this._drawLimbSet(this.pose.armL, this.pose.forearmL, null, true, true, this.pose.shoulderL, true); }
            }

            // --- Extracción y adaptación de personaje-de-sonic-articulado-2d-detalle-mximo.html ---
            class SonicArticulado {
                constructor(ctx) { this.ctx = ctx; this.pose = { torsoAngle: 0, headAngle: 0, armL: { x: -30, y: -40, angle: 0.1 }, forearmL: { x: 0, y: 35, angle: 0.1 }, handL: { x: 0, y: 30, angle: 0 }, armR: { x: 30, y: -40, angle: -0.1 }, forearmR: { x: 0, y: 35, angle: -0.1 }, handR: { x: 0, y: 30, angle: 0 }, thighL: { x: -15, y: 40, angle: -0.05 }, shinL: { x: 0, y: 45, angle: 0.1 }, footL: { x: 0, y: 45, angle: 0 }, thighR: { x: 15, y: 40, angle: 0.05 }, shinR: { x: 0, y: 45, angle: -0.1 }, footR: { x: 0, y: 45, angle: 0 }, }; }
                _adjustColor(hex, lum) { hex = hex.replace(/[^0-9a-f]/gi, ''); if (hex.length < 6) { hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; } let rgb = "#", c, i; for (i = 0; i < 3; i++) { c = parseInt(hex.substr(i * 2, 2), 16); c = Math.round(Math.min(255, Math.max(0, c + lum))).toString(16); while (c.length < 2) c = "0" + c; rgb += c; } return rgb; }
                _drawShadedRect(colorBase, w, h, radius = 0, isVertical = false) { const ctx = this.ctx; let grad; if (isVertical) { grad = ctx.createLinearGradient(-w / 2, 0, w / 2, 0); grad.addColorStop(0.0, this._adjustColor(colorBase, -30)); grad.addColorStop(0.5, colorBase); grad.addColorStop(1.0, this._adjustColor(colorBase, 20)); } else { grad = ctx.createLinearGradient(0, -h / 2, 0, h / 2); grad.addColorStop(0.0, this._adjustColor(colorBase, 20)); grad.addColorStop(0.5, colorBase); grad.addColorStop(1.0, this._adjustColor(colorBase, -30)); } ctx.fillStyle = grad; ctx.beginPath(); ctx.moveTo(-w / 2 + radius, -h / 2); ctx.lineTo(w / 2 - radius, -h / 2); ctx.quadraticCurveTo(w / 2, -h / 2, w / 2, -h / 2 + radius); ctx.lineTo(w / 2, h / 2 - radius); ctx.quadraticCurveTo(w / 2, h / 2, w / 2 - radius, h / 2); ctx.lineTo(-w / 2 + radius, h / 2); ctx.quadraticCurveTo(-w / 2, h / 2, -w / 2, h / 2 - radius); ctx.lineTo(-w / 2, -h / 2 + radius); ctx.quadraticCurveTo(-w / 2, -h / 2, -w / 2 + radius, -h / 2); ctx.closePath(); ctx.fill(); }
                _drawHead(ctx) { const blue = '#1E90FF'; const peach = '#FFDBA5'; ctx.save(); ctx.rotate(this.pose.headAngle); ctx.fillStyle = this._adjustColor(blue, -20); for(let i=0; i<3; i++) { ctx.save(); ctx.rotate(0.3 * (i - 1)); ctx.beginPath(); ctx.moveTo(0, -50); ctx.lineTo(15, -15); ctx.lineTo(-15, -15); ctx.closePath(); ctx.fill(); ctx.restore(); } this._drawShadedRect(blue, 60, 70, 35, true); ctx.translate(0, 10); this._drawShadedRect(peach, 40, 35, 20); ctx.fillStyle = blue; ctx.beginPath(); ctx.moveTo(-30, -55); ctx.lineTo(-50, -65); ctx.lineTo(-35, -45); ctx.fill(); ctx.fillStyle = this._adjustColor(peach, -10); ctx.beginPath(); ctx.moveTo(-35, -50); ctx.lineTo(-45, -60); ctx.lineTo(-35, -45); ctx.fill(); ctx.fillStyle = 'white'; ctx.beginPath(); ctx.moveTo(-25, -20); ctx.arc(-10, -20, 15, Math.PI, Math.PI * 1.5); ctx.arc(10, -20, 15, Math.PI * 1.5, Math.PI * 2); ctx.lineTo(25, -20); ctx.closePath(); ctx.fill(); ctx.fillStyle = '#006400'; ctx.beginPath(); ctx.arc(-5, -15, 4, 0, Math.PI * 2); ctx.arc(5, -15, 4, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = 'black'; ctx.beginPath(); ctx.arc(-5, -15, 1, 0, Math.PI * 2); ctx.arc(5, -15, 1, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = 'black'; ctx.beginPath(); ctx.ellipse(0, -5, 7, 5, 0, 0, Math.PI * 2); ctx.fill(); ctx.restore(); }
                _drawTorso(ctx) { const blue = '#1E90FF'; const peach = '#FFDBA5'; ctx.save(); ctx.rotate(this.pose.torsoAngle); this._drawShadedRect(blue, 50, 60, 20, true); ctx.translate(0, 5); this._drawShadedRect(peach, 40, 45, 20); ctx.fillStyle = this._adjustColor(blue, -30); ctx.beginPath(); ctx.moveTo(-20, -30); ctx.lineTo(0, -50); ctx.lineTo(20, -30); ctx.closePath(); ctx.fill(); ctx.restore(); }
                _drawLimb(ctx, h, angle) { const blue = '#1E90FF'; const w = 15; ctx.save(); ctx.rotate(angle); this._drawShadedRect(blue, w, h, w / 2, true); ctx.restore(); }
                _drawHand(ctx) { const white = '#FFFFFF'; const handW = 20; const handH = 20; ctx.save(); this._drawShadedRect(white, handW * 0.9, 10, 5); ctx.translate(0, 15); this._drawShadedRect(white, handW, handH, 10); ctx.fillStyle = this._adjustColor(white, -20); ctx.fillRect(-handW * 0.4, 5, 5, 5); ctx.fillRect(0, 5, 5, 5); ctx.restore(); }
                _drawFoot(ctx) { const red = '#FF0000'; const white = '#FFFFFF'; const yellow = '#FFD700'; ctx.save(); this._drawShadedRect(white, 20, 20, 10); ctx.translate(0, 15); ctx.rotate(0.1); this.ctx.beginPath(); this.ctx.ellipse(0, 0, 40, 25, 0, 0, Math.PI * 2); this.ctx.fillStyle = red; this.ctx.fill(); ctx.fillStyle = white; ctx.fillRect(-40, -10, 80, 5); ctx.fillStyle = yellow; ctx.fillRect(30, -20, 10, 10); ctx.restore(); }
                _drawLimbSet(joint1, joint2, joint3, isFront, isArm) { const ctx = this.ctx; const limbH1 = 40; const limbH2 = 40; ctx.save(); ctx.translate(joint1.x, joint1.y); this._drawLimb(ctx, limbH1, joint1.angle); ctx.translate(Math.sin(joint1.angle) * limbH1, Math.cos(joint1.angle) * limbH1); this._drawLimb(ctx, limbH2, joint2.angle); ctx.translate(Math.sin(joint2.angle) * limbH2, Math.cos(joint2.angle) * limbH2); if (isArm) { this._drawHand(ctx); } else { this._drawFoot(ctx); } ctx.restore(); }
                draw(ctx) { ctx.translate(0, -60); this._drawLimbSet(this.pose.thighR, this.pose.shinR, this.pose.footR, false, false); this._drawLimbSet(this.pose.armL, this.pose.forearmL, this.pose.handL, false, true); ctx.save(); this._drawTorso(ctx); ctx.translate(0, -65); this._drawHead(ctx); ctx.restore(); this._drawLimbSet(this.pose.thighL, this.pose.shinL, this.pose.footL, true, false); ctx.save(); ctx.translate(this.pose.armR.x, this.pose.armR.y); this._drawLimbSet(this.pose.armR, this.pose.forearmR, this.pose.handR, true, true); ctx.restore(); }
            }

            // =====================================================================
            // CLASE FIGHTER (Clase contenedora con lógica de física y animación)
            // =====================================================================

            class Fighter {
                constructor(id, name, color, initialX, initialY, drawClass, ctx) {
                    this.id = id;
                    this.name = name;
                    this.color = color;
                    this.drawImpl = new drawClass(ctx); // La clase de dibujo detallada

                    this.x = initialX;
                    this.y = initialY;
                    this.vx = 0;
                    this.vy = 0;
                    this.onGround = false;
                    this.jumpsLeft = 2;
                    this.damage = 0;
                    this.stock = CONFIG.MAX_STOCK;
                    this.hitStunTimer = 0;
                    this.facing = 1;
                    this.size = 100 * CONFIG.SCALE;
                }

                updatePose() {
                    // Adaptar la animación de pose en función del estado (Aquí solo idle para Rest Area)
                    const t = CONFIG.TIME * 5;
                    if (this.drawImpl.pose) {
                        // Animación de idle (reposo sutil)
                        if (this.drawImpl.pose.armL) this.drawImpl.pose.armL.angle = 0.1 + Math.sin(t * 0.3) * 0.1;
                        if (this.drawImpl.pose.armR) this.drawImpl.pose.armR.angle = -0.1 - Math.sin(t * 0.3) * 0.1;
                    } else if (this.drawImpl.pose.bodyAngle !== undefined) {
                        this.drawImpl.pose.bodyAngle = Math.sin(t * 0.2) * 0.03; // Kirby
                    } else if (this.drawImpl.pose.headAngle !== undefined) {
                        this.drawImpl.pose.headAngle = Math.cos(t * 0.4) * 0.03; // Pikachu/Sonic
                    }
                }

                // Los demás métodos de física (updatePhysics, takeDamage, attack) se omiten ya que no son necesarios en el modo REST_AREA.

                draw(ctx) {
                    ctx.save();
                    ctx.translate(this.x, this.y);
                    ctx.scale(this.facing * CONFIG.SCALE, CONFIG.SCALE);

                    this.drawImpl.draw(ctx);

                    ctx.restore();
                }
            }

            // =====================================================================
            // CLASES DE GESTIÓN (Música, UI, Input)
            // =====================================================================

            class MusicManager {
                static _currentTrack = null;
                static _audioElements = {};

                static init() {
                    const trackIds = ['menu-music', 'select-music', 'mario-music', 'kirby-music', 'metroid-music', 'zelda-music', 'sonic-music', 'pokemon-music', 'drawaria-music', 'hit-sfx', 'ko-sfx'];
                    trackIds.forEach(id => {
                        this._audioElements[id] = document.getElementById(id);
                    });
                }

                static playTrack(id) {
                    if (this._currentTrack === this._audioElements[id]) return;

                    if (this._currentTrack) {
                        this._currentTrack.pause();
                        this._currentTrack.currentTime = 0;
                    }

                    this._currentTrack = this._audioElements[id];
                    if (this._currentTrack) {
                        this._currentTrack.volume = 0.6;
                        this._currentTrack.play().catch(e => console.error("Error al reproducir música:", e));
                    }
                }

                static playSFX(id) {
                    const sfx = this._audioElements[id];
                    if (sfx) {
                        sfx.currentTime = 0;
                        sfx.volume = 0.8;
                        sfx.play().catch(e => console.error("Error al reproducir SFX:", e));
                    }
                }
            }

            class UIManager {
                constructor(ctx) {
                    this.ctx = ctx;
                }

                _drawFighterGrid(fighterList) {
                    const ctx = this.ctx;
                    const W = CONFIG.WIDTH;
                    const H = CONFIG.HEIGHT;

                    const gridX = W * 0.05;
                    const gridY = H * 0.2;
                    const cols = 4;
                    const cellW = 50;
                    const cellH = 50;
                    const padding = 5;

                    fighterList.forEach((fighter, index) => {
                        const row = Math.floor(index / cols);
                        const col = index % cols;

                        const x = gridX + col * (cellW + padding);
                        const y = gridY + row * (cellH + padding);

                        // Contenedor del ícono
                        ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';
                        ctx.fillRect(x, y, cellW, cellH);

                        // Si es el luchador activo, resáltalo
                        if (fighter.id === CONFIG.ACTIVE_FIGHTER_DATA.id) {
                            ctx.strokeStyle = (CONFIG.TIME % 0.1 < 0.05) ? '#FFD700' : '#FF00FF';
                            ctx.lineWidth = 3;
                            ctx.shadowColor = ctx.strokeStyle;
                            ctx.shadowBlur = 10;
                            ctx.strokeRect(x, y, cellW, cellH);
                            ctx.shadowBlur = 0;
                        }

                        // Dibuja el ícono (Implementación Placeholder simplificada: solo un círculo de color)
                        ctx.save();
                        ctx.translate(x + cellW/2, y + cellH/2);
                        ctx.scale(0.08 * CONFIG.SCALE, 0.08 * CONFIG.SCALE);

                        // Crear una instancia temporal solo para dibujar la miniatura
                        const tempFighter = new fighter.class(ctx);
                        tempFighter.draw(ctx);

                        ctx.restore();
                    });
                }

                _drawRestArea(fighter) {
                    const ctx = this.ctx;
                    const W = CONFIG.WIDTH;
                    const H = CONFIG.HEIGHT;

                    // 1. Timer (Top Center)
                    ctx.font = 'bold 50px Arial';
                    ctx.textAlign = 'center';
                    ctx.fillStyle = 'white';
                    ctx.shadowColor = 'black';
                    ctx.shadowBlur = 5;

                    const minutes = Math.floor(CONFIG.REST_AREA_TIMER / 60);
                    const seconds = Math.floor(CONFIG.REST_AREA_TIMER % 60);
                    const centiseconds = Math.floor((CONFIG.REST_AREA_TIMER * 100) % 100);
                    const timerText = \`\${minutes.toString().padStart(2, '0')}:\${seconds.toString().padStart(2, '0')} \${centiseconds.toString().padStart(2, '0')}\`;

                    ctx.fillText(timerText, W / 2, H * 0.1);
                    ctx.shadowBlur = 0;

                    // 2. Cuadrícula de Personajes (Grid de la esquina superior izquierda)
                    this._drawFighterGrid(CONFIG.FIGHTER_LIST);

                    // 3. HUD de Daño y Vidas (Bottom Left, estilo Melee)

                    // Iconos de Corazón (Stocks)
                    const heartX = W * 0.1;
                    const heartY = H * 0.7;
                    for (let i = 0; i < fighter.stock; i++) {
                        ctx.save();
                        ctx.translate(heartX + i * 100, heartY);

                        // Dibuja un corazón simplificado (simula el asset 3D)
                        ctx.fillStyle = 'rgba(0, 255, 0, 0.4)';
                        ctx.strokeStyle = 'rgba(0, 255, 0, 0.8)';
                        ctx.lineWidth = 3;
                        ctx.shadowColor = 'rgba(0, 255, 0, 0.6)';
                        ctx.shadowBlur = 10;
                        ctx.beginPath();
                        ctx.moveTo(0, 20);
                        ctx.bezierCurveTo(20, 0, 40, 0, 0, -40);
                        ctx.bezierCurveTo(-40, 0, -20, 0, 0, 20);
                        ctx.fill();
                        ctx.stroke();
                        ctx.restore();
                    }

                    // Porcentaje de Daño (Simulación de 18% en la imagen)
                    ctx.font = 'bold 100px Arial Black';
                    ctx.textAlign = 'left';
                    ctx.fillStyle = '#FFFFFF';
                    ctx.strokeStyle = '#000000';
                    ctx.lineWidth = 4;
                    const damageText = \`Rest Area\`;
                    ctx.fillText(damageText, W * 0.1, H * 0.95);
                    ctx.strokeText(damageText, W * 0.1, H * 0.95);

                    // Indicador P1 (Sobre el luchador)
                    ctx.font = 'bold 30px Arial Black';
                    ctx.fillStyle = 'red';
                    ctx.textAlign = 'center';
                    ctx.fillText('P1', fighter.x, fighter.y - fighter.size * 1.5);
                    ctx.beginPath();
                    ctx.moveTo(fighter.x - 10, fighter.y - fighter.size * 1.4);
                    ctx.lineTo(fighter.x + 10, fighter.y - fighter.size * 1.4);
                    ctx.lineTo(fighter.x, fighter.y - fighter.size * 1.3);
                    ctx.closePath();
                    ctx.fill();
                }

                draw(gameState, fighters, winner) {
                    switch (gameState) {
                        case 'REST_AREA':
                            this._drawRestArea(Game.restFighter);
                            break;
                        // ... (otros estados pueden estar aquí, pero nos centramos en REST_AREA)
                    }
                }
            }

            // El InputManager se adapta para solo manejar clics en este modo.
            class InputManager {
                constructor() {
                    // No necesitamos keydown/keyup para el modo Rest Area, solo el evento de clic.
                }
            }


            // =====================================================================
            // CLASE GAME (Controlador Principal)
            // =====================================================================

            class SmashGame {
                constructor() {
                    this.canvas = document.getElementById('game-canvas');
                    this.ctx = this.canvas.getContext('2d');
                    this._initDimensions();
                    window.addEventListener('resize', this._initDimensions.bind(this));

                    // Inicializar gestores
                    MusicManager.init();
                    this.inputManager = new InputManager();
                    this.uiManager = new UIManager(this.ctx);

                    // Definición de personajes
                    CONFIG.FIGHTER_LIST = [
                        { id: 'MARIO', name: 'Mario', color: 'red', class: MarioArticulado, music: 'mario-music' },
                        { id: 'KIRBY', name: 'Kirby', color: 'pink', class: KirbyArticulado, music: 'kirby-music' },
                        { id: 'PIKACHU', name: 'Pikachu', color: 'yellow', class: PikachuArticulado, music: 'pokemon-music' },
                        { id: 'LINK', name: 'Link', color: 'green', class: LinkArticulado, music: 'zelda-music' },
                        { id: 'SAMUS', name: 'Samus', color: 'orange', class: SamusArticulada, music: 'metroid-music' },
                        { id: 'SONIC', name: 'Sonic', color: 'blue', class: SonicArticulado, music: 'sonic-music' },
                    ];

                    this.fighters = [];
                    this.winner = null;
                    this.lastTime = 0;

                    // --- Inicializar el luchador para el Rest Area ---
                    CONFIG.ACTIVE_FIGHTER_DATA = CONFIG.FIGHTER_LIST.find(f => f.id === 'MARIO');
                    if (!CONFIG.ACTIVE_FIGHTER_DATA) CONFIG.ACTIVE_FIGHTER_DATA = CONFIG.FIGHTER_LIST[0]; // Fallback a Mario
                    this.restFighter = this._createRestFighter();
                    // --------------------------------------------------------

                    // --- Manejador de Clicks para el Grid ---
                    this.canvas.addEventListener('click', this._handleCanvasClick.bind(this));
                    // -----------------------------------------------

                    this.rafHandle = requestAnimationFrame(this._gameLoop.bind(this));
                }

                _initDimensions() {
                    CONFIG.WIDTH = window.innerWidth;
                    CONFIG.HEIGHT = window.innerHeight;
                    this.canvas.width = CONFIG.WIDTH;
                    this.canvas.height = CONFIG.HEIGHT;
                    CONFIG.SCALE = Math.min(CONFIG.WIDTH / 1200, CONFIG.HEIGHT / 1000) * 1.5;

                    // Re-crear el luchador para asegurar la posición correcta después de la escala/dimensiones
                    if (this.restFighter) this.restFighter = this._createRestFighter();
                }

                _createRestFighter() {
                    if (!CONFIG.ACTIVE_FIGHTER_DATA || !this.ctx) return null;
                    const W = CONFIG.WIDTH;
                    const H = CONFIG.HEIGHT;

                    const fighter = new Fighter(
                        'P1',
                        CONFIG.ACTIVE_FIGHTER_DATA.name,
                        CONFIG.ACTIVE_FIGHTER_DATA.color,
                        W / 2,
                        H * 0.7,
                        CONFIG.ACTIVE_FIGHTER_DATA.class,
                        this.ctx
                    );
                    fighter.damage = 18; // Daño inicial como en la imagen de referencia
                    fighter.stock = 2; // Dos corazones
                    fighter.facing = -1; // Mirando hacia la izquierda (hacia el grid)
                    return fighter;
                }

                _handleCanvasClick(e) {
                    if (CONFIG.STATE !== 'REST_AREA') return;

                    const W = CONFIG.WIDTH;
                    const H = CONFIG.HEIGHT;
                    const x = e.clientX;
                    const y = e.clientY;

                    const gridX = W * 0.05;
                    const gridY = H * 0.2;
                    const cols = 4;
                    const cellW = 50;
                    const cellH = 50;
                    const padding = 5;

                    // Comprobar colisión con la cuadrícula
                    CONFIG.FIGHTER_LIST.forEach((fighter, index) => {
                        const row = Math.floor(index / cols);
                        const col = index % cols;

                        const cellLeft = gridX + col * (cellW + padding);
                        const cellTop = gridY + row * (cellH + padding);

                        if (x >= cellLeft && x <= cellLeft + cellW &&
                            y >= cellTop && y <= cellTop + cellH) {

                            // Personaje clickeado
                            CONFIG.ACTIVE_FIGHTER_DATA = fighter;
                            this.restFighter = this._createRestFighter();
                            MusicManager.playSFX('hit-sfx'); // SFX de golpe como placeholder de click
                            return;
                        }
                    });
                }

                _gameLoop(time) {
                    const dt = (time - this.lastTime) / 1000 || 0;
                    this.lastTime = time;
                    CONFIG.TIME = time / 1000;

                    this.ctx.clearRect(0, 0, CONFIG.WIDTH, CONFIG.HEIGHT);

                    // Actualizar el Timer
                    if (CONFIG.STATE === 'REST_AREA') {
                        // El timer solo sube/avanza en este ejemplo
                        CONFIG.REST_AREA_TIMER += dt;
                    }

                    switch (CONFIG.STATE) {
                        case 'REST_AREA':
                            MusicManager.playTrack('menu-music'); // Música del Rest Area de Melee

                            // --- DIBUJO DEL FONDO TIPO REST AREA (Green Hill Zone) ---

                            // 1. Cielo (Azul)
                            this.ctx.fillStyle = '#61A9FF';
                            this.ctx.fillRect(0, 0, CONFIG.WIDTH, CONFIG.HEIGHT);

                            // 2. Césped y Arboles (Fondo)
                            this.ctx.fillStyle = '#3CB371';
                            this.ctx.fillRect(0, CONFIG.HEIGHT * 0.4, CONFIG.WIDTH, CONFIG.HEIGHT * 0.6);

                            // Dibujar árboles simplificados (Silueta)
                            this.ctx.fillStyle = '#2F4F4F'; // Gris oscuro para la lejanía
                            this.ctx.beginPath();
                            this.ctx.moveTo(0, CONFIG.HEIGHT * 0.45);
                            this.ctx.bezierCurveTo(CONFIG.WIDTH * 0.2, CONFIG.HEIGHT * 0.3, CONFIG.WIDTH * 0.8, CONFIG.HEIGHT * 0.3, CONFIG.WIDTH, CONFIG.HEIGHT * 0.45);
                            this.ctx.lineTo(CONFIG.WIDTH, CONFIG.HEIGHT * 0.6);
                            this.ctx.lineTo(0, CONFIG.HEIGHT * 0.6);
                            this.ctx.closePath();
                            this.ctx.fill();

                            // 3. Primer Plano (Césped vibrante con sendero)
                            this.ctx.fillStyle = '#55A855'; // Césped más oscuro
                            this.ctx.fillRect(0, CONFIG.HEIGHT * 0.65, CONFIG.WIDTH, CONFIG.HEIGHT * 0.35);

                            // Sendero de tierra
                            this.ctx.fillStyle = '#8B4513';
                            this.ctx.beginPath();
                            this.ctx.ellipse(CONFIG.WIDTH / 2, CONFIG.HEIGHT * 0.75, CONFIG.WIDTH * 0.5, 30, 0, 0, Math.PI * 2);
                            this.ctx.fill();


                            // --- DIBUJO DE ELEMENTOS DE JUEGO ---

                            // Actualizar y Dibujar el Luchador Activo
                            if (this.restFighter) {
                                this.restFighter.updatePose();
                                this.restFighter.draw(this.ctx);
                            }

                            // Dibujar la UI
                            this.uiManager.draw('REST_AREA', null);
                            break;

                        // Los demás estados de juego se omiten intencionalmente para la escena de Rest Area.
                        case 'MENU':
                        case 'CHARACTER_SELECT':
                        case 'BATTLE':
                        case 'RESULTS':
                            // Evitar fallos si se cambia el estado
                            this.ctx.font = '50px Arial';
                            this.ctx.fillStyle = 'red';
                            this.ctx.fillText("MODO NO IMPLEMENTADO EN ESTA VERSIÓN", CONFIG.WIDTH / 2, CONFIG.HEIGHT / 2);
                            break;
                    }

                    this.rafHandle = requestAnimationFrame(this._gameLoop.bind(this));
                }
            }

            // =====================================================================
            // INICIADOR GLOBAL Y MÚSICA DE FONDO
            // =====================================================================
            let Game;

            // Usamos DOMContentLoaded en lugar de 'load' para iniciar antes y
            // no esperar a que todas las imágenes de la página de destino carguen.
            window.addEventListener('load', () => {
                Game = new SmashGame();

                // Lógica de reproducción del audio bg-music del final del script original
                const music = document.getElementById('bg-music');
                // Intentar reproducir al hacer clic en cualquier parte de la pantalla
                document.body.addEventListener('click', () => {
                    // Intenta reproducir solo si está pausado
                    if (music && music.paused) {
                        music.play().catch(e => console.log("Se requiere interacción para la música de fondo.", e));
                    }
                });
            });
        `;

        // Inyectar el script usando un elemento <script> para asegurar el ámbito global (window)
        const script = document.createElement('script');
        script.textContent = scriptContent;
        document.body.appendChild(script);
    }

    // ----------------------------------------------------
    // EJECUCIÓN DEL SCRIPT
    // ----------------------------------------------------

    // Asegurarse de que el script se inyecta después de que el cuerpo del documento esté listo.
    if (document.body) {
        injectCSS();
        injectHTML();
        injectGameScript();
    } else {
        document.addEventListener('DOMContentLoaded', () => {
            injectCSS();
            injectHTML();
            injectGameScript();
        });
    }

})();