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.
// ==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';
}
}
});
})();