Drawaria Interactive Tools Suit💻

A suite of interactive tools for Drawaria.online with a draggable floating menu.

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 Interactive Tools Suit💻
// @namespace    http://tampermonkey.net/
// @version      1.1.2
// @description  A suite of interactive tools for Drawaria.online with a draggable floating menu.
// @author       YouTubeDrawaria
// @match        https://drawaria.online/*
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-idle
// @license     MIT
// @icon        https://www.google.com/s2/favicons?sz=64&domain=drawaria.online
// ==/UserScript==

(function() {
    'use strict';

    // --- Core Variables and State ---
    let _drawariaCanvas = null;
    let _drawariaCtx = null;
    let _isReady = false;
    let _animationFrameId = null; // Usar requestAnimationFrame para un renderizado más suave
    let _drawariaSocket = null; // Para enviar comandos al servidor

    let _isPhoneActive = false;
    let _currentPhoneState = 'home';
    let _lastPhoneButtons = [];
    let _phoneCalcInput = "";

    let _isGameConsoleActive = false;
    let _lastGameConsoleButtons = [];

    let _isComputerActive = false;
    let _computerOutput = [];
    let _lastComputerButtons = [];

    let _isTabletActive = false;
    let _currentTabletState = 'home';
    let _lastTabletButtons = [];

    let _isShoppingMallActive = false;
    let _currentShoppingMallState = 'shop';
    let _lastShoppingMallButtons = [];
    const _shoppingMallProducts = [
        { id: "apple", name: "a p p l e", icon: "a", price: 5, color: "#df3535" },
        { id: "ball", name: "b a l l", icon: "b", price: 7, color: "#2277f3" },
        { id: "coin", name: "c o i n", icon: "3", price: 3, color: "#ddbe37" },
        { id: "lamp", name: "l a m p", icon: "l", price: 11, color: "#eedd66" }
    ];

    let _isHotelActive = false;
    let _currentHotelState = 'lobby';
    let _lastHotelButtons = [];

    let _isTechCenterActive = false;
    let _currentTechCenterState = 'main';
    let _lastTechCenterButtons = [];
    const _techCenterProducts = [
        { id: "chip", name: "c h i p", icon: "c", price: 10, color: "#92e8a1" },
        { id: "battery", name: "b a t t", icon: "b", price: 8, color: "#d9dd27" },
        { id: "robo_arm", name: "r o b o - b r a z o", icon: "r", price: 25, color: "#808080" },
        { id: "laser", name: "l a s e r", icon: "l", price: 18, color: "#ff0000" }
    ];

    let _userCoins = 20;
    let _userInventory = [];
    const _ui = {};

    // --- Patrones de Letras y Números (Ajustados para consistencia) ---
    const _letterPaths = {
        a: [[10, 40], [20, 0], [30, 40], [25, 20], [15, 20]],
        b: [[0, 0], [0, 40], [15, 40], [20, 35], [20, 25], [15, 20], [0, 20], [15, 20], [20, 15], [20, 5], [15, 0], [0, 0]],
        c: [[30, 10], [20, 0], [10, 0], [0, 10], [0, 30], [10, 40], [20, 40], [30, 30]],
        d: [[0, 0], [0, 40], [10, 40], [30, 20], [10, 0], [0, 0]],
        e: [[30, 0], [0, 0], [0, 20], [20, 20], [0, 20], [0, 40], [30, 40]],
        f: [[20, 0], [0, 0], [0, 20], [15, 20], [0, 20], [0, 40]],
        g: [[30, 10], [20, 0], [10, 0], [0, 10], [0, 30], [10, 40], [20, 40], [30, 30], [20, 20]],
        h: [[0, 0], [0, 40], [0, 20], [20, 20], [20, 0], [20, 40]],
        i: [[10, 0], [10, 40]],
        j: [[20, 0], [20, 40], [10, 40], [0, 30]],
        k: [[0, 0], [0, 40], [0, 20], [20, 0], [0, 20], [20, 40]],
        l: [[0, 0], [0, 40], [20, 40]],
        m: [[0, 40], [0, 0], [10, 20], [20, 0], [20, 40]],
        n: [[0, 40], [0, 0], [20, 40], [20, 0]],
        o: [[10, 0], [20, 0], [30, 10], [30, 30], [20, 40], [10, 40], [0, 30], [0, 10], [10, 0]],
        p: [[0, 40], [0, 0], [10, 0], [20, 10], [10, 20], [0, 20]],
        q: [[10, 0], [20, 0], [30, 10], [30, 30], [20, 40], [10, 40], [0, 30], [0, 10], [10, 0], [20, 20], [30, 40]],
        r: [[0, 40], [0, 0], [10, 0], [20, 10], [10, 20], [0, 20], [20, 40]],
        s: [[20, 0], [10, 0], [0, 10], [20, 20], [30, 30], [20, 40], [10, 40], [0, 30]],
        t: [[10, 0], [10, 40], null, [1, 0], [20, 0]],
        u: [[0, 0], [0, 30], [10, 40], [20, 40], [30, 30], [30, 0]],
        v: [[0, 0], [15, 40], [30, 0]],
        w: [[0, 0], [0, 40], [10, 20], [20, 40], [30, 0]],
        x: [[0, 0], [30, 40], [15, 20], [0, 40], [30, 0]],
        y: [[0, 0], [15, 20], [30, 0], [15, 20], [15, 40]],
        z: [[0, 0], [30, 0], [0, 40], [30, 40]],
        '.': [[7.5, 35], [9, 36]],
        '!': [[15, 0], [15, 30], null, [15, 35], [15, 40]],
        '@': [[20, 10], [10, 0], [0, 10], [0, 30], [10, 40], [20, 40], [30, 30], [30, 20], [15, 20]],
        '#': [[5, 0], [5, 40], null, [25, 0], [25, 40], null, [0, 10], [30, 10], null, [0, 30], [30, 30]],
        '$': [[20, 0], [10, 0], [0, 10], [10, 20], [20, 20], [30, 30], [20, 40], [10, 40], [15, 0], [15, 40]],
        '%': [[0, 30], [30, 0], null, [5, 10], [10, 5], null, [20, 35], [25, 30]],
        '^': [[0, 20], [15, 0], [30, 20]],
        '?': [[0, 10], [10, 0], [20, 0], [30, 10], [15, 20], [15, 30], null, [15, 35], [15, 40]],
        '+': [[15, 0], [15, 40], null, [0, 20], [30, 20]],
        '-': [[0, 20], [30, 20]],
        '*': [[15, 0], [15, 40], null, [0, 10], [30, 30], null, [0, 30], [30, 10]],
        '/': [[0, 40], [30, 0]],
        '(': [[15, 0], [0, 0], [0, 40], [15, 40]],
        ')': [[15, 0], [30, 0], [30, 40], [15, 40]],
        ':': [[15, 10], [16, 11], null, [15, 30], [16, 31]],
        '_': [[0, 40], [30, 40]],
        '=': [[0, 15], [30, 15], null, [0, 25], [30, 25]],
        '<': [[30, 10], [0, 20], [30, 30]],
        '>': [[0, 10], [30, 20], [0, 30]],
        ',': [[10, 30], [10, 35], [5, 40]],
        "'": [[15, 0], [20, 5], [15, 10]]
    };

    const _numberPaths = {
        0: [[10, 0], [20, 0], [30, 10], [30, 30], [20, 40], [10, 40], [0, 30], [0, 10], [10, 0]],
        1: [[15, 0], [15, 40], null, [15, 0], [10, 10], null, [10, 40], [20, 40]],
        2: [[0, 10], [10, 0], [20, 0], [30, 10], [0, 40], [30, 40]],
        3: [[0, 10], [10, 0], [20, 0], [30, 10], [20, 20], [30, 30], [20, 40], [10, 40], [0, 30]],
        4: [[20, 0], [20, 40], null, [0, 20], [25, 20], null, [0, 20], [20, 0]],
        5: [[30, 0], [0, 0], [0, 20], [20, 20], [30, 30], [20, 40], [10, 40], [0, 30]],
        6: [[30, 10], [20, 0], [10, 0], [0, 10], [0, 30], [10, 40], [20, 40], [30, 30], [20, 20], [10, 20], [0, 20], [0, 10]],
        7: [[0, 0], [30, 0], [15, 40]],
        8: [[15, 0], [25, 10], [15, 20], [5, 10], [15, 0], null, [15, 20], [25, 30], [15, 40], [5, 30], [15, 20]],
        9: [[5, 35], [15, 40], [25, 30], [30, 10], [20, 0], [10, 0], [0, 10], [5, 20], [15, 20], [25, 20], [27.5, 20]]
    };

    // --- Utility Functions (Adaptadas de la tienda) ---

    function getGameSocket() {
        if (_drawariaSocket) return _drawariaSocket;

        if (window.socket) {
            _drawariaSocket = window.socket;
        } else if (window.WebSocket && window.WebSocket.prototype) {
            const origSend = WebSocket.prototype.send;
            WebSocket.prototype.send = function(...args) {
                if (this.url && this.url.includes('drawaria') && !_drawariaSocket) {
                    _drawariaSocket = this;
                }
                return origSend.apply(this, args);
            };
        }
        return _drawariaSocket;
    }

    function saveState() {
        GM_setValue('userCoins', _userCoins);
        GM_setValue('userInventory', JSON.stringify(_userInventory));
    }

    function loadState() {
        _userCoins = GM_getValue('userCoins', 20);
        _userInventory = JSON.parse(GM_getValue('userInventory', '[]'));
    }

    function createDraggableMenu() {
        GM_addStyle(`
            #drawaria-tools-menu {
                position: fixed;
                top: 20px;
                left: 20px;
                width: 200px;
                background: #2b2b2b;
                border: 1px solid #555;
                border-radius: 8px;
                box-shadow: 0 4px 8px rgba(0,0,0,0.5);
                z-index: 9999;
                font-family: Arial, sans-serif;
                color: #f0f0f0;
                resize: both;
                overflow: auto;
            }
            #drawaria-tools-menu-header {
                cursor: move;
                background: #3c3c3c;
                padding: 10px;
                border-top-left-radius: 8px;
                border-top-right-radius: 8px;
                text-align: center;
                font-weight: bold;
                border-bottom: 1px solid #555;
            }
            #drawaria-tools-menu-content {
                padding: 10px;
            }
            .tool-button {
                width: 100%;
                padding: 8px;
                margin-bottom: 5px;
                background: #444;
                color: #fff;
                border: 1px solid #555;
                border-radius: 4px;
                cursor: pointer;
            }
            .tool-button:hover {
                background: #555;
            }
            .tool-button.active {
                background: #007bff;
                border-color: #0056b3;
            }
            .module-status-indicator {
                margin-top: 10px;
                padding: 5px;
                border-radius: 4px;
                text-align: center;
            }
            .module-status-connected { background: #28a745; }
            .module-status-disconnected { background: #dc3545; }
            .module-status-stopped { background: #ffc107; }
        `);

        const menu = document.createElement('div');
        menu.id = 'drawaria-tools-menu';
        document.body.appendChild(menu);

        const header = document.createElement('div');
        header.id = 'drawaria-tools-menu-header';
        header.textContent = 'Drawaria Interactive Tools Suit';
        menu.appendChild(header);

        const content = document.createElement('div');
        content.id = 'drawaria-tools-menu-content';
        menu.appendChild(content);

        let isDragging = false;
        let startX, startY;

        header.addEventListener('mousedown', (e) => {
            isDragging = true;
            startX = e.clientX - menu.offsetLeft;
            startY = e.clientY - menu.offsetTop;
            document.addEventListener('mousemove', onMouseMove);
            document.addEventListener('mouseup', onMouseUp);
        });

        const onMouseMove = (e) => {
            if (isDragging) {
                menu.style.left = `${e.clientX - startX}px`;
                menu.style.top = `${e.clientY - startY}px`;
            }
        };

        const onMouseUp = () => {
            isDragging = false;
            document.removeEventListener('mousemove', onMouseMove);
            document.removeEventListener('mouseup', onMouseUp);
        };

        _ui.togglePhoneButton = createButton('<i class="fas fa-mobile-alt"></i> Teléfono', () => _toggleModule('phone'));
        _ui.toggleGameConsoleButton = createButton('<i class="fas fa-gamepad"></i> Consola', () => _toggleModule('game_console'));
        _ui.toggleComputerButton = createButton('<i class="fas fa-laptop"></i> Computadora', () => _toggleModule('computer'));
        _ui.toggleTabletButton = createButton('<i class="fas fa-tablet-alt"></i> Tablet', () => _toggleModule('tablet'));
        _ui.toggleShoppingMallButton = createButton('<i class="fas fa-store"></i> Centro Comercial', () => _toggleModule('shopping_mall'));
        _ui.toggleHotelButton = createButton('<i class="fas fa-hotel"></i> Hotel', () => _toggleModule('hotel'));
        _ui.toggleTechCenterButton = createButton('<i class="fas fa-microchip"></i> Centro de Tecnología', () => _toggleModule('tech_center'));
        _ui.resetDataButton = createButton('<i class="fas fa-redo-alt"></i> Resetear Datos', () => _resetAllData());
        _ui.stopAllButton = createButton('<i class="fas fa-stop-circle"></i> Detener Todo', () => _stopAllModulesAndRendering());
        _ui.statusLabel = document.createElement('div');
        _ui.statusLabel.className = 'module-status-indicator';
        _ui.statusText = document.createElement('span');
        _ui.statusLabel.appendChild(_ui.statusText);

        content.appendChild(_ui.togglePhoneButton);
        content.appendChild(_ui.toggleGameConsoleButton);
        content.appendChild(_ui.toggleComputerButton);
        content.appendChild(_ui.toggleTabletButton);
        content.appendChild(_ui.toggleShoppingMallButton);
        content.appendChild(_ui.toggleHotelButton);
        content.appendChild(_ui.toggleTechCenterButton);
        content.appendChild(document.createElement('hr'));
        content.appendChild(_ui.resetDataButton);
        content.appendChild(_ui.stopAllButton);
        content.appendChild(_ui.statusLabel);
    }

    function createButton(html, onClick) {
        const btn = document.createElement('button');
        btn.className = 'tool-button';
        btn.innerHTML = html;
        btn.addEventListener('click', onClick);
        return btn;
    }

    function _waitUntilReady() {
        return new Promise(resolve => {
            const check = () => {
                _drawariaCanvas = document.getElementById('canvas');
                if (_drawariaCanvas) {
                    _drawariaCtx = _drawariaCanvas.getContext('2d');
                }
                getGameSocket(); // Asegura que _drawariaSocket se inicialice
                if (_drawariaCanvas && _drawariaCtx && _drawariaSocket) {
                    resolve();
                } else {
                    setTimeout(check, 250);
                }
            };
            check();
        });
    }

    function _getMouseCanvasCoords(e) {
        if (!_drawariaCanvas) return { x: 0, y: 0 };
        const rect = _drawariaCanvas.getBoundingClientRect();
        return {
            x: (e.clientX - rect.left) * (_drawariaCanvas.width / rect.width),
            y: (e.clientY - rect.top) * (_drawariaCanvas.height / rect.height)
        };
    }

    // --- Adaptado de la tienda: Funciones de Dibujo y Envío de Comandos ---
    function drawLineServerLocal(x1, y1, x2, y2, color = '#222', thickness = 3) {
        if (!_drawariaSocket || !_drawariaCanvas) return;
        const nx1 = (x1 / _drawariaCanvas.width).toFixed(4), ny1 = (y1 / _drawariaCanvas.height).toFixed(4),
              nx2 = (x2 / _drawariaCanvas.width).toFixed(4), ny2 = (y2 / _drawariaCanvas.height).toFixed(4);
        const cmd = `42["drawcmd",0,[${nx1},${ny1},${nx2},${ny2},false,${-Math.abs(thickness)},"${color}",0,0,{}]]`;
        try {
            _drawariaSocket.send(cmd);
        } catch (e) {
            console.error("Error sending draw command:", e);
        }

        _drawariaCtx.save();
        _drawariaCtx.strokeStyle = color;
        _drawariaCtx.lineWidth = thickness;
        _drawariaCtx.lineCap = 'round';
        _drawariaCtx.beginPath();
        _drawariaCtx.moveTo(x1, y1);
        _drawariaCtx.lineTo(x2, y2);
        _drawariaCtx.stroke();
        _drawariaCtx.restore();
    }

    function drawFilledRect(x, y, w, h, color = '#eee') {
        if (!_drawariaCtx) return;
        _drawariaCtx.save();
        _drawariaCtx.fillStyle = color;
        _drawariaCtx.fillRect(x, y, w, h);
        _drawariaCtx.restore();
    }

    function drawRectServerLocal(x, y, w, h, color = '#222', thickness = 3) {
        if (!_drawariaCtx) return;
        _drawariaCtx.save();
        _drawariaCtx.strokeStyle = color;
        _drawariaCtx.lineWidth = thickness;
        _drawariaCtx.strokeRect(x, y, w, h);
        _drawariaCtx.restore();
    }

     function drawLine(x1, y1, x2, y2, color, thickness) {
         drawLineServerLocal(x1, y1, x2, y2, color, thickness);
     }

    function drawLetterPathLocal(path, startX, startY, fontSize, color, thickness) {
        if (!_drawariaCtx) return;
        const scale = fontSize / 40;

        _drawariaCtx.save();
        _drawariaCtx.strokeStyle = color;
        _drawariaCtx.lineWidth = thickness;
        _drawariaCtx.lineCap = 'round';
        _drawariaCtx.lineJoin = 'round';
        _drawariaCtx.beginPath();

        let penLifted = true;
        for (let i = 0; i < path.length; i++) {
            const segment = path[i];
            if (segment === null) {
                penLifted = true;
                continue;
            }
            const [px, py] = segment;
            const currentX = startX + px * scale;
            const currentY = startY + py * scale;
            if (penLifted) {
                _drawariaCtx.moveTo(currentX, currentY);
                penLifted = false;
            } else {
                _drawariaCtx.lineTo(currentX, currentY);
            }
        }
        _drawariaCtx.stroke();
        _drawariaCtx.restore();
    }

    function _drawLocalText(str, x, y, color, thickness = 2, fontSize = 18) {
        let cx = x;
        for (const char of str) {
            const path = _letterPaths[char.toLowerCase()] || _numberPaths[char] || _letterPaths[' '];
            if (path) {
                drawLetterPathLocal(path, cx, y, fontSize, color, thickness);
            }
            cx += fontSize * 0.6;
        }
    }

    // --- Main Logic (Converted from Class Methods) ---

    function _onStartup() {
        createDraggableMenu();
        loadState();
        _waitUntilReady().then(() => {
            _isReady = true;
            _startRenderLoop();
            document.getElementById('canvas').addEventListener('click', _handleCanvasClick);
        });
    }

    // Función de bucle de renderizado usando requestAnimationFrame
    function _renderLoop() {
        if (!_isReady || !_drawariaCtx) {
            const socketStatus = getGameSocket() ? 'connected' : 'disconnected';
            _ui.statusLabel.className = `module-status-indicator module-status-${socketStatus}`;
            _ui.statusText.textContent = socketStatus.charAt(0).toUpperCase() + socketStatus.slice(1);
            _animationFrameId = requestAnimationFrame(_renderLoop); // Continuar solicitando fotogramas incluso si no se renderizan módulos
            return;
        }

        const anyModuleActive = _isPhoneActive || _isGameConsoleActive || _isComputerActive ||
            _isTabletActive || _isShoppingMallActive || _isHotelActive ||
            _isTechCenterActive;

        if (anyModuleActive) {
            // Limpiar solo si un módulo está activo para dibujar la interfaz del módulo
            _drawariaCtx.clearRect(0, 0, _drawariaCanvas.width, _drawariaCanvas.height);

            if (_isPhoneActive) _renderPhone();
            else if (_isGameConsoleActive) _renderGameConsole();
            else if (_isComputerActive) _renderComputer();
            else if (_isTabletActive) _renderTablet();
            else if (_isShoppingMallActive) _renderShoppingMall();
            else if (_isHotelActive) _renderHotel();
            else if (_isTechCenterActive) _renderTechCenter();
        } else {
            // Si ningún módulo está activo, NO limpiar el canvas.
            // Esto permite que el juego principal se dibuje sobre el canvas.
            // Nuestro script solo interviene cuando un módulo está activo.
        }

        const socketStatus = getGameSocket() ? 'connected' : 'disconnected';
        _ui.statusLabel.className = `module-status-indicator module-status-${socketStatus}`;
        _ui.statusText.textContent = socketStatus.charAt(0).toUpperCase() + socketStatus.slice(1);

        _animationFrameId = requestAnimationFrame(_renderLoop); // Programar el siguiente fotograma
    }

    function _startRenderLoop() {
        if (_animationFrameId) {
            cancelAnimationFrame(_animationFrameId); // Cancelar el anterior si existe
        }
        _animationFrameId = requestAnimationFrame(_renderLoop); // Iniciar el bucle
    }

    function _handleCanvasClick(e) {
        if (!_isReady || !_drawariaCtx) return;
        const { x: cx, y: cy } = _getMouseCanvasCoords(e);

        // Delegar el manejo del clic al módulo activo
        if (_isPhoneActive) _handlePhoneClick(cx, cy);
        else if (_isGameConsoleActive) _handleGameConsoleClick(cx, cy);
        else if (_isComputerActive) _handleComputerClick(cx, cy);
        else if (_isTabletActive) _handleTabletClick(cx, cy);
        else if (_isShoppingMallActive) _handleShoppingMallClick(cx, cy);
        else if (_isHotelActive) _handleHotelClick(cx, cy);
        else if (_isTechCenterActive) _handleTechCenterClick(cx, cy);
    }

    function _toggleModule(moduleName) {
        // Desactivar todos los módulos primero
        _isPhoneActive = false;
        _isGameConsoleActive = false;
        _isComputerActive = false;
        _isTabletActive = false;
        _isShoppingMallActive = false;
        _isHotelActive = false;
        _isTechCenterActive = false;

        // Remover la clase 'active' de todos los botones del menú
        document.querySelectorAll('.tool-button').forEach(btn => btn.classList.remove('active'));

        let message = `Módulo '${moduleName.replace('_', ' ')}' desactivado.`;

        switch (moduleName) {
            case 'phone':
                _isPhoneActive = true;
                _ui.togglePhoneButton.classList.add('active');
                _currentPhoneState = 'home';
                message = "Módulo 'Teléfono' activado.";
                break;
            case 'game_console':
                _isGameConsoleActive = true;
                _ui.toggleGameConsoleButton.classList.add('active');
                message = "Módulo 'Consola' activado.";
                break;
            case 'computer':
                _isComputerActive = true;
                _ui.toggleComputerButton.classList.add('active');
                message = "Módulo 'Computadora' activado.";
                break;
            case 'tablet':
                _isTabletActive = true;
                _ui.toggleTabletButton.classList.add('active');
                _currentTabletState = 'home';
                message = "Módulo 'Tablet' activado.";
                break;
            case 'shopping_mall':
                _isShoppingMallActive = true;
                _ui.toggleShoppingMallButton.classList.add('active');
                _currentShoppingMallState = 'shop';
                message = "Módulo 'Centro Comercial' activado.";
                break;
            case 'hotel':
                _isHotelActive = true;
                _ui.toggleHotelButton.classList.add('active');
                _currentHotelState = 'lobby';
                message = "Módulo 'Hotel' activado.";
                break;
            case 'tech_center':
                _isTechCenterActive = true;
                _ui.toggleTechCenterButton.classList.add('active');
                _currentTechCenterState = 'main';
                message = "Módulo 'Centro de Tecnología' activado.";
                break;
        }

        // Si el canvas está disponible, lo limpiamos solo si activamos un módulo,
        // para asegurar que el estado anterior no interfiera.
        if (_drawariaCtx && _drawariaCanvas && anyModuleActive) {
            _drawariaCtx.clearRect(0, 0, _drawariaCanvas.width, _drawariaCanvas.height);
        }
        _startRenderLoop(); // Reiniciar bucle para aplicar cambios
    }

    function _resetAllData() {
        _userCoins = 20;
        _userInventory = [];
        _phoneCalcInput = "";
        _currentPhoneState = 'home';
        _currentTabletState = 'home';
        _currentShoppingMallState = 'shop';
        _currentHotelState = 'lobby';
        _currentTechCenterState = 'main';
        _computerOutput = [];
        saveState();
        _startRenderLoop(); // Re-renderizar para mostrar el estado reseteado
        alert("Todos los datos han sido reseteados.");
    }

    function _stopAllModulesAndRendering() {
        _isPhoneActive = false;
        _isGameConsoleActive = false;
        _isComputerActive = false;
        _isTabletActive = false;
        _isShoppingMallActive = false;
        _isHotelActive = false;
        _isTechCenterActive = false;

        document.querySelectorAll('.tool-button').forEach(btn => btn.classList.remove('active'));

        if (_animationFrameId) {
            cancelAnimationFrame(_animationFrameId);
            _animationFrameId = null;
        }

        // Al detener todo, debemos asegurarnos de que el canvas se limpie para mostrar el juego de nuevo.
        if (_drawariaCtx && _drawariaCanvas) {
            _drawariaCtx.clearRect(0, 0, _drawariaCanvas.width, _drawariaCanvas.height);
        }

        const socketStatus = getGameSocket() ? 'connected' : 'disconnected';
        _ui.statusLabel.className = `module-status-indicator module-status-stopped`;
        _ui.statusText.textContent = `Detenido (${socketStatus.charAt(0).toUpperCase() + socketStatus.slice(1)})`;
    }

    // --- Helper Drawing Functions ---

    function _drawLocalLine(x1, y1, x2, y2, color = '#222', thickness = 3) {
        if (!_drawariaCtx) return;
        _drawariaCtx.save();
        _drawariaCtx.strokeStyle = color;
        _drawariaCtx.lineWidth = thickness;
        _drawariaCtx.lineCap = 'round';
        _drawariaCtx.beginPath();
        _drawariaCtx.moveTo(x1, y1);
        _drawariaCtx.lineTo(x2, y2);
        _drawariaCtx.stroke();
        _drawariaCtx.restore();
    }

     // Función genérica para dibujar texto usando los patrones definidos
     function _drawTextGeneric(str, x, y, color, thickness = 2, fontSize = 18, paths) {
         let cx = x;
         for (const char of str) {
             const path = paths[char.toLowerCase()] || paths[' '];
             if (path) {
                 drawLetterPathLocal(path, cx, y, fontSize, color, thickness);
             }
             cx += fontSize * 0.6;
         }
     }

     // Sobrescribir _drawLocalText para usar la función genérica
     function _drawLocalText(str, x, y, color, thickness = 2, fontSize = 18) {
         _drawTextGeneric(str, x, y, color, thickness, fontSize, _letterPaths);
     }

    function _drawLocalFilledRect(x, y, w, h, color = '#eee') {
        if (!_drawariaCtx) return;
        _drawariaCtx.save();
        _drawariaCtx.fillStyle = color;
        _drawariaCtx.fillRect(x, y, w, h);
        _drawariaCtx.restore();
    }

    function _drawLocalRectOutline(x, y, w, h, color = '#222', thickness = 3) {
        if (!_drawariaCtx) return;
        _drawariaCtx.save();
        _drawariaCtx.strokeStyle = color;
        _drawariaCtx.lineWidth = thickness;
        _drawariaCtx.strokeRect(x, y, w, h);
        _drawariaCtx.restore();
    }

    function _drawActionButton(x, y, w, h, text, action, buttonArray, bgColor = '#DDD', textColor = '#222', fontSize = 17, textThickness = 2, borderColor = '#222', borderWidth = 2, extraData = {}) {
        _drawLocalFilledRect(x, y, w, h, bgColor);
        _drawLocalRectOutline(x, y, w, h, borderColor, borderWidth);
        const textWidthApprox = text.length * fontSize * 0.6;
        _drawLocalText(text, x + (w - textWidthApprox) / 2, y + (h - fontSize) / 2 + 3, textColor, textThickness, fontSize);
        buttonArray.push({ x, y, w, h, action, ...extraData });
    }

     function _drawAppButton(x, y, size, action, bgColor, borderColor, iconChar, iconColor, labelText, labelColor, buttonArray) {
         _drawLocalFilledRect(x, y, size, size, bgColor);
         _drawLocalRectOutline(x, y, size, size, borderColor, 2);
         _drawLocalText(iconChar, x + size / 2 - 10, y + 8, iconColor, 2, 20);
         const labelTextWidthApprox = labelText.length * 12 * 0.6;
         _drawLocalText(labelText, x + size / 2 - (labelTextWidthApprox / 2), y + size + 5, labelColor, 1.5, 12);
         buttonArray.push({ x: x, y: y, w: size, h: size, action: action });
     }


    // --- Module Rendering and Click Handlers ---

    function _handlePhoneClick(cx, cy) {
        for (const btn of _lastPhoneButtons) {
            if (cx >= btn.x && cx <= btn.x + btn.w && cy >= btn.y && cy <= btn.y + btn.h) {
                switch (btn.action) {
                    case 'home': _currentPhoneState = 'home'; break;
                    case 'open_football': _currentPhoneState = 'football'; break;
                    case 'open_notes': _currentPhoneState = 'notes'; break;
                    case 'open_calc': _currentPhoneState = 'calc'; break;
                    case 'open_clock': _currentPhoneState = 'clock'; break;
                    case 'open_gallery': _currentPhoneState = 'gallery'; break;
                    case 'calcpress':
                        _phoneCalcInput += btn.val;
                        break;
                    case 'equals':
                        try {
                            let safeInput = _phoneCalcInput.replace(/[^0-9+\-*/.()]/g, '');
                            _phoneCalcInput = String(eval(safeInput));
                        } catch {
                            _phoneCalcInput = "ERR";
                        }
                        break;
                    case 'ce':
                        _phoneCalcInput = "";
                        break;
                }
                _renderPhone();
                return;
            }
        }
    }

    function _renderPhone() {
        if (!_drawariaCanvas) return;
        const phoneW = 220, phoneH = 420;
        const { x, y, w, h } = { x: _drawariaCanvas.width - phoneW - 32, y: _drawariaCanvas.height - phoneH - 32, w: phoneW, h: phoneH };
        _lastPhoneButtons = [];

        _drawLocalFilledRect(x, y, w, h, '#222');
        _drawLocalRectOutline(x, y, w, h, '#999', 4);
        _drawLocalFilledRect(x + 10, y + 10, w - 20, h - 20, '#000');
        _drawLocalFilledRect(x + w / 2 - 30, y + 20, 60, 10, '#444');
        _drawLocalFilledRect(x + w / 2 - 15, y + h - 30, 30, 15, '#444');

        switch (_currentPhoneState) {
            case 'home': _renderPhoneHome(x + 15, y + 45, w - 30, h - 80); break;
            case 'football': _renderPhoneFootballApp(x + 15, y + 45, w - 30, h - 80); break;
            case 'notes': _renderPhoneNotesApp(x + 15, y + 45, w - 30, h - 80); break;
            case 'calc': _renderPhoneCalcApp(x + 15, y + 45, w - 30, h - 80); break;
            case 'clock': _renderPhoneClockApp(x + 15, y + 45, w - 30, h - 80); break;
            case 'gallery': _renderPhoneGalleryApp(x + 15, y + 45, w - 30, h - 80); break;
        }

        if (_currentPhoneState !== 'home') {
            const btnX = x + 15 + (w - 30) / 2 - 40, btnY = y + 45 + (h - 80) - 40, btnW = 80, btnH = 30;
            _drawActionButton(btnX, btnY, btnW, btnH, "v o l v e r", 'home', _lastPhoneButtons, '#DDD', '#555', 14);
        }
    }

    function _renderPhoneHome(x, y, w, h) {
        _drawLocalText("a n d r o i d", x + 10, y + 10, '#17A', 3, 17);
        _drawAppButton(x + 10, y + 40, 45, 'open_football', '#FAFAFF', '#222', 'f', '#173', 'f u t b o l', '#222', _lastPhoneButtons);
        _drawAppButton(x + 70, y + 40, 45, 'open_notes', '#FFFDE9', '#222', 'n', '#962', 'n o t e s', '#222', _lastPhoneButtons);
        _drawAppButton(x + 130, y + 40, 45, 'open_calc', '#EAEEFF', '#222', 'c', '#246', 'c a l c', '#222', _lastPhoneButtons);
        _drawAppButton(x + 10, y + 120, 45, 'open_clock', '#F6FFEA', '#222', 'r', '#184', 'r e l o j', '#222', _lastPhoneButtons);
        _drawAppButton(x + 70, y + 120, 45, 'open_gallery', '#FAEEFF', '#222', 'g', '#71a', 'g a l e r', '#222', _lastPhoneButtons);
    }

    function _renderPhoneFootballApp(x, y, w, h) {
        _drawLocalText("f u t b o l", x + 20, y + 10, '#173', 3, 18);
        _drawLocalFilledRect(x + 20, y + 50, w - 40, h - 100, '#8BC34A');
        _drawLocalRectOutline(x + 20, y + 50, w - 40, h - 100, '#222', 2);
        _drawLocalLine(x + w / 2, y + 50, x + w / 2, y + h - 50, '#FFF', 1);
        _drawLocalText("b o l a", x + w / 2 - 25, y + h / 2 + 10, '#FFF', 2, 18);
    }

    function _renderPhoneNotesApp(x, y, w, h) {
        _drawLocalText("n o t a s", x + 20, y + 10, '#962', 3, 18);
        _drawLocalFilledRect(x + 10, y + 40, w - 20, h - 80, '#fffbe0');
        _drawLocalRectOutline(x + 10, y + 40, w - 20, h - 80, '#555', 2);
        for (let i = 0; i < 5; i++) {
            _drawLocalLine(x + 15, y + 50 + i * 20, x + w - 15, y + 50 + i * 20, '#99F', 1);
        }
        _drawLocalText("t o m a  n o t a !", x + 20, y + 60, "#333", 2, 15);
    }

    function _renderPhoneCalcApp(x, y, w, h) {
        _drawLocalText("c a l c", x + 20, y + 10, '#246', 3, 18);
        _drawLocalFilledRect(x + 10, y + 40, w - 20, 40, '#f4f7fd');
        _drawLocalRectOutline(x + 10, y + 40, w - 20, 40, '#222', 2);
        _drawLocalText(_phoneCalcInput || "0", x + 15, y + 50, '#246', 2, 18);
        const bw = 40, bh = 30, pad = 5;
        const layout = [
            ['7', '8', '9', '+'],
            ['4', '5', '6', '-'],
            ['1', '2', '3', '*'],
            ['ce', '0', '=', '/']
        ];
        let startY = y + 90;
        for (let row = 0; row < layout.length; row++) {
            let startX = x + 15;
            for (let col = 0; col < layout[row].length; col++) {
                const char = layout[row][col];
                const btnAction = (char === 'ce' || char === '=') ? char : 'calcpress';
                const extra = (btnAction === 'calcpress') ? { val: char } : {};
                _drawActionButton(startX + col * (bw + pad), startY + row * (bh + pad), bw, bh, char, btnAction, _lastPhoneButtons, '#EEE', '#222', 15, 2, '#999', 1, extra);
            }
        }
    }

    function _renderPhoneClockApp(x, y, w, h) {
        _drawLocalText("r e l o j", x + 20, y + 10, '#184', 3, 18);
        const now = new Date();
        const timeStr = `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`;
        const dateStr = `${String(now.getDate()).padStart(2, '0')}/${String(now.getMonth() + 1).padStart(2, '0')}/${now.getFullYear()}`;
        _drawLocalText(timeStr, x + 20, y + 70, '#222', 3, 25);
        _drawLocalText(dateStr, x + 20, y + 110, '#555', 2, 15);
    }

    function _renderPhoneGalleryApp(x, y, w, h) {
        _drawLocalText("g a l e r", x + 20, y + 10, '#71a', 3, 18);
        _drawLocalFilledRect(x + 10, y + 40, w - 20, h - 80, '#DDD');
        _drawLocalRectOutline(x + 10, y + 40, w - 20, h - 80, '#555', 2);
        _drawLocalText("n o   f o t o s", x + 20, y + 50, '#555', 2, 15);
    }

    function _handleGameConsoleClick(cx, cy) {
        for (const btn of _lastGameConsoleButtons) {
            if (cx >= btn.x && cx <= btn.x + btn.w && cy >= btn.y && cy <= btn.y + btn.h) {
                switch (btn.action) {
                    case 'dpad_up': _drawLocalText("A R R I B A", cx, cy - 20, '#0F0', 2, 12); break;
                    case 'dpad_down': _drawLocalText("A B A J O", cx, cy + 20, '#0F0', 2, 12); break;
                    case 'dpad_left': _drawLocalText("I Z Q", cx - 20, cy + 5, '#0F0', 2, 12); break;
                    case 'dpad_right': _drawLocalText("D E R", cx + 20, cy + 5, '#0F0', 2, 12); break;
                    case 'btn_a': _drawLocalText("A C T I O N", cx, cy, '#0F0', 2, 12); break;
                    case 'btn_b': _drawLocalText("C A N C E L", cx, cy, '#0F0', 2, 12); break;
                }
                _renderGameConsole();
                return;
            }
        }
    }

    function _renderGameConsole() {
        if (!_drawariaCanvas) return;
        const consoleW = 400, consoleH = 200;
        const { x, y, w, h } = { x: _drawariaCanvas.width / 2 - consoleW / 2, y: _drawariaCanvas.height / 2 - consoleH / 2, w: consoleW, h: consoleH };
        _lastGameConsoleButtons = [];

        _drawLocalFilledRect(x, y, w, h, '#444');
        _drawLocalRectOutline(x, y, w, h, '#999', 4);
        _drawLocalFilledRect(x + 20, y + 20, w - 40, 100, '#000');
        _drawLocalRectOutline(x + 20, y + 20, w - 40, 100, '#0F0', 2);

        _drawLocalText("P O N G", x + w / 2 - 50, y + 50, '#0F0', 3, 20);
        _drawLocalText("j u g a r", x + w / 2 - 60, y + 80, '#0F0', 2, 15);
        _drawLocalText("c o n s o l a", x + w / 2 - 80, y + 140, '#CCC', 2, 18);

        const btnSize = 30, btnPad = 10;
        _drawActionButton(x + 30, y + 140, btnSize, btnSize, '▲', 'dpad_up', _lastGameConsoleButtons);
        _drawActionButton(x + 30, y + 140 + btnSize + btnPad, btnSize, btnSize, '▼', 'dpad_down', _lastGameConsoleButtons);
        _drawActionButton(x + 30 - btnSize - btnPad, y + 140 + btnSize + btnPad / 2, btnSize, btnSize, '◀', 'dpad_left', _lastGameConsoleButtons);
        _drawActionButton(x + 30 + btnSize + btnPad, y + 140 + btnSize + btnPad / 2, btnSize, btnSize, '▶', 'dpad_right', _lastGameConsoleButtons);
        _drawActionButton(x + w - 30 - btnSize, y + 140 + btnSize / 2, btnSize, btnSize, 'A', 'btn_a', _lastGameConsoleButtons);
        _drawActionButton(x + w - 30 - btnSize - 20, y + 140 + btnSize / 2 + 10, btnSize, btnSize, 'B', 'btn_b', _lastGameConsoleButtons);
    }

    function _handleComputerClick(cx, cy) {
        for (const btn of _lastComputerButtons) {
            if (cx >= btn.x && cx <= btn.x + btn.w && cy >= btn.y && cy <= btn.y + btn.h) {
                switch (btn.action) {
                    case 'power':
                        _computerOutput.push("P O W E R   O N");
                        break;
                    case 'code':
                        _computerOutput.push("P R O G R A M M I N G");
                        _computerOutput.push("C O D E   L I N E");
                        break;
                    case 'internet':
                        _computerOutput.push("I N T E R N E T");
                        _computerOutput.push("S E A R C H I N G...");
                        break;
                    case 'clear':
                        _computerOutput = [];
                        break;
                }
                if (_computerOutput.length > 5) {
                    _computerOutput.shift();
                }
                _renderComputer();
                return;
            }
        }
    }

    function _renderComputer() {
        if (!_drawariaCanvas) return;
        const compW = 450, compH = 300;
        const { x, y, w, h } = { x: 10, y: 10, w: compW, h: compH };
        _lastComputerButtons = [];

        _drawLocalFilledRect(x, y, w, h, '#333');
        _drawLocalRectOutline(x, y, w, h, '#777', 4);
        _drawLocalFilledRect(x + 20, y + 20, w - 40, h - 60, '#000');
        _drawLocalRectOutline(x + 20, y + 20, w - 40, h - 60, '#0F0', 2);

        _drawLocalText("C O M P U T A D O R A", x + w / 2 - 100, y + 10, '#EEE', 3, 18);
        let outputY = y + 30;
        _computerOutput.forEach(line => {
            _drawLocalText(line, x + 30, outputY, '#0F0', 2, 14);
            outputY += 20;
        });

        _drawActionButton(x + 20, y + h - 30, 80, 20, 'O N', 'power', _lastComputerButtons, '#28A745', '#FFF', 14);
        _drawActionButton(x + 110, y + h - 30, 80, 20, 'C O D E', 'code', _lastComputerButtons, '#007BFF', '#FFF', 14);
        _drawActionButton(x + 200, y + h - 30, 80, 20, 'I N T E R N E T', 'internet', _lastComputerButtons, '#FFC107', '#FFF', 14);
        _drawActionButton(x + w - 100, y + h - 30, 80, 20, 'C L E A R', 'clear', _lastComputerButtons, '#DC3545', '#FFF', 14);
    }

    function _handleTabletClick(cx, cy) {
        for (const btn of _lastTabletButtons) {
            if (cx >= btn.x && cx <= btn.x + btn.w && cy >= btn.y && cy <= btn.y + btn.h) {
                switch (btn.action) {
                    case 'home': _currentTabletState = 'home'; break;
                    case 'open_youtube': _currentTabletState = 'youtube'; break;
                    case 'open_maps': _currentTabletState = 'maps'; break;
                    case 'open_paint': _currentTabletState = 'paint'; break;
                }
                _renderTablet();
                return;
            }
        }
    }

    function _renderTablet() {
        if (!_drawariaCanvas) return;
        const tabletW = 500, tabletH = 350;
        const { x, y, w, h } = { x: _drawariaCanvas.width / 2 - tabletW / 2, y: _drawariaCanvas.height / 2 - tabletH / 2, w: tabletW, h: tabletH };
        _lastTabletButtons = [];

        _drawLocalFilledRect(x, y, w, h, '#222');
        _drawLocalRectOutline(x, y, w, h, '#999', 4);
        _drawLocalFilledRect(x + 10, y + 10, w - 20, h - 20, '#fff');
        _drawLocalFilledRect(x + w / 2 - 20, y + h - 25, 40, 10, '#444');

        switch (_currentTabletState) {
            case 'home': _renderTabletHome(x + 10, y + 10, w - 20, h - 20); break;
            case 'youtube': _renderTabletYouTubeApp(x + 10, y + 10, w - 20, h - 20); break;
            case 'maps': _renderTabletMapsApp(x + 10, y + 10, w - 20, h - 20); break;
            case 'paint': _renderTabletPaintApp(x + 10, y + 10, w - 20, h - 20); break;
        }

        if (_currentTabletState !== 'home') {
            const btnX = x + 10 + (w - 20) / 2 - 40, btnY = y + 10 + (h - 20) - 40, btnW = 80, btnH = 30;
            _drawActionButton(btnX, btnY, btnW, btnH, "v o l v e r", 'home', _lastTabletButtons, '#DDD', '#555', 14);
        }
    }

    function _renderTabletHome(x, y, w, h) {
        _drawLocalText("T A B L E T", x + 10, y + 10, '#369', 3, 18);
        _drawAppButton(x + 20, y + 50, 60, 'open_youtube', '#F00', '#222', 'p', '#FFF', 'y o u t u b e', '#222', _lastTabletButtons);
        _drawAppButton(x + 100, y + 50, 60, 'open_maps', '#28A745', '#222', 'm', '#FFF', 'm a p s', '#222', _lastTabletButtons);
        _drawAppButton(x + 180, y + 50, 60, 'open_paint', '#81D4FA', '#222', 'p', '#FFF', 'p i n t a r', '#222', _lastTabletButtons);
    }

    function _renderTabletYouTubeApp(x, y, w, h) {
        _drawLocalText("y o u t u b e", x + 10, y + 10, '#F00', 3, 18);
        _drawLocalFilledRect(x + 20, y + 50, w - 40, h - 100, '#000');
        _drawLocalRectOutline(x + 20, y + 50, w - 40, h - 100, '#F00', 2);
        _drawLocalText("v i d e o", x + w / 2 - 50, y + h / 2 - 10, '#FFF', 2, 20);
        _drawLocalText("►", x + w / 2 - 10, y + h / 2 - 20, '#FFF', 3, 25);
    }

    function _renderTabletMapsApp(x, y, w, h) {
        _drawLocalText("m a p s", x + 10, y + 10, '#28A745', 3, 18);
        _drawLocalFilledRect(x + 20, y + 50, w - 40, h - 100, '#8BC34A');
        _drawLocalRectOutline(x + 20, y + 50, w - 40, h - 100, '#222', 2);
        _drawLocalText("m a p a", x + w / 2 - 40, y + h / 2 - 10, '#222', 2, 20);
        _drawLocalText("📍", x + w / 2 - 10, y + h / 2 - 20, '#F00', 3, 25);
    }

    function _renderTabletPaintApp(x, y, w, h) {
        _drawLocalText("p i n t a r", x + 10, y + 10, '#81D4FA', 3, 18);
        _drawLocalFilledRect(x + 20, y + 50, w - 40, h - 100, '#FFF');
        _drawLocalRectOutline(x + 20, y + 50, w - 40, h - 100, '#222', 2);
        _drawLocalText("l a p i z", x + 20, y + 60, '#222', 2, 15);
        _drawLocalText("🎨", x + 20, y + 75, '#222', 3, 25);
    }

    function _handleShoppingMallClick(cx, cy) {
        for (const btn of _lastShoppingMallButtons) {
            if (cx >= btn.x && cx <= btn.x + btn.w && cy >= btn.y && cy <= btn.y + btn.h) {
                switch (btn.action) {
                    case 'shop':
                        _currentShoppingMallState = 'shop';
                        break;
                    case 'inventory':
                        _currentShoppingMallState = 'inventory';
                        break;
                    case 'buy':
                        const prod = _shoppingMallProducts.find(p => p.id === btn.id);
                        if (prod && _userCoins >= prod.price) {
                            _userCoins -= prod.price;
                            _userInventory.push(prod.id);
                            saveState();
                        } else if (prod) {
                            alert("¡No tienes suficientes coins!");
                        }
                        break;
                }
                _renderShoppingMall();
                return;
            }
        }
    }

    function _renderShoppingMall() {
        if (!_drawariaCanvas) return;
        const shopW = 500, shopH = 300;
        const { x, y, w, h } = { x: _drawariaCanvas.width / 2 - shopW / 2, y: _drawariaCanvas.height - shopH - 32, w: shopW, h: shopH };
        _lastShoppingMallButtons = [];

        _drawLocalFilledRect(x, y, w, h, '#f4f4f4');
        _drawLocalRectOutline(x, y, w, h, '#222', 4);
        _drawLocalText("c e n t r o   c o m e r c i a l", x + 10, y + 10, '#222', 3, 18);
        _drawLocalText(`c o i n s: ${_userCoins}`, x + 10, y + 30, '#555', 2, 15);
        _drawActionButton(x + 10, y + 45, 100, 30, 't i e n d a', 'shop', _lastShoppingMallButtons);
        _drawActionButton(x + 120, y + 45, 100, 30, 'i n v e n t', 'inventory', _lastShoppingMallButtons);

        switch (_currentShoppingMallState) {
            case 'shop': _renderShopItems(x, y, w, h); break;
            case 'inventory': _renderInventory(x, y, w, h); break;
        }
    }

    function _renderShopItems(x, y, w, h) {
        const itemX = x + 20, itemY = y + 80, itemW = 100, itemH = 60, pad = 10;
        let currentY = itemY;
        _shoppingMallProducts.forEach(item => {
            _drawLocalFilledRect(itemX, currentY, itemW, itemH, '#EEE');
            _drawLocalRectOutline(itemX, currentY, itemW, itemH, '#555', 2);
            _drawLocalText(item.name, itemX + 5, currentY + 5, '#222', 2, 14);
            _drawLocalText(`$${item.price}`, itemX + 5, currentY + 25, '#444', 2, 12);
            const canAfford = _userCoins >= item.price;
            _drawActionButton(itemX + 60, currentY + 30, 35, 20, 'c o m p', 'buy', _lastShoppingMallButtons, canAfford ? '#4a90e2' : '#999', '#FFF', 12, 1, '#222', 1, { id: item.id });
            currentY += itemH + pad;
        });
    }

    function _renderInventory(x, y, w, h) {
        _drawLocalText("i n v e n t a r i o", x + 20, y + 80, '#222', 3, 16);
        let invY = y + 100;
        if (_userInventory.length === 0) {
            _drawLocalText("v a c i o", x + 30, invY, '#555', 2, 14);
        } else {
            const counts = _userInventory.reduce((acc, curr) => {
                acc[curr] = (acc[curr] || 0) + 1;
                return acc;
            }, {});
            for (const itemId in counts) {
                 const product = _shoppingMallProducts.find(p => p.id === itemId);
                 if (product) {
                    _drawLocalText(`${product.name} x ${counts[itemId]}`, x + 30, invY, '#222', 2, 14);
                    invY += 20;
                 }
            }
        }
    }

    function _handleHotelClick(cx, cy) {
        for (const btn of _lastHotelButtons) {
            if (cx >= btn.x && cx <= btn.x + btn.w && cy >= btn.y && cy <= btn.y + btn.h) {
                switch (btn.action) {
                    case 'lobby':
                        _currentHotelState = 'lobby';
                        break;
                    case 'rent':
                        if (_userCoins >= 10) {
                            _userCoins -= 10;
                            _currentHotelState = 'room';
                            saveState();
                        } else {
                            alert("¡No tienes suficientes coins para alquilar!");
                        }
                        break;
                    case 'check_out':
                        _currentHotelState = 'lobby';
                        break;
                }
                _renderHotel();
                return;
            }
        }
    }

    function _renderHotel() {
        if (!_drawariaCanvas) return;
        const hotelW = 400, hotelH = 250;
        const { x, y, w, h } = { x: 30, y: 30, w: hotelW, h: hotelH };
        _lastHotelButtons = [];

        _drawLocalFilledRect(x, y, w, h, '#E0F7FA');
        _drawLocalRectOutline(x, y, w, h, '#222', 4);
        _drawLocalText("h o t e l", x + 10, y + 10, '#369', 3, 18);
        _drawLocalText(`c o i n s: ${_userCoins}`, x + 10, y + 30, '#555', 2, 15);

        switch (_currentHotelState) {
            case 'lobby': _renderHotelLobby(x, y, w, h); break;
            case 'room': _renderHotelRoom(x, y, w, h); break;
        }
    }

    function _renderHotelLobby(x, y, w, h) {
        _drawLocalText("b i e n v e n i d o", x + w / 2 - 60, y + 60, '#369', 3, 18);
        _drawLocalText("r e n t a   u n a   h a b i t", x + 20, y + 100, '#555', 2, 14);
        _drawLocalText("c o s t o: 10 c", x + 20, y + 120, '#555', 2, 14);
        const canRent = _userCoins >= 10;
        _drawActionButton(x + 20, y + h - 50, 150, 30, "a l q u i l a r", 'rent', _lastHotelButtons, canRent ? '#4a90e2' : '#999', '#FFF', 14, 1, '#222', 1);
    }

    function _renderHotelRoom(x, y, w, h) {
        _drawLocalText("t u   h a b i t a c i o n", x + w / 2 - 80, y + 60, '#369', 3, 18);
        _drawLocalText("h o r a   d e   r e l a j", x + 20, y + 100, '#555', 2, 14);
        _drawActionButton(x + 20, y + h - 50, 150, 30, "d e s a l o j a r", 'check_out', _lastHotelButtons, '#DC3545', '#FFF', 14, 1, '#222', 1);
    }

    function _handleTechCenterClick(cx, cy) {
        for (const btn of _lastTechCenterButtons) {
            if (cx >= btn.x && cx <= btn.x + btn.w && cy >= btn.y && cy <= btn.y + btn.h) {
                switch (btn.action) {
                    case 'main':
                        _currentTechCenterState = 'main';
                        break;
                    case 'buy_tech':
                        const prod = _techCenterProducts.find(p => p.id === btn.id);
                        if (prod && _userCoins >= prod.price) {
                            _userCoins -= prod.price;
                            _userInventory.push(prod.id);
                            saveState();
                        } else if (prod) {
                             alert("¡No tienes suficientes coins!");
                        }
                        break;
                }
                _renderTechCenter();
                return;
            }
        }
    }

    function _renderTechCenter() {
        if (!_drawariaCanvas) return;
        const techW = 500, techH = 300;
        const { x, y, w, h } = { x: _drawariaCanvas.width / 2 - techW / 2, y: _drawariaCanvas.height / 2 - techH / 2, w: techW, h: techH };
        _lastTechCenterButtons = [];

        _drawLocalFilledRect(x, y, w, h, '#212121');
        _drawLocalRectOutline(x, y, w, h, '#9E9E9E', 4);
        _drawLocalText("t e c n o l o g i a", x + 10, y + 10, '#E0F7FA', 3, 18);
        _drawLocalText(`c o i n s: ${_userCoins}`, x + 10, y + 30, '#BDBDBD', 2, 15);
        _drawActionButton(x + 10, y + 45, 100, 30, 'm e n u', 'main', _lastTechCenterButtons);

        switch (_currentTechCenterState) {
            case 'main': _renderTechItems(x, y, w, h); break;
        }
    }

    function _renderTechItems(x, y, w, h) {
        const itemX = x + 20, itemY = y + 80, itemW = 100, itemH = 60, pad = 10;
        let currentY = itemY;
        _techCenterProducts.forEach(item => {
            _drawLocalFilledRect(itemX, currentY, itemW, itemH, '#424242');
            _drawLocalRectOutline(itemX, currentY, itemW, itemH, '#757575', 2);
            _drawLocalText(item.name, itemX + 5, currentY + 5, '#E0F7FA', 2, 14);
            _drawLocalText(`$${item.price}`, itemX + 5, currentY + 25, '#BDBDBD', 2, 12);
            const canAfford = _userCoins >= item.price;
            _drawActionButton(itemX + 60, currentY + 30, 35, 20, 'c o m p', 'buy_tech', _lastTechCenterButtons, canAfford ? '#4a90e2' : '#999', '#FFF', 12, 1, '#222', 1, { id: item.id });
            currentY += itemH + pad;
        });
    }

    // --- Inicialización ---
    _onStartup();

})();