Minefun Ultimate Hub V2

Bàn phím ảo + Cài đặt liền khối, đa ngôn ngữ, tự động nhặt đồ, lưu mọi thiết lập.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

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

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Minefun Ultimate Hub V2
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  Bàn phím ảo + Cài đặt liền khối, đa ngôn ngữ, tự động nhặt đồ, lưu mọi thiết lập.
// @author       Bạn
// @match        *://*.minefun.io/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // ==========================================
    // 1. DỮ LIỆU TỪ ĐIỂN & LƯU TRỮ (LOCALSTORAGE)
    // ==========================================
    const langDict = {
        VN: {
            title: "🎮 BÀN PHÍM MINEFUN",
            btnLang: "VN ⇆ EN",
            btnSet: "⚙️ CÀI ĐẶT",
            xhTitle: "🎯 Tâm Nhắm",
            colorTitle: "🎨 Màu Sắc",
            xhEffTitle: "✨ Hiệu Ứng Tâm",
            kbEffTitle: "⌨️ Hiệu Ứng Phím",
            eff1: "Tĩnh ⏹️", eff2: "Xoay 🔄", eff3: "Nhịp tim 💓", eff4: "Cầu vồng 🌈", 
            eff5: "Lắc 📳", eff6: "Sáng 🌟", eff7: "Nháy ⚡", eff8: "Lật 🔂",
            kb1: "Sáng Viền 🔲", kb2: "Thở 💨", kb3: "Viền Hồng 🌸", 
            kb4: "Nổi Lên 👆", kb5: "V. Cầu vồng 🌈", kb6: "T. Phản 🌗"
        },
        EN: {
            title: "🎮 MINEFUN KEYBOARD",
            btnLang: "EN ⇆ VN",
            btnSet: "⚙️ SETTINGS",
            xhTitle: "🎯 Crosshairs",
            colorTitle: "🎨 Colors",
            xhEffTitle: "✨ XH Effect",
            kbEffTitle: "⌨️ KB Effect",
            eff1: "Static ⏹️", eff2: "Spin 🔄", eff3: "Pulse 💓", eff4: "Rainbow 🌈", 
            eff5: "Shake 📳", eff6: "Glow 🌟", eff7: "Blink ⚡", eff8: "Flip 🔂",
            kb1: "Glow Box 🔲", kb2: "Breathe 💨", kb3: "Pink Box 🌸", 
            kb4: "Pop-up 👆", kb5: "RGB Box 🌈", kb6: "Contrast 🌗"
        }
    };

    // Tải cấu hình đã lưu hoặc dùng mặc định
    let cfg = JSON.parse(localStorage.getItem('minefun_hub_cfg')) || {
        lang: 'VN', x: 20, y: 20, xh: '+', xhColor: '#00FFFF', xhEff: 1, kbEff: 1, setOpen: false
    };

    const saveCfg = () => { localStorage.setItem('minefun_hub_cfg', JSON.stringify(cfg)); };

    // ==========================================
    // 2. CSS TỐI ƯU NHỎ GỌN & BẮT MẮT
    // ==========================================
    const style = document.createElement('style');
    style.innerHTML = `
        @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@500;700&display=swap');
        
        .no-block-game { pointer-events: none; }
        .allow-click { pointer-events: auto; }

        /* Container Chính - Ghép cả bàn phím & cài đặt */
        #hub-container {
            position: fixed; background: rgba(15, 15, 25, 0.9);
            border: 1px solid #444; border-radius: 8px;
            padding: 8px; width: 300px; z-index: 10000;
            user-select: none; font-family: 'Roboto', sans-serif;
            box-shadow: 0 4px 15px rgba(0,0,0,0.8);
            cursor: grab; /* Kéo được ở mọi nơi */
        }
        #hub-container:active { cursor: grabbing; }

        /* Header & Nút Bấm */
        #hub-header {
            display: flex; justify-content: space-between; align-items: center;
            border-bottom: 1px solid #333; padding-bottom: 5px; margin-bottom: 8px;
        }
        .hub-title { color: #fff; font-size: 10px; font-weight: bold; pointer-events: none; }
        .head-btn {
            background: #222; border: 1px solid #555; color: #fff;
            font-size: 9px; padding: 3px 6px; border-radius: 3px; cursor: pointer;
        }
        .head-btn:hover { background: #444; }

        /* Bàn Phím */
        .vk-row { display: flex; justify-content: center; gap: 3px; margin-bottom: 3px; }
        .vk-key {
            background: linear-gradient(135deg, #1e1e2f, #3a3a5c);
            color: #fff; font-size: 9px; font-weight: bold;
            width: 22px; height: 22px;
            display: flex; justify-content: center; align-items: center;
            border-radius: 4px; border: 1px solid #111; cursor: default;
            transition: transform 0.05s, background 0.1s;
        }
        .vk-key.wide { width: 42px; }
        .vk-key.active { background: #fff !important; color: #000 !important; transform: scale(0.9); box-shadow: 0 0 8px #fff; }

        /* Cài đặt (Ẩn/Hiện mượt mà) */
        #settings-area {
            display: ${cfg.setOpen ? 'block' : 'none'};
            margin-top: 10px; border-top: 1px dashed #555; padding-top: 5px;
            max-height: 250px; overflow-y: auto; cursor: default;
        }
        /* Tùy chỉnh thanh cuộn cho gọn */
        #settings-area::-webkit-scrollbar { width: 4px; }
        #settings-area::-webkit-scrollbar-thumb { background: #666; border-radius: 2px; }

        .set-group { margin-bottom: 8px; }
        .set-title { font-size: 9px; color: #0ff; margin-bottom: 4px; font-weight: bold; }
        .grid-xh { display: grid; grid-template-columns: repeat(10, 1fr); gap: 2px; }
        .grid-color { display: grid; grid-template-columns: repeat(10, 1fr); gap: 2px; }
        .grid-eff { display: grid; grid-template-columns: repeat(3, 1fr); gap: 3px; }
        
        .grid-btn {
            background: #2a2a35; border: 1px solid #444; color: #ccc;
            font-size: 9px; padding: 4px 0; border-radius: 3px; cursor: pointer; text-align: center;
        }
        .grid-btn:hover { background: #555; color: #fff; }
        .grid-btn.active-btn { background: #0ff; color: #000; border-color: #fff; font-weight: bold; }
        
        /* Tâm Nhắm Game */
        #custom-crosshair {
            position: fixed; top: 50%; left: 50%;
            transform: translate(-50%, -50%);
            font-size: 24px; pointer-events: none; z-index: 9999;
            text-shadow: 0 0 2px #000;
        }

        /* Hiệu ứng Tâm Nhắm & Bàn Phím (Giữ nguyên logic cũ) */
        .xh-eff-1 { } 
        .xh-eff-2 { animation: xhSpin 2s linear infinite; }
        .xh-eff-3 { animation: xhPulse 1s infinite; }
        .xh-eff-4 { animation: xhRainbow 3s linear infinite; }
        .xh-eff-5 { animation: xhShake 0.3s infinite; }
        .xh-eff-6 { text-shadow: 0 0 10px currentColor; }
        .xh-eff-7 { animation: xhBlink 0.5s step-end infinite; }
        .xh-eff-8 { animation: xhFlip 2s infinite; }

        .kb-eff-1 { box-shadow: 0 0 8px #0ff; }
        .kb-eff-2 { animation: kbBreathe 2s infinite; }
        .kb-eff-3 { border-color: #ff69b4; box-shadow: 0 0 5px #ff69b4; }
        .kb-eff-4 .vk-key { box-shadow: 0 2px 0 #0ff; }
        .kb-eff-4 .vk-key:active, .kb-eff-4 .vk-key.active { transform: translateY(2px); box-shadow: none; }
        .kb-eff-5 { animation: kbRainbowBorder 3s linear infinite; }
        .kb-eff-6 { filter: contrast(1.3); }

        @keyframes xhSpin { 100% { transform: translate(-50%, -50%) rotate(360deg); } }
        @keyframes xhPulse { 0%, 100% { transform: translate(-50%, -50%) scale(1); } 50% { transform: translate(-50%, -50%) scale(1.5); } }
        @keyframes xhRainbow { 100% { filter: hue-rotate(360deg); } }
        @keyframes xhShake { 0%, 100% { margin-left: 0; } 25% { margin-left: -2px; } 75% { margin-left: 2px; } }
        @keyframes xhBlink { 50% { opacity: 0; } }
        @keyframes xhFlip { 50% { transform: translate(-50%, -50%) rotateY(180deg); } }
        @keyframes kbBreathe { 0%, 100% { box-shadow: 0 0 2px #fff; } 50% { box-shadow: 0 0 15px #0ff; } }
        @keyframes kbRainbowBorder { 100% { filter: hue-rotate(360deg); } }
    `;
    document.head.appendChild(style);

    // ==========================================
    // 3. TẠO HTML GIAO DIỆN CHÍNH
    // ==========================================
    const keysRow1 = ['1','2','3','4','5','6','7','8','9'];
    const keysRow2 = ['W','Q','R','T','P','A','S','D','X','C','M','Shift'];
    const keysRow3 = ['Enter','Bksp','!','@','#','$','%','^','&','*','(',')','_','+','{','}','|',':','"','<','>','?'];
    
    const crosshairs = ['+','x','o','O','•','✛','✜','✚','✙','⌖','⯐','⯏','⯎','⯌','⯍','⯨','⯩','⯪','⯫','⭖','⭗','⭘','⭙','⭚','⭛','⭜','⭝','❖','⊕','🖕'];
    const colors = ['#FF0000','#00FF00','#0000FF','#FFFF00','#00FFFF','#FF00FF','#FFFFFF','#000000','#FF8C00','#8A2BE2','#00FF7F','#FF1493','#1E90FF','#FFD700','#32CD32','#8B008B','#FF4500','#00CED1','#9400D3','#ADFF2F'];

    const renderRow = (arr) => `<div class="vk-row">` + arr.map(k => `<div class="vk-key allow-click ${(k.length>1)?'wide':''}" data-key="${(k==='Bksp'?'BACKSPACE':k).toUpperCase()}">${k}</div>`).join('') + `</div>`;

    document.body.insertAdjacentHTML('beforeend', `
        <div id="hub-container" class="allow-click" style="left:${cfg.x}px; top:${cfg.y}px;">
            <div id="hub-header">
                <div class="hub-title" id="t-title">🎮 BÀN PHÍM MINEFUN</div>
                <div>
                    <button class="head-btn" id="btn-lang">VN ⇆ EN</button>
                    <button class="head-btn" id="btn-toggle-set">⚙️ CÀI ĐẶT</button>
                </div>
            </div>
            
            <div id="keyboard-area">
                ${renderRow(keysRow1)}
                ${renderRow(keysRow2)}
                ${renderRow(keysRow3)}
            </div>

            <div id="settings-area">
                <div class="set-group">
                    <div class="set-title" id="t-xh">🎯 Tâm Nhắm</div>
                    <div class="grid-xh">
                        ${crosshairs.map(c => `<div class="grid-btn allow-click xh-btn" data-val="${c}">${c}</div>`).join('')}
                    </div>
                </div>
                <div class="set-group">
                    <div class="set-title" id="t-color">🎨 Màu Sắc</div>
                    <div class="grid-color">
                        ${colors.map(c => `<div class="grid-btn allow-click color-btn" style="background:${c}; height:12px;" data-val="${c}"></div>`).join('')}
                    </div>
                </div>
                <div class="set-group">
                    <div class="set-title" id="t-xh-eff">✨ Hiệu Ứng Tâm</div>
                    <div class="grid-eff" id="xh-eff-list"></div>
                </div>
                <div class="set-group">
                    <div class="set-title" id="t-kb-eff">⌨️ Hiệu Ứng Phím</div>
                    <div class="grid-eff" id="kb-eff-list"></div>
                </div>
            </div>
        </div>
        <div id="custom-crosshair">${cfg.xh}</div>
    `);

    const hub = document.getElementById('hub-container');
    const xhEl = document.getElementById('custom-crosshair');
    const setArea = document.getElementById('settings-area');

    // ==========================================
    // 4. KÉO THẢ TỰ DO (Kéo ở mọi nơi trên bảng)
    // ==========================================
    let isDragging = false, offX, offY;
    hub.addEventListener('mousedown', (e) => {
        // Không kéo khi ấn vào các nút/chữ có tính tương tác
        if (e.target.closest('.vk-key') || e.target.closest('.head-btn') || e.target.closest('.grid-btn') || e.target.closest('#settings-area')) return;
        isDragging = true;
        offX = e.clientX - hub.offsetLeft;
        offY = e.clientY - hub.offsetTop;
    });
    document.addEventListener('mousemove', (e) => {
        if (!isDragging) return;
        hub.style.left = (e.clientX - offX) + 'px';
        hub.style.top = (e.clientY - offY) + 'px';
    });
    document.addEventListener('mouseup', () => {
        if (isDragging) {
            isDragging = false;
            cfg.x = parseInt(hub.style.left); cfg.y = parseInt(hub.style.top);
            saveCfg();
        }
    });

    // ==========================================
    // 5. NGÔN NGỮ & RENDER NÚT HIỆU ỨNG (CÓ EMOJI)
    // ==========================================
    const renderLang = () => {
        const t = langDict[cfg.lang];
        document.getElementById('t-title').innerText = t.title;
        document.getElementById('btn-lang').innerText = t.btnLang;
        document.getElementById('btn-toggle-set').innerText = t.btnSet;
        document.getElementById('t-xh').innerText = t.xhTitle;
        document.getElementById('t-color').innerText = t.colorTitle;
        document.getElementById('t-xh-eff').innerText = t.xhEffTitle;
        document.getElementById('t-kb-eff').innerText = t.kbEffTitle;

        document.getElementById('xh-eff-list').innerHTML = [1,2,3,4,5,6,7,8].map(i => 
            `<div class="grid-btn allow-click xhe-btn ${cfg.xhEff===i?'active-btn':''}" data-val="${i}">${t['eff'+i]}</div>`
        ).join('');

        document.getElementById('kb-eff-list').innerHTML = [1,2,3,4,5,6].map(i => 
            `<div class="grid-btn allow-click kbe-btn ${cfg.kbEff===i?'active-btn':''}" data-val="${i}">${t['kb'+i]}</div>`
        ).join('');
        
        bindEffectEvents(); // Gắn lại sự kiện click cho các nút vừa tạo
    };

    document.getElementById('btn-lang').addEventListener('click', () => {
        cfg.lang = cfg.lang === 'VN' ? 'EN' : 'VN';
        saveCfg(); renderLang();
    });

    document.getElementById('btn-toggle-set').addEventListener('click', () => {
        cfg.setOpen = !cfg.setOpen;
        setArea.style.display = cfg.setOpen ? 'block' : 'none';
        saveCfg();
    });

    // ==========================================
    // 6. ÁP DỤNG CÀI ĐẶT & SỰ KIỆN CLICK SETTINGS
    // ==========================================
    const applyAllCfg = () => {
        xhEl.innerText = cfg.xh;
        xhEl.style.color = cfg.xhColor;
        xhEl.className = `xh-eff-${cfg.xhEff}`;
        hub.className = `allow-click kb-eff-${cfg.kbEff}`;
    };

    // Chọn Tâm Nhắm
    document.querySelectorAll('.xh-btn').forEach(btn => {
        btn.addEventListener('click', (e) => {
            cfg.xh = e.target.getAttribute('data-val');
            saveCfg(); applyAllCfg();
        });
    });

    // Chọn Màu
    document.querySelectorAll('.color-btn').forEach(btn => {
        btn.addEventListener('click', (e) => {
            cfg.xhColor = e.target.getAttribute('data-val');
            saveCfg(); applyAllCfg();
        });
    });

    // Chọn Hiệu ứng (Dùng function gắn sự kiện vì HTML được render lại khi đổi ngôn ngữ)
    function bindEffectEvents() {
        document.querySelectorAll('.xhe-btn').forEach(btn => {
            btn.addEventListener('click', (e) => {
                cfg.xhEff = parseInt(e.target.getAttribute('data-val'));
                saveCfg(); applyAllCfg(); renderLang(); // Cập nhật nút màu sáng (active)
            });
        });
        document.querySelectorAll('.kbe-btn').forEach(btn => {
            btn.addEventListener('click', (e) => {
                cfg.kbEff = parseInt(e.target.getAttribute('data-val'));
                saveCfg(); applyAllCfg(); renderLang();
            });
        });
    }

    // Khởi chạy ngay khi load
    renderLang();
    applyAllCfg();

    // ==========================================
    // 7. NHÁY TRẮNG BÀN PHÍM VÀ AUTO LOOT
    // ==========================================
    const allVkKeys = document.querySelectorAll('.vk-key');
    document.addEventListener('keydown', (e) => {
        let keyName = e.key.toUpperCase();
        allVkKeys.forEach(vk => {
            if (vk.getAttribute('data-key') === keyName || (e.code === 'Space' && vk.getAttribute('data-key') === 'SPACE')) {
                vk.classList.add('active');
            }
        });
    });
    document.addEventListener('keyup', (e) => {
        let keyName = e.key.toUpperCase();
        allVkKeys.forEach(vk => {
            if (vk.getAttribute('data-key') === keyName) {
                vk.classList.remove('active');
            }
        });
    });

    // Auto Loot 
    document.addEventListener('click', (e) => {
        let t = e.target;
        if (t.className && typeof t.className === 'string' && (t.className.toLowerCase().includes('item') || t.className.toLowerCase().includes('loot'))) {
            let bp = document.querySelector('.backpack, #backpack, [class*="inventory"]');
            if (bp) {
                bp.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, cancelable: true, view: window }));
                t.style.display = 'none';
            }
        }
    });

})();