☰

Drawaria Super Mario Levels πŸ„

Motor de renderizado de mapas HD. Texturas vectoriales, sombras 3D, nubes, arbustos y castillo sin sacrificar el rendimiento instantΓ‘neo.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Drawaria Super Mario Levels πŸ„
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  Motor de renderizado de mapas HD. Texturas vectoriales, sombras 3D, nubes, arbustos y castillo sin sacrificar el rendimiento instantΓ‘neo.
// @author       YouTubeDrawaria
// @match        https://drawaria.online/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=drawaria.online
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    /* ---------- SHARED GLOBALS ---------- */
    let drawariaSocket = null;
    let drawariaCanvas = null;
    let drawariaCtx = null;

    /* ---------- BATCH QUEUE SYSTEM ---------- */
    const commandQueue =[];
    let batchProcessor = null;
    const BATCH_SIZE = 70; // Aumentado para soportar texturas HD
    const BATCH_INTERVAL = 20;

    const originalWebSocketSend = WebSocket.prototype.send;
    WebSocket.prototype.send = function (...args) {
        if (!drawariaSocket && this.url && this.url.includes('drawaria')) {
            drawariaSocket = this;
            console.log('πŸ„ Level Maker HD: WebSocket Interceptado.');
            startBatchProcessor();
        }
        return originalWebSocketSend.apply(this, args);
    };

    function startBatchProcessor() {
        if (batchProcessor) return;
        batchProcessor = setInterval(() => {
            if (!drawariaSocket || drawariaSocket.readyState !== WebSocket.OPEN || commandQueue.length === 0) return;
            const batch = commandQueue.splice(0, BATCH_SIZE);
            batch.forEach(cmd => { try { drawariaSocket.send(cmd); } catch (e) {} });
        }, BATCH_INTERVAL);
    }

    // Nuevo parΓ‘metro CAP para permitir bordes redondos en nubes
    function enqueueDrawCommand(x1, y1, x2, y2, color, thickness, cap = 'square') {
        if (!drawariaCanvas) return;
        if (drawariaCtx) {
            drawariaCtx.strokeStyle = color;
            drawariaCtx.lineWidth = thickness;
            drawariaCtx.lineCap = cap;
            drawariaCtx.lineJoin = 'miter';
            drawariaCtx.beginPath();
            drawariaCtx.moveTo(x1, y1);
            drawariaCtx.lineTo(x2, y2);
            drawariaCtx.stroke();
        }
        const normX1 = (x1 / drawariaCanvas.width).toFixed(4);
        const normY1 = (y1 / drawariaCanvas.height).toFixed(4);
        const normX2 = (x2 / drawariaCanvas.width).toFixed(4);
        const normY2 = (y2 / drawariaCanvas.height).toFixed(4);

        // El servidor Drawaria usa el boolean del array para determinar si es lΓ­nea normal (false)
        const cmd = `42["drawcmd",0,[${normX1},${normY1},${normX2},${normY2},false,${-Math.abs(thickness)},"${color}",0,0,{"2":0,"3":0.5,"4":0.5}]]`;
        commandQueue.push(cmd);
    }

    async function cleanCanvas(skyColor) {
        if (!drawariaCanvas) return;
        const w = drawariaCanvas.width;
        const h = drawariaCanvas.height;
        if (drawariaCtx) drawariaCtx.clearRect(0, 0, w, h);

        const nukeThickness = Math.max(w, h) * 2;
        enqueueDrawCommand(w/2, h/2, w/2 + 0.1, h/2 + 0.1, skyColor, nukeThickness);
        await new Promise(r => setTimeout(r, 60));
    }

    /* ---------- HD TILE RENDER ENGINE ---------- */
    const PALETTE = {
        'G': { base: '#c84c0c' }, // Suelo
        'B': { base: '#cc5400' }, // Ladrillos
        '?': { base: '#f8b800' }, // Bloque Moneda
        'T': { base: '#00a800' }, // TuberΓ­a Top
        'P': { base: '#00a800' }, // TuberΓ­a Cuerpo
        'H': { base: '#f8d8b0' }, // Bloque Duro
        'U': { base: '#000000' }, // Muro subterrΓ‘neo
        'O': { base: '#008888' }, // Ladrillos subterrΓ‘neos
        'W': { base: '#ffffff', bg: true }, // Nubes
        'S': { base: '#00a800', bg: true }  // Arbustos
    };

    function drawDecorations(char, startX, endX, cy, len, blockW, h, isUnderground) {
        const topY = cy - h/2;
        const bottomY = cy + h/2;
        const w = blockW * len;

        switch(char) {
            case 'W': // Nubes (Round caps)
                enqueueDrawCommand(startX + blockW/2, cy, endX - blockW/2, cy, '#ffffff', h, 'round');
                enqueueDrawCommand(startX + blockW, cy - h*0.4, endX - blockW, cy - h*0.4, '#ffffff', h*0.8, 'round');
                break;
            case 'S': // Arbustos (Round caps)
                enqueueDrawCommand(startX + blockW/2, cy + h*0.2, endX - blockW/2, cy + h*0.2, '#00a800', h*0.6, 'round');
                enqueueDrawCommand(startX + blockW, cy - h*0.1, endX - blockW, cy - h*0.1, '#00a800', h*0.5, 'round');
                enqueueDrawCommand(startX + blockW/2, bottomY, endX - blockW/2, bottomY, '#000000', 3); // Sombra base
                break;
            case 'G': // Suelo HD
                if (!isUnderground) enqueueDrawCommand(startX, topY + 2, endX, topY + 2, '#00a800', 4); // Pasto
                enqueueDrawCommand(startX, topY, endX, topY, '#000000', 2); // Borde
                // Textura rocosa
                for(let i=0; i<len; i++) {
                    enqueueDrawCommand(startX + i*blockW + 5, cy, startX + i*blockW + 15, cy, '#a03000', 2);
                    enqueueDrawCommand(startX + i*blockW + 15, cy + h*0.3, startX + i*blockW + 25, cy + h*0.3, '#a03000', 2);
                }
                break;
            case 'B': // Ladrillos HD
            case 'O':
                enqueueDrawCommand(startX, topY+1, endX, topY+1, '#ffffff', 2); // Bisel superior
                enqueueDrawCommand(startX, bottomY-1, endX, bottomY-1, '#000000', 2); // Sombra inferior
                enqueueDrawCommand(startX, cy, endX, cy, '#000000', 2); // Cemento medio
                // Cemento vertical intercalado
                for(let x = startX; x <= endX; x += blockW/2) {
                    let isStag = Math.floor((x - startX) / (blockW/2)) % 2 === 0;
                    if(isStag) enqueueDrawCommand(x, topY, x, cy, '#000000', 2);
                    else enqueueDrawCommand(x, cy, x, bottomY, '#000000', 2);
                }
                break;
            case '?': // Bloque de Moneda HD
                for(let i=0; i<len; i++) {
                    let bx = startX + i*blockW;
                    let cx = bx + blockW/2;
                    // Bordes
                    enqueueDrawCommand(bx, topY, bx+blockW, topY, '#000000', 2);
                    enqueueDrawCommand(bx, bottomY, bx+blockW, bottomY, '#000000', 2);
                    enqueueDrawCommand(bx, topY, bx, bottomY, '#000000', 2);
                    enqueueDrawCommand(bx+blockW, topY, bx+blockW, bottomY, '#000000', 2);
                    // Remaches
                    enqueueDrawCommand(bx+4, topY+4, bx+4.1, topY+4, '#c84c0c', 4, 'round');
                    enqueueDrawCommand(bx+blockW-4, topY+4, bx+blockW-4.1, topY+4, '#c84c0c', 4, 'round');
                    enqueueDrawCommand(bx+4, bottomY-4, bx+4.1, bottomY-4, '#c84c0c', 4, 'round');
                    enqueueDrawCommand(bx+blockW-4, bottomY-4, bx+blockW-4.1, bottomY-4, '#c84c0c', 4, 'round');
                    // SΓ­mbolo ?
                    enqueueDrawCommand(cx-4, cy-6, cx+4, cy-6, '#c84c0c', 3);
                    enqueueDrawCommand(cx+4, cy-6, cx+4, cy, '#c84c0c', 3);
                    enqueueDrawCommand(cx+4, cy, cx, cy, '#c84c0c', 3);
                    enqueueDrawCommand(cx, cy, cx, cy+4, '#c84c0c', 3);
                    enqueueDrawCommand(cx, cy+8, cx+0.1, cy+8, '#c84c0c', 4, 'round');
                }
                break;
            case 'H': // Bloque Duro 3D
                enqueueDrawCommand(startX, topY + 2, endX, topY + 2, '#ffffff', 4); // Bisel Blanco
                for(let i=1; i<=len; i++) {
                    let bx = startX + i*blockW;
                    enqueueDrawCommand(bx - blockW + 2, topY, bx - blockW + 2, bottomY, '#ffffff', 4);
                    enqueueDrawCommand(bx, topY, bx, bottomY, '#000000', 3); // Sombra Negra
                }
                enqueueDrawCommand(startX, bottomY, endX, bottomY, '#000000', 3);
                break;
            case 'T': // Boquilla de TuberΓ­a
                enqueueDrawCommand(startX - 4, cy, endX + 4, cy, PALETTE['T'].base, h);
                enqueueDrawCommand(startX - 4, topY, endX + 4, topY, '#000000', 4);
                enqueueDrawCommand(startX - 4, bottomY, endX + 4, bottomY, '#000000', 4);
                enqueueDrawCommand(startX - 4, topY, startX - 4, bottomY, '#000000', 4);
                enqueueDrawCommand(endX + 4, topY, endX + 4, bottomY, '#000000', 4);
                enqueueDrawCommand(startX + w*0.2, topY, startX + w*0.2, bottomY, '#88f800', w*0.15); // Brillo
                break;
            case 'P': // Cuerpo de TuberΓ­a
                enqueueDrawCommand(startX, topY, startX, bottomY, '#000000', 4);
                enqueueDrawCommand(endX, topY, endX, bottomY, '#000000', 4);
                enqueueDrawCommand(startX + w*0.2, topY, startX + w*0.2, bottomY, '#88f800', w*0.15); // Brillo
                break;
        }
    }

    function drawVectorProps(mapName, blockW, blockH) {
        if(mapName !== 'screen4') return;

        // DIBUJAR CASTILLO (Arte Vectorial Directo)
        const cx = blockW * 26; // PosiciΓ³n X
        const cy = blockH * 12.5; // Base Y (Toca el suelo)
        const cw = blockW * 4;
        const ch = blockH * 4;

        enqueueDrawCommand(cx - cw/2, cy - ch/2, cx + cw/2, cy - ch/2, '#d8a800', ch); // Cuerpo
        enqueueDrawCommand(cx - cw/2, cy - ch, cx + cw/2, cy - ch, '#000000', 3); // Borde techo
        // Almenas (Techo)
        for(let i=0; i<3; i++) {
           let ax = (cx - cw/2) + i*(cw/2.5) + blockW*0.6;
           enqueueDrawCommand(ax, cy - ch, ax, cy - ch - blockH, '#d8a800', blockW);
           enqueueDrawCommand(ax - blockW/2, cy - ch - blockH, ax + blockW/2, cy - ch - blockH, '#000000', 2);
        }
        // Puerta negra
        enqueueDrawCommand(cx, cy, cx, cy - ch/2, '#000000', blockW*1.5);
        enqueueDrawCommand(cx, cy - ch/2, cx+0.1, cy - ch/2, '#000000', blockW*1.5, 'round'); // Arco puerta

        // DIBUJAR ASTA Y BANDERA
        const fx = blockW * 14;
        const fyTop = blockH * 2;
        enqueueDrawCommand(fx, cy, fx, fyTop, '#ffffff', 6); // Asta
        enqueueDrawCommand(fx, fyTop, fx+0.1, fyTop, '#00a800', 16, 'round'); // Bola verde
        enqueueDrawCommand(fx, fyTop + 10, fx - blockW*1.5, fyTop + blockH*0.8, '#00a800', 6); // Bandera
        enqueueDrawCommand(fx - blockW*1.5, fyTop + blockH*0.8, fx, fyTop + blockH*1.6, '#00a800', 6);
        // Base de piedra
        enqueueDrawCommand(fx, cy - blockH/2, fx, cy - blockH/2, '#f8d8b0', blockH);
    }

    const LevelEngine = {
        async render(mapName, mapArray, skyColor) {
            await cleanCanvas(skyColor);
            const isUnderground = mapName === 'underground';

            const rows = mapArray.length;
            const cols = mapArray[0].length;
            const blockW = drawariaCanvas.width / cols;
            const blockH = drawariaCanvas.height / rows;

            // Renderizado en 2 Capas: 1. Fondos (Nubes/Arbustos), 2. SΓ³lidos
            [true, false].forEach(isBgPass => {
                for (let r = 0; r < rows; r++) {
                    let c = 0;
                    while (c < cols) {
                        let char = mapArray[r][c];
                        if (char === ' ') { c++; continue; }

                        let isBgChar = PALETTE[char]?.bg === true;
                        if (isBgPass !== isBgChar) { c++; continue; } // Solo dibuja la capa correspondiente

                        let len = 1;
                        while (c + len < cols && mapArray[r][c + len] === char) len++;

                        const startX = c * blockW;
                        const endX = startX + (blockW * len);
                        const cy = (r * blockH) + (blockH / 2);

                        // 1. Dibujar Base SΓ³lida
                        if (!isBgChar) {
                            enqueueDrawCommand(startX + 1, cy, endX - 1, cy, PALETTE[char].base, blockH);
                        }

                        // 2. Aplicar Texturas HD
                        drawDecorations(char, startX, endX, cy, len, blockW, blockH, isUnderground);

                        c += len;
                    }
                }
            });

            // 3. Renderizar Modelos Vectoriales (Castillo, Bandera)
            drawVectorProps(mapName, blockW, blockH);

            console.log(`βœ… Pantalla [${mapName}] HD renderizada al instante.`);
        }
    };

    /* ---------- MAPAS HD EN ASCII (32x15 Grid) ---------- */
    const MAPS = {
        screen1:[
            "                                ",
            "      WW           W            ",
            "     WWWW         WWW           ",
            "                                ",
            "                                ",
            "             ?                  ",
            "                                ",
            "          B?B?B                 ",
            "                                ",
            "                                ",
            "                      TT        ",
            "                TT    PP        ",
            "    S           PP    PP      S ",
            "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG",
            "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG"
        ],
        screen2:[
            "                                ",
            "                                ",
            "   W                WW          ",
            "  WWW              WWWW         ",
            "                                ",
            "                                ",
            "           B?B                  ",
            "                                ",
            "                      BBBBBBBB  ",
            "    TT                          ",
            "    PP            S             ",
            "    PP  TT       SSS            ",
            "    PP  PP                      ",
            "GGGGGGGGGG  GGGGGGGGGGGG   GGGGG",
            "GGGGGGGGGG  GGGGGGGGGGGG   GGGGG"
        ],
        screen3:[
            "                                ",
            "                                ",
            "             W                  ",
            "            WWW                 ",
            "             BB?B               ",
            "                                ",
            "                                ",
            "                                ",
            "                                ",
            "                    H      H    ",
            "                   HH      HH   ",
            "                  HHH      HHH  ",
            "                 HHHH      HHHH ",
            "GGGGGGGGGGGGGGGGHHHHH  GGGGHHHHH",
            "GGGGGGGGGGGGGGGGHHHHH  GGGGHHHHH"
        ],
        screen4:[
            "                                ",
            "                                ",
            "        W                       ",
            "       WWW                      ",
            "                                ",
            "                                ",
            "                                ",
            "                                ",
            "                                ",
            "         H                      ",
            "        HH                      ",
            "       HHH                      ",
            "      HHHH                      ",
            "GGGGGHHHHHGGGGGGGGGGGGGGGGGGGGGG",
            "GGGGGHHHHHGGGGGGGGGGGGGGGGGGGGGG"
        ],
        underground:[
            "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU",
            "U                              U",
            "U           ?????              U",
            "U                              U",
            "U       OOOOOO                 U",
            "U       O    O                 U",
            "U       OOOOOO                 U",
            "U                              U",
            "U                              U",
            "U                   TT         U",
            "U                   PP         U",
            "U  BBBBBBB          PP         U",
            "U  BBBBBBB          PP         U",
            "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG",
            "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG"
        ]
    };

    /* ---------- UI DRAGGABLE ---------- */
    function initUI() {
        if (document.getElementById('mario-menu')) return;

        const menu = document.createElement('div');
        menu.id = 'mario-menu';
        menu.style.cssText = `
            position: fixed; top: 120px; left: 20px; width: 340px;
            background: linear-gradient(135deg, #e52521, #b31b18);
            border: 3px solid #f8b800; border-radius: 12px;
            box-shadow: 0 10px 40px rgba(0,0,0,0.9);
            color: white; font-family: 'Segoe UI', Tahoma, sans-serif; z-index: 999999;
        `;

        menu.innerHTML = `
            <div id="mario-header" style="background: #f8b800; padding: 12px; cursor: move; border-top-left-radius: 8px; border-top-right-radius: 8px; font-weight: bold; color: black; display: flex; justify-content: space-between; font-size: 15px;">
                <span>πŸ„ Super Drawaria 1-1 (HD Remaster)</span>
                <span id="mario-close" style="cursor: pointer;">Γ—</span>
            </div>
            <div style="padding: 15px;">
                <p style="font-size: 11px; color: #ffd8a8; margin-top: 0; margin-bottom: 12px; font-weight: bold;">
                    ✨ Ahora con Texturas Vectoriales, Nubes, Arbustos y Sombras 3D instantÑneas.
                </p>

                <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 15px;">
                    <button class="mario-btn" data-map="screen1">🏞️ Pantalla 1</button>
                    <button class="mario-btn" data-map="screen2">🏞️ Pantalla 2</button>
                    <button class="mario-btn" data-map="screen3">🏞️ Pantalla 3</button>
                    <button class="mario-btn" data-map="screen4">🏁 Pantalla 4 (Castillo)</button>
                </div>

                <button class="mario-btn" data-map="underground" style="width: 100%; background: #222; border-color: #555; margin-bottom: 15px;">
                    πŸš‡ Zona SubterrΓ‘nea
                </button>

                <div style="background: rgba(0,0,0,0.4); padding: 10px; border-radius: 8px; font-size: 11px; border: 1px solid #f8b800; text-align: center;">
                    <b>βš™οΈ CONEXIΓ“N CON AVATAR PHYSICS:</b><br>
                    AΓ±ade estos colores a tus "Hitboxes" para tocar los bloques:<br>
                    <div style="margin-top: 5px; display: grid; grid-template-columns: 1fr 1fr;">
                        <span>Suelo: <b style="color:#c84c0c;">#c84c0c</b></span>
                        <span>Ladrillos: <b style="color:#cc5400;">#cc5400</b></span>
                        <span>Tubos: <b style="color:#00a800;">#00a800</b></span>
                        <span>Duros: <b style="color:#f8d8b0;">#f8d8b0</b></span>
                        <span>Moneda: <b style="color:#f8b800;">#f8b800</b></span>
                        <span>Under: <b style="color:#008888;">#008888</b></span>
                    </div>
                </div>
            </div>
        `;

        document.body.appendChild(menu);

        const style = document.createElement('style');
        style.innerHTML = `
            .mario-btn { background: #00a800; color: white; border: 2px solid #00f800; padding: 10px; border-radius: 6px; cursor: pointer; font-weight: bold; transition: 0.2s; font-size: 12px; }
            .mario-btn:hover { background: #00f800; color: black; transform: scale(1.03); box-shadow: 0 4px 10px rgba(0,248,0,0.4); }
        `;
        document.head.appendChild(style);

        document.getElementById('mario-close').onclick = () => menu.style.display = 'none';

        document.querySelectorAll('.mario-btn').forEach(btn => {
            btn.onclick = () => {
                const mapName = btn.getAttribute('data-map');
                const skyColor = mapName === 'underground' ? '#5c94fc' : '#5c94fc';
                LevelEngine.render(mapName, MAPS[mapName], skyColor);
            };
        });

        let isDragging = false, offsetX, offsetY;
        const header = document.getElementById('mario-header');
        header.onmousedown = (e) => { isDragging = true; offsetX = e.clientX - menu.offsetLeft; offsetY = e.clientY - menu.offsetTop; };
        document.onmousemove = (e) => { if (isDragging) { menu.style.left = Math.max(0, e.clientX - offsetX) + 'px'; menu.style.top = Math.max(0, e.clientY - offsetY) + 'px'; } };
        document.onmouseup = () => isDragging = false;
    }

    function init() {
        const canvas = document.getElementById('canvas');
        if (canvas) { drawariaCanvas = canvas; drawariaCtx = canvas.getContext('2d'); initUI(); }
        else { setTimeout(init, 1000); }
    }

    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
    else init();
})();