Kobitz VOXHACK Menu

Aimbot, triggerbot, chams, no-recoil, High Visibility NameTags (No Ores) with sound

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name        Kobitz VOXHACK Menu
// @namespace   http://tampermonkey.net/
// @match       https://voxiom.io/*
// @run-at      document-start
// @grant       none
// @version     3.0
// @author      Log & Modified
// @description Aimbot, triggerbot, chams, no-recoil, High Visibility NameTags (No Ores) with sound
// @license     GPL
// @require     https://cdn.jsdelivr.net/npm/[email protected]/dist/lil-gui.umd.min.js
// @require     https://unpkg.com/[email protected]/build/three.min.js
// @icon        https://www.google.com/s2/favicons?sz=64&domain=voxiom.io
// ==/UserScript==
if (!document.getElementById('side-player-list')) {
    const listUI = document.createElement('div');
listUI.id = 'side-player-list';
    listUI.style = `
        position: fixed; top: 230px; left: 0px; width: 280px;
        background: rgba(0, 0, 0, 0.85);
        border-left: 5px solid #00ff00;
        color: white;
        font-family: 'Segoe UI', sans-serif;
        font-size: 16px;
        z-index: 10001; padding: 15px; border-radius: 0 10px 10px 0;
        pointer-events: none;
        box-shadow: 8px 8px 20px rgba(0,0,0,0.6);
    `;

    // Thêm style cho mục được chọn bằng phím tắt và làm rõ số mét
    const styleSheet = document.createElement("style");
    styleSheet.innerText = `
        .player-row {
            display: flex; align-items: center; margin-bottom: 8px; transition: all 0.2s; padding: 2px 5px; border-radius: 4px;
        }
        .player-row.selected {
            background: rgba(255, 255, 0, 0.3) !important;
            border: 1px solid yellow;
        }
        .dist-text {
            margin-left: auto; color: #00ffff !important; font-size: 13px; font-weight: bold; opacity: 1 !important; text-shadow: 1px 1px 2px #000;
        }
    `;
    document.head.appendChild(styleSheet);
    listUI.innerHTML = `
    <div style="color:#00ff00; font-weight:bold; margin-bottom:10px; border-bottom:1px solid #444; font-size:12px; letter-spacing:1px; text-transform: uppercase;">
        📡 Player Radar (<span id="radar-count" style="color: #00ff00;">0</span>)
    </div>
    <div id="list-content"></div>
`;
    document.body.appendChild(listUI);
}// --- TẠO BẢNG THÔNG BÁO CÓ HIỆU ỨNG TRƯỢT ---
const statusNotify = document.createElement('div');
statusNotify.id = 'status-notify';
statusNotify.style = `
    position: fixed;
    bottom: 50px;
    left: -300px; /* Bắt đầu ở ngoài màn hình bên trái */
    padding: 10px 20px;
    background: rgba(0, 0, 0, 0.9);
    color: #00ff00;
    border-left: 5px solid #00ff00;
    font-family: 'Segoe UI', sans-serif;
    font-size: 13px;
    font-weight: bold;
    z-index: 10005;
    pointer-events: none;
    border-radius: 0 4px 4px 0; /* Bo góc bên phải */
    box-shadow: 5px 0 15px rgba(0,0,0,0.5);
    text-transform: uppercase;
    transition: left 0.3s ease-out; /* Hiệu ứng trượt trong 0.3 giây */
`;
document.body.appendChild(statusNotify);

let statusTimer;
function notifyStatus(label, value) {
    statusNotify.innerHTML = `${label}: <span style="color:white">${value}</span>`;

    // Hiệu ứng: Chạy từ trái vào (sát lề 0px)
    statusNotify.style.left = '0px';

    clearTimeout(statusTimer);
    statusTimer = setTimeout(() => {
        // Hiệu ứng: Chạy ngược ra ngoài màn hình
        statusNotify.style.left = '-300px';
    }, 2000);
}
// CHÈN VÀO ĐÂY:
window.handlePlayerAction = function(name) {
    console.log("Đang tương tác với người chơi: " + name);
    // Ví dụ: Thông báo tên người chơi vừa nhấn
    alert("Bạn đã chọn: " + name);
};
// Khởi tạo Map toàn cục
window.playerMap = new Map();
window.lastPositions = new Map(); // Cực kỳ quan trọng: Không có cái này máy không nhớ được vị trí cũ để tính hướng di chuyển
window.ignoredPlayers = new Set(); // Danh sách lưu tên người chơi bị né
// Hàm tạo tiếng "Ping" thanh mảnh khi nhấn
window.playClickSound = function() {
    try {
        const oscillator = audioCtx.createOscillator();
        const gainNode = audioCtx.createGain();
        oscillator.connect(gainNode);
        gainNode.connect(audioCtx.destination);

        oscillator.type = 'sine';
        oscillator.frequency.setValueAtTime(1500, audioCtx.currentTime); // Tần số cao nghe rất thanh
        gainNode.gain.setValueAtTime(0.1, audioCtx.currentTime);
        gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.2);

        oscillator.start();
        oscillator.stop(audioCtx.currentTime + 0.2);
    } catch (e) { console.log("Audio error"); }
};

window.handlePlayerAction = function(name) {
    window.playClickSound(); // Kêu Ping!
    if (window.ignoredPlayers.has(name)) {
        window.ignoredPlayers.delete(name);
    } else {
        window.ignoredPlayers.add(name);
    }
};

// Hàm tạo tiếng "tích" nhỏ khi nhấn
window.playClickSound = function() {
    try {
        if (!window.sharedAudioCtx) window.sharedAudioCtx = new (window.AudioContext || window.webkitAudioContext)();
const audioCtx = window.sharedAudioCtx;
        const oscillator = audioCtx.createOscillator();
        const gainNode = audioCtx.createGain();
        oscillator.connect(gainNode);
        gainNode.connect(audioCtx.destination);
        oscillator.type = 'sine';
        oscillator.frequency.setValueAtTime(1200, audioCtx.currentTime); // Tần số cao cho tiếng "tích"
        gainNode.gain.setValueAtTime(0.05, audioCtx.currentTime); // Âm lượng nhỏ
        gainNode.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.1);
        oscillator.start();
        oscillator.stop(audioCtx.currentTime + 0.1);
    } catch (e) {}
};

window.handlePlayerAction = function(name) {
    window.playClickSound(); // Phát âm thanh ngay lập tức
    if (window.ignoredPlayers.has(name)) {
        window.ignoredPlayers.delete(name);
    } else {
        window.ignoredPlayers.add(name);
    }
};
window.handlePlayerAction = function(name) {
    if (window.ignoredPlayers.has(name)) {
        window.ignoredPlayers.delete(name);
        console.log("Đã cho phép bắn: " + name);
    } else {
        window.ignoredPlayers.add(name);
        console.log("Aimbot sẽ né: " + name);
    }
};
// avoid detection
const matchDetection = /^function\(\){\w+\['\w+'\]\(\);}$/;
const setIntervalHandler = {
  apply: function(target, thisArg, argumentsList) {
    const callback = argumentsList[0];
    const delay = argumentsList[1];
    if (delay === 1000 && callback && callback.toString().match(matchDetection)) {
      console.log('Blocked detection');
      return null;
    }
    return Reflect.apply(...arguments);
  }
};
window.setInterval = new Proxy(window.setInterval, setIntervalHandler);

// add #lil-gui container
const lilGuiContainer = document.createElement('div');
lilGuiContainer.id = 'lil-gui';
document.body.appendChild(lilGuiContainer);

const style = document.createElement('style');
const guiStyle = document.createElement('style');
const GUI = lil.GUI;
const gui = new GUI({ container: lilGuiContainer, title: 'Kobitz Menu' });
// THÊM ĐOẠN NÀY NGAY PHÍA DƯỚI:
gui.onFinishChange(() => {
    const configToSave = gui.save();
    localStorage.setItem('espConfig', JSON.stringify(configToSave));
    console.log('Đã lưu cấu hình mới!');
});

let espConfig = {
  heightLine: 1.16,
  zoomLevel: 20,    // Độ phóng (càng nhỏ càng phóng xa)
  zoomKey: 'z',      // Phím Zoom là Z
  isZooming: false,  // Trạng thái Zoom
  fZoomEnabled: false,
  sneakHeight: 0.4,
  ennemyDistance: 50,
  maxAngleInRadians: 0.5,
  unlimitedAngle: false, // THÊM DÒNG NÀY: Trạng thái không giới hạn góc
  noRecoil: true,
  showBox: 0,
  showOutline: 0,
  showPlayer: 2,
  nameScaling: true, // Bật/tắt tự động phóng to theo khoảng cách
  showPlayerNames: true,
  showRadar: true, // Mặc định bảng sẽ hiện khi vào game
  showLine: 1,
  wireframe: false,
  allEnnemies: false,
  isSniper: false,
  aimbot: 2,
  triggerBot: 2,
  aimbotIgnoreWall: false,
  aimbotIgnoreWallKey: '\\', // Thêm dòng này để gán phím \
  mapZoom: 100,
  mapOffsetZ: 0,
  autoClaimAds: false,
  antiAFK: false,
  antiAFKKey: 'k', // Thêm phím tắt cho Anti-AFK
  showRadar: true, // THÊM DÒNG NÀY: Mặc định hiện bảng Radar
  sit: false,
  sit: false, // Lưu trạng thái cho nút trên Menu
  rainbow: false,
  rainbowKey: '=', // Gán phím =
  showAimRadius: false,
  lockAimbotTriggerBot: false,
  aimbotKey: 'b',
  triggerBotKey: 't',
  toggleUIKey: '.',
  // NEW: Sound features
  triggerSound: false,
  triggerSoundType: 'beep',
  triggerSoundVolume: 0.5,
  // NEW: Item ESP
  showItems: false,
  showItemNames: false,
  // NEW: Key bindings
  showItemsKey: 'i',
  showItemNamesKey: 'n',
};

const aimbotFolder = gui.addFolder('Aimbot');
aimbotFolder.add(espConfig, 'aimbot').name(`aimbot (${espConfig.aimbotKey})`).options({Off: 0, LeftClick: 1, RightClick: 2, Always: 3}).listen();
aimbotFolder.add(espConfig, 'triggerBot').name(`triggerBot (${espConfig.triggerBotKey})`).options({Off: 0, LeftClick: 1, RightClick: 2, Always: 3}).listen();
aimbotFolder.add(espConfig, 'noRecoil');
aimbotFolder.add(espConfig, 'allEnnemies').name("All Enemies (L)").listen();
aimbotFolder.add(espConfig, 'isSniper');
const advancedAimbotFolder = aimbotFolder.addFolder('Advanced');
advancedAimbotFolder.close();
advancedAimbotFolder.add(espConfig, 'aimbotIgnoreWall');
advancedAimbotFolder.add(espConfig, 'showAimRadius');
advancedAimbotFolder.add(espConfig, 'maxAngleInRadians', 0.01, 0.5, 0.01);
advancedAimbotFolder.add(espConfig, 'unlimitedAngle').name('Không giới hạn góc (Unlimited)');
advancedAimbotFolder.add(espConfig, 'heightLine', .5, 1.25, 0.01);
advancedAimbotFolder.add(espConfig, 'sneakHeight', 0, 1, 0.01);

const chamsFolder = gui.addFolder('Chams');
chamsFolder.close();
chamsFolder.add(espConfig, 'showPlayer').options({Off: 0, Ennemies: 1, All: 2});
chamsFolder.add(espConfig, 'nameScaling').name('Auto Scale Names');
chamsFolder.add(espConfig, 'showPlayerNames').name('Show Names');
chamsFolder.add(espConfig, 'showRadar').name("Show Radar ( ' )").listen();
chamsFolder.add(espConfig, 'showRadar').name("Hiện Bảng Radar ( ' )").listen();
    // Lệnh .listen() cực kỳ quan trọng để dấu tích tự nhảy khi bạn nhấn phím '
chamsFolder.add(espConfig, 'showLine').options({Off: 0, Ennemies: 1, All: 2});
chamsFolder.add(espConfig, 'showOutline').options({Off: 0, Ennemies: 1, All: 2});
chamsFolder.add(espConfig, 'showBox').options({Off: 0, Ennemies: 1, All: 2});
chamsFolder.add(espConfig, 'ennemyDistance', 10, 100, 1);
chamsFolder.add(espConfig, 'wireframe');
chamsFolder.add(espConfig, 'rainbow').name("rainbow ( = )").listen();
chamsFolder.add(espConfig, 'mapZoom', 20, 100, 1);
chamsFolder.add(espConfig, 'mapOffsetZ', -50, 50, 1);
// NEW: Item ESP settings
chamsFolder.add(espConfig, 'showItems').name(`Show Items (${espConfig.showItemsKey})`);
chamsFolder.add(espConfig, 'showItemNames').name(`Show Item Names (${espConfig.showItemNamesKey})`);

// NEW: Sound folder
const soundFolder = gui.addFolder('Sound');
soundFolder.close();
soundFolder.add(espConfig, 'triggerSound').name('Triggerbot Sound');
// ĐÃ THÊM DANH SÁCH 11 ÂM THANH
soundFolder.add(espConfig, 'triggerSoundType', [
  'beep', 'click', 'ping', 'laser', 'retro',
  'heavy', 'digital', 'sharp', 'ufo', 'electric', 'dubstep'
]).name('Sound Type');
soundFolder.add(espConfig, 'triggerSoundVolume', 0.1, 1, 0.1).name('Volume');

const zoomFolder = gui.addFolder('Tính năng Zoom');
zoomFolder.add(espConfig, 'isZooming').name('Đang Zoom (Z)').listen();
zoomFolder.add(espConfig, 'zoomLevel', 1, 175, 1).name('Độ Zoom (FOV)').listen();
zoomFolder.add(espConfig, 'fZoomEnabled').name('Bật Zoom phím F').listen(); // Nút mới ở đây
zoomFolder.add(espConfig, 'zoomKey').name('Phím Zoom');

const toolsFolder = gui.addFolder('Tools');
toolsFolder.close();
toolsFolder.add(espConfig, 'autoClaimAds');
toolsFolder.add(espConfig, 'antiAFK').name(`antiAFK (${espConfig.antiAFKKey})`).listen();
toolsFolder.add(espConfig, 'sit').name('Sit Mode (V)'); // Nút bấm trên Menu
toolsFolder.add(espConfig, 'lockAimbotTriggerBot');

// load/save config
const configFolder = gui.addFolder('Config');
configFolder.add(espConfig, 'toggleUIKey').name('Toggle UI key');
configFolder.add(espConfig, 'aimbotKey').name('Aimbot key');
configFolder.add(espConfig, 'triggerBotKey').name('Triggerbot key');
configFolder.add(espConfig, 'showItemsKey').name('Show Items key'); // NEW
configFolder.add(espConfig, 'showItemNamesKey').name('Show Item Names key'); // NEW
configFolder.close();
const defaultConfig = gui.save();
let config = { configName: 'espConfig' };
configFolder.add(config, 'configName').name('Config name');
configFolder.add({ export: () => {
  const currentConfig = JSON.stringify(gui.save(), null, 2);
  const element = document.createElement('a');
  element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(currentConfig));
  element.setAttribute('download', config.configName + '.json');
  element.style.display = 'none';
  document.body.appendChild(element);
  element.click();
  document.body.removeChild(element);
}}, 'export').name('Export config');
configFolder.add({ import: () => {
  const input = document.createElement('input');
  input.type = 'file';
  input.accept = '.json';
  input.onchange = (e) => {
    const file = e.target.files[0];
    const reader = new FileReader();
    reader.onload = (e) => {
      gui.load(JSON.parse(e.target.result));
    };
    reader.readAsText(file);
  };
  input.click();
}}, 'import').name('Import config');
configFolder.add({ reset: () => {
  gui.load(defaultConfig);
  localStorage.removeItem('espConfig');
}}, 'reset').name('Reset config');

// auto load/save config
const savedConfig = localStorage.getItem('espConfig');
if (savedConfig) {
  console.log('Loaded config', savedConfig);
  gui.load(JSON.parse(savedConfig));
}
// --- TỐI ƯU ÂM THANH: Tạo 1 đối tượng duy nhất để dùng lại ---
const clickSound = new Audio('https://commondatastorage.googleapis.com/codeskulptor-assets/week7-brads79-brio.ogg');
clickSound.volume = 0.5;

// --- ĐOẠN MÃ TỐI ƯU: CHỈ DÙNG 1 LISTENER DUY NHẤT ---
document.addEventListener('keydown', (e) => {
    // 1. Kiểm tra nếu đang gõ văn bản thì không kích hoạt hack
    const isInputField = e.target && (e.target.isContentEditable || e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement);
    if (isInputField) return;

    const key = e.key;
    const keyL = e.key.toLowerCase();
    const modes = ["OFF", "LeftClick", "RightClick", "Always"];

    // 2. Xử lý các phím chức năng
    switch (keyL) {
        case espConfig.rainbowKey: // Phím '='
            espConfig.rainbow = !espConfig.rainbow;
            notifyStatus("Rainbow", espConfig.rainbow ? "ON" : "OFF");
            break;
case espConfig.aimbotIgnoreWallKey: // Phím '\'
        case 'n':
            // Sửa điều kiện: thêm phím '\' vào để nó nhận diện đúng
            if (e.shiftKey || key === 'N' || key === '\\') {
                espConfig.aimbotIgnoreWall = !espConfig.aimbotIgnoreWall;
                notifyStatus("aimbotIgnoreWall", espConfig.aimbotIgnoreWall ? "ON" : "OFF");
            } else {
                espConfig.showItemNames = !espConfig.showItemNames;
                notifyStatus("showItemName", espConfig.showItemNames ? "ON" : "OFF");
            }
            break;
        case 'k':
            espConfig.antiAFK = !espConfig.antiAFK;
            notifyStatus("Anti-AFK", espConfig.antiAFK ? "ON" : "OFF");
            break;
        case 'i':
            espConfig.showItems = !espConfig.showItems;
            notifyStatus("Show Items", espConfig.showItems ? "ON" : "OFF");
            break;
        case 'b':
            if (!espConfig.lockAimbotTriggerBot) {
                espConfig.aimbot = (espConfig.aimbot + 1) % 4;
                notifyStatus("Aimbot", modes[espConfig.aimbot]);
            }
            break;
        case espConfig.zoomKey.toLowerCase():
            espConfig.isZooming = true;
            break;
        case 't':
            if (!espConfig.lockAimbotTriggerBot) {
                espConfig.triggerBot = (espConfig.triggerBot + 1) % 4;
                notifyStatus("TriggerBot", modes[espConfig.triggerBot]);
            }
            break;
        case 'l':
            espConfig.allEnnemies = !espConfig.allEnnemies;
            notifyStatus("All Enemies", espConfig.allEnnemies ? "ON" : "OFF");
            break;
        case 'f': // Thêm xử lý cho phím F
    if (espConfig.fZoomEnabled) {
        espConfig.isZooming = true;
    }
    break;
        case ';':
            espConfig.wireframe = !espConfig.wireframe;
            notifyStatus("Wireframe", espConfig.wireframe ? "ON" : "OFF");
            break;
        case 'v':
            espConfig.sit = !espConfig.sit; // Lệnh đảo trạng thái Bật/Tắt
            notifyStatus("Sit Mode", espConfig.sit ? "ON" : "OFF");
            break;
        case "'":
            espConfig.showRadar = !espConfig.showRadar;
            notifyStatus("Radar", espConfig.showRadar ? "ON" : "OFF");
            const radar = document.getElementById('side-player-list');
            if (radar) radar.style.display = espConfig.showRadar ? 'block' : 'none';
            break;
        case espConfig.toggleUIKey: // Phím '.'
            lilGuiContainer.style.display = lilGuiContainer.style.display === 'none' ? 'block' : 'none';
            break;
        case 'e':
            if (espConfig.autoClaimAds) setTimeout(claimAds, 100);
            break;
    }

    // Cập nhật lại Menu lil-gui để đồng bộ dấu tích
    if (typeof gui !== 'undefined') {
        gui.controllersRecursive().forEach(c => c.updateDisplay());
    }
});


// NEW: Sound functions
let audioContext = null;
let lastSoundTime = 0;
const soundCooldown = 100; // ms between sounds

function createTriggerSound(type, volume) {
  if (!audioContext) {
    audioContext = new (window.AudioContext || window.webkitAudioContext)();
  }

  const now = Date.now();
  if (now - lastSoundTime < soundCooldown) return;

  lastSoundTime = now;

  const gainNode = audioContext.createGain();
  gainNode.gain.value = volume;
  gainNode.connect(audioContext.destination);

  const oscillator = audioContext.createOscillator();
  oscillator.connect(gainNode);

  switch(type) {
    case 'beep':
      oscillator.frequency.value = 800;
      oscillator.type = 'sine';
      oscillator.start();
      oscillator.stop(audioContext.currentTime + 0.05);
      break;

    case 'click':
      oscillator.frequency.value = 1200;
      oscillator.type = 'sine';
      oscillator.start();
      oscillator.stop(audioContext.currentTime + 0.03);
      break;

    case 'ping':
      oscillator.frequency.value = 1000;
      oscillator.type = 'triangle';
      oscillator.start();
      oscillator.frequency.exponentialRampToValueAtTime(2000, audioContext.currentTime + 0.1);
      oscillator.stop(audioContext.currentTime + 0.1);
      break;

    case 'laser':
      oscillator.frequency.value = 1500;
      oscillator.type = 'sawtooth';
      oscillator.start();
      oscillator.frequency.exponentialRampToValueAtTime(200, audioContext.currentTime + 0.2);
      oscillator.stop(audioContext.currentTime + 0.2);
      break;

    case 'retro':
      oscillator.frequency.value = 600;
      oscillator.type = 'square';
      oscillator.start();
      oscillator.frequency.exponentialRampToValueAtTime(100, audioContext.currentTime + 0.1);
      oscillator.stop(audioContext.currentTime + 0.1);
      break;

    // --- CÁC ÂM THANH MỚI ---
    case 'heavy':
      oscillator.frequency.value = 150;
      oscillator.type = 'sawtooth';
      oscillator.start();
      oscillator.frequency.exponentialRampToValueAtTime(50, audioContext.currentTime + 0.15);
      oscillator.stop(audioContext.currentTime + 0.15);
      break;

    case 'digital':
      oscillator.frequency.value = 2000;
      oscillator.type = 'square';
      oscillator.start();
      oscillator.frequency.setValueAtTime(1500, audioContext.currentTime + 0.05);
      oscillator.stop(audioContext.currentTime + 0.1);
      break;

    case 'sharp':
      oscillator.frequency.value = 3000;
      oscillator.type = 'sine';
      oscillator.start();
      oscillator.stop(audioContext.currentTime + 0.02);
      break;

    case 'ufo':
      oscillator.frequency.value = 1000;
      oscillator.type = 'sine';
      oscillator.start();
      oscillator.frequency.linearRampToValueAtTime(200, audioContext.currentTime + 0.2);
      oscillator.frequency.linearRampToValueAtTime(1000, audioContext.currentTime + 0.4);
      oscillator.stop(audioContext.currentTime + 0.2);
      break;

    case 'electric':
      oscillator.frequency.value = 400;
      oscillator.type = 'sawtooth';
      gainNode.gain.setTargetAtTime(0, audioContext.currentTime, 0.05);
      oscillator.start();
      oscillator.stop(audioContext.currentTime + 0.1);
      break;

    case 'dubstep':
      oscillator.frequency.value = 100;
      oscillator.type = 'square';
      oscillator.start();
      oscillator.frequency.exponentialRampToValueAtTime(800, audioContext.currentTime + 0.05);
      oscillator.frequency.exponentialRampToValueAtTime(100, audioContext.currentTime + 0.1);
      oscillator.stop(audioContext.currentTime + 0.15);
      break;
  }
}

function playTriggerSound() {
  if (espConfig.triggerSound) {
    createTriggerSound(espConfig.triggerSoundType, espConfig.triggerSoundVolume);
  }
}

// no-recoil
let foundRecoil = false;
const arrayPushHandler = {
  apply: function(target, thisArg, argumentsList) {
    if (!foundRecoil && argumentsList.length === 1) {
      const item = argumentsList[0];
      if (item && typeof item === 'object') {
        const keys = Object.keys(item);
        if (keys.length === 44) {
          for (const key in item) {
            if (item[key] === 0.3) {
              console.log('Recoil key found', key);
              foundRecoil = true;
              Object.defineProperty(Object.prototype, key, {
                get: () => {
                  return espConfig.noRecoil ? 0 : item[key];
                },
                set: (baseRecoil) => {
                  _baseRecoil = baseRecoil;
                }
              });
              break;
            }
          }
        }
      }
    }
    return Reflect.apply(...arguments);
  }
};
Array.prototype.push = new Proxy(Array.prototype.push, arrayPushHandler);

// listen for mouse click
let isLeftClick = false;
let isRightClick = false;
document.addEventListener('mousedown', (e) => {
  if (e.button === 0) {
    isLeftClick = true;
  }
  if (e.button === 2) {
    if (espConfig.isSniper) {
      setTimeout(() => {
        isRightClick = true;
      }, 400);
    } else {
      isRightClick = true;
    }
  }
});
document.addEventListener('mouseup', (e) => {
  if (e.button === 0) {
    isLeftClick = false;
  }
  if (e.button === 2) {
    isRightClick = false;
  }
});

// obfuscaed keys
let worldScene = null;
let childrenKey = null;
let worldCamera = null;
let projectionMatrixKey = null;
let matrixWorldKey = null;
let matrixElKey = null;

// three.js setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.rotation.order = 'YXZ';
let saveViewport = new THREE.Vector4();
let saveScissor = new THREE.Vector4();
let minimapViewport = new THREE.Vector4(20, window.innerHeight - 250 - 20, 250, 250);
const minimapCamera = new THREE.OrthographicCamera(-espConfig.mapZoom, espConfig.mapZoom, espConfig.mapZoom, -espConfig.mapZoom, 0.1, 1000);
minimapCamera.rotation.order = 'YXZ';
minimapCamera.position.set(0, 50, 0);
minimapCamera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer( {
  alpha: true,
  antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.domElement.id = 'overlayCanvas';
document.body.appendChild(renderer.domElement);


function setTransform(target, transform, isMatrix = true) {
  const matrix = new THREE.Matrix4().fromArray(isMatrix ? transform : transform[matrixWorldKey][matrixElKey]);
  matrix.decompose(target.position, target.quaternion, target.scale);
}

doOnce = (fn) => {
  let done = false;
  return (...args) => {
    if (!done) {
      done = true;
      return fn(...args);
    }
  };
};

function checkWorldCamera(object) {
  if (worldCamera && object.uuid === worldCamera.uuid) return;
  let hasProjectionMatrix = false;
  for (const key in object) {
    const element = object[key];
    if (!element) continue;
    if (typeof element == 'object') {
      if (hasProjectionMatrix) continue;
      const valueKey = Object.keys(element)[0];
      const value = element[valueKey];
      if (Array.isArray(value) && value[11] === -1) {
        hasProjectionMatrix = true;
        matrixElKey = valueKey;
        projectionMatrixKey = key;
      }
    } else if (typeof element === 'function') {
      const code = element.toString();
      const match = /verse'\]\(this\['([^']+)'\]\);/.exec(code);
      if (match) {
        matrixWorldKey = match[1];
      }
    }
    if (hasProjectionMatrix && matrixWorldKey) {
      console.log('Found camera', {object}, object);
      worldCamera = object;
      object[projectionMatrixKey] = new Proxy(object[projectionMatrixKey], {
        get: function(target, prop, receiver) {

          // 1. Update overlay camera (camera) based on game's worldCamera state
          setTransform(camera, worldCamera, false);
          camera.near = worldCamera.near;
          camera.far = worldCamera.far;
          camera.aspect = worldCamera.aspect;
          camera.fov = worldCamera.fov;
          camera.updateProjectionMatrix();

          worldCamera = object;
          window.worldCamera = object;
          return Reflect.get(...arguments);
        }
      });
      break;
    }
  }
}

function checkWorldScene(object) {
  if (worldScene || object instanceof THREE.Scene) return;
  for (const key in object) {
    const element = object[key];
    if (!element) continue;
    if (Array.isArray(element) && element.length === 9) {
      const value = element[0];
      if (value && typeof value === 'object' && value.hasOwnProperty('uuid')) {
        childrenKey = key;
      }
    }
    if (childrenKey) {
      console.log('Found scene', {childrenKey}, object);
      worldScene = object;
      window.worldScene = object;
      renderer.setAnimationLoop(animate);
      break;
    }
  }
}

Object.defineProperty( Object.prototype, 'overrideMaterial', {
  get: function() {
    checkWorldScene(this);
    return this._overrideMaterial;
  },
  set: function(value) {
    this._overrideMaterial = value;
  }
});
Object.defineProperty( Object.prototype, 'far', {
  get: function() {
    checkWorldCamera(this);
    return this._far;
  },
  set: function(value) {
    this._far = value;
  }
});

function isPlayer(entity) {
  try {
    return entity[childrenKey].length > 2 || !entity[childrenKey][1].geometry;
  } catch {
    return false;
  }
}

// NEW: Function to check if entity is an item (from the first script)
function isItem(entity) {
  try {
    // Items typically have simpler geometry than players
    const mesh = entity[childrenKey][0];
    if (mesh && mesh.geometry) {
      // Check if it's not a player and has geometry (could be item or block)
      return !isPlayer(entity) && mesh.geometry;
    }
    return false;
  } catch {
    return false;
  }
}

// NEW: Function to create item sprite with name
function createItemSprite(text, colorStr) {
    const fontface = "Arial";
    const fontsize = 40;
    const padding = 8;

    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    context.font = "Bold " + fontsize + "px " + fontface;

    const metrics = context.measureText(text);
    const textWidth = metrics.width;

    canvas.width = textWidth + padding * 2;
    canvas.height = fontsize * 1.2;

    context.font = "Bold " + fontsize + "px " + fontface;
    context.textBaseline = "middle";
    context.textAlign = "center";

    context.fillStyle = "rgba(0, 0, 0, 0.6)";
    context.fillRect(0, 0, canvas.width, canvas.height);

    context.fillStyle = colorStr;
    context.fillText(text, canvas.width / 2, canvas.height / 2);

    const texture = new THREE.CanvasTexture(canvas);
    texture.minFilter = THREE.LinearFilter;

    const spriteMaterial = new THREE.SpriteMaterial({
        map: texture,
        depthTest: false,
        depthWrite: false
    });

    const sprite = new THREE.Sprite(spriteMaterial);
    sprite.initialRatio = (canvas.width / canvas.height);
    sprite.baseScale = 1.0;
    sprite.scale.set(0.3 * sprite.initialRatio, 0.3, 1);
    sprite.scale.multiplyScalar(sprite.baseScale);

    return sprite;
}

// claim ads
function claimAds() {
  document.querySelectorAll('svg').forEach(svg => {
    if (svg.getAttribute('data-icon') === 'play-circle') {
      svg.closest('div').click();
      console.log('Claimed ads');
    }
  });
}

const context2DFillTextHandler = {
  apply: function(target, thisArg, argumentsList) {
    thisArg.canvas.lastText = argumentsList[0];
    return Reflect.apply(...arguments);
  }
};
CanvasRenderingContext2D.prototype.fillText = new Proxy(CanvasRenderingContext2D.prototype.fillText, context2DFillTextHandler);

function isEnnemy(entity) {
  for (const child of entity[childrenKey]) {
    try {
      const matImage = child.material.map.image;
      if (matImage instanceof HTMLCanvasElement && matImage.hasOwnProperty('lastText')) {
        entity.playerName = matImage.lastText;
        return false;
      }
    } catch {}
  }
  return true;
}

let lastFiringState = false;
function setFiring(shouldFire) {
  if (setFiring.firing === shouldFire) return;
  setFiring.firing = shouldFire;

  // NEW: Play sound when starting to fire
  if (shouldFire && !lastFiringState) {
    playTriggerSound();
  }
  lastFiringState = shouldFire;

  if (shouldFire) {
    if (espConfig.isSniper) { // need improvement
      setTimeout(() => {
        document.dispatchEvent(new MouseEvent('mousedown', { buttons: 3 }));
        setTimeout(() => {
          document.dispatchEvent(new MouseEvent('mouseup', { buttons: 0 }));
        }, 200);
        // setFiring.firing = false;
      }, 300);
    } else {
      document.dispatchEvent(new MouseEvent('mousedown', { buttons: 3 }));
    }
  } else {
    document.dispatchEvent(new MouseEvent('mouseup', { buttons: 0 }));
  }
}

const colors = {
  ennemy: new THREE.Color(0xff0000),
  player: new THREE.Color(0x00ff00),
  blue: new THREE.Color(0x0000ff),
  item: new THREE.Color(0xD4AF37) // NEW: Gold color for items (from first script)
};

const outlineMats = {
  ennemy: new THREE.LineBasicMaterial({ color: colors.ennemy }),
  player: new THREE.LineBasicMaterial({ color: colors.player })
};
const meshMats = {
  ennemy: new THREE.MeshBasicMaterial({ color: colors.ennemy, transparent: true, opacity: 0.5 }),
  player: new THREE.MeshBasicMaterial({ color: colors.player, transparent: true, opacity: 0.5 }),
  item: new THREE.MeshBasicMaterial({ color: colors.item, transparent: true, opacity: 0.7 }) // NEW: Item material
};

const raycaster = new THREE.Raycaster();
const edgesGeometry = new THREE.EdgesGeometry(new THREE.BoxGeometry(1, 1, 1).translate(0, 0.5, 0));

// NEW: Item box geometry (smaller than player boxes)
const itemBoxGeometry = new THREE.BoxGeometry(0.25, 0.25, 0.25);

const lineGeometry = new THREE.BufferGeometry();
const lineMaterial = new THREE.LineBasicMaterial({ vertexColors: true, transparent: true });
const line = new THREE.LineSegments(lineGeometry, lineMaterial);
line.frustumCulled = false;
scene.add(line);

const dummyLookAt = new THREE.PerspectiveCamera();
const color = new THREE.Color();

const chunkMaterial = new THREE.MeshNormalMaterial();

const boxPlayerGeometry = new THREE.BoxGeometry(.25, 1.25, 0.25);


// crosshair circle
const crosshairGeometry = new THREE.CircleGeometry(.5, 32);
const crosshairMaterial = new THREE.LineBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.2 });
const crosshair = new THREE.LineLoop(crosshairGeometry, crosshairMaterial);
camera.add(crosshair);
scene.add(camera);

function calculateValue(maxAngleInRadians) {
  const a = -79.83;
  const b = -30.06;
  const c = -0.90;
  return a * Math.exp(b * maxAngleInRadians) + c;
}

// Hàm tạo Text Sprite: RÕ RÀNG HƠN với nền đen và chữ to
function makeTextSprite(message, colorStr) {
    const fontface = "Arial";
    const fontsize = 60;
    const padding = 10;

    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    context.font = "Bold " + fontsize + "px " + fontface;

    const metrics = context.measureText(message);
    const textWidth = metrics.width;

    canvas.width = textWidth + padding * 2;
    canvas.height = fontsize * 1.4;

    context.font = "Bold " + fontsize + "px " + fontface;
    context.textBaseline = "middle";
    context.textAlign = "center";

    context.fillStyle = "rgba(0, 0, 0, 0.6)";
    context.fillRect(0, 0, canvas.width, canvas.height);

    context.fillStyle = colorStr;
    context.fillText(message, canvas.width / 2, canvas.height / 2);

    const texture = new THREE.CanvasTexture(canvas);
    texture.minFilter = THREE.LinearFilter;

    const spriteMaterial = new THREE.SpriteMaterial({
        map: texture,
        depthTest: false,
        depthWrite: false
    });

    const sprite = new THREE.Sprite(spriteMaterial);

    // Đặt tỷ lệ cơ bản (nhỏ hơn 2.0 ban đầu) và lưu ratio/baseScale
    sprite.initialRatio = (canvas.width / canvas.height);
    sprite.baseScale = 1.5; // Kích thước cơ bản
    sprite.scale.set(0.5 * sprite.initialRatio, 0.5, 1);
    sprite.scale.multiplyScalar(sprite.baseScale);

    return sprite;
}

function animate(time) {
  const now = Date.now();
  const entities = childrenKey ? worldScene[childrenKey][5][childrenKey] : [];
  const lineOrigin = camera.localToWorld(new THREE.Vector3(0, 0, -10));
  const linePositions = [];
  crosshair.position.z = calculateValue(espConfig.maxAngleInRadians);
  crosshair.visible = espConfig.showAimRadius && !espConfig.unlimitedAngle;
  const colorArray = [];
  const aimbotTarget = { angleDifference: Infinity};
  const chunks = [];
  const gameChunks = childrenKey ? worldScene[childrenKey][4][childrenKey] : [];
  for (const chunk of gameChunks) {
    if (!chunk || !chunk.geometry) continue;
    const chunkPositions = chunk.geometry.attributes.position.array;
    if (!chunkPositions || !chunkPositions.length) continue;
    if (!chunk.myChunk) {
      const geometry = new THREE.BufferGeometry();
      geometry.setAttribute(
        'position',
        new THREE.Float32BufferAttribute(chunkPositions, 3)
      );
      geometry.setIndex(
        new THREE.BufferAttribute(chunk.geometry.index.array, 1)
      );
      geometry.computeVertexNormals();
      geometry.computeBoundingBox();
      chunk.myChunk = new THREE.Mesh(geometry, chunkMaterial);
      chunk.myChunk.box = new THREE.Box3();
    }
    const myChunk = chunk.myChunk;
    if (chunk.material) chunk.material.wireframe = espConfig.wireframe;
    setTransform(myChunk, chunk, false);
    myChunk.updateMatrixWorld();
    myChunk.box.copy(myChunk.geometry.boundingBox).applyMatrix4(myChunk.matrixWorld);
    chunks.push(myChunk);
  }

  chunks.sort((a, b) => {
    const distanceA = a.position.distanceTo(camera.position);
    const distanceB = b.position.distanceTo(camera.position);
    return distanceB - distanceA;
  });

  const shouldAimbot = espConfig.aimbot === 3 || (espConfig.aimbot === 1 && isLeftClick) || (espConfig.aimbot === 2 && isRightClick);

  entities.forEach(entity => {
    if (!entity || !entity.parent) return;
    if (!entity.myObject3D) {
      entity.myObject3D = new THREE.Object3D();
      entity.myObject3D.frustumCulled = false;
      entity.discovered = now;
      entity.loaded = false;
      entity.logged = false;
      entity.ennemy = null;
      return;
    }
    if (typeof entity.visible === 'boolean' && !entity.visible) {
      entity.myObject3D.visible = false;
      return;
    }
    if (!entity.loaded && now - entity.discovered < 500) return;
    entity.loaded = true;
// --- TÍNH VẬN TỐC CHO TẤT CẢ MỌI NGƯỜI (DÙ CÓ TÊN HAY KHÔNG) ---
    if (entity.myObject3D) {
        // Sử dụng entity.id thay cho entity.playerName để quét tất cả vật thể
        const entityKey = entity.id || entity.playerName || "unknown";
        const currentPos = entity.myObject3D.position.clone();

        if (window.lastPositions.has(entityKey)) {
            const lastPos = window.lastPositions.get(entityKey);
            const instantVel = new THREE.Vector3().subVectors(currentPos, lastPos);

            if (!entity.velocity) entity.velocity = new THREE.Vector3(0, 0, 0);
            // Giữ nguyên độ nhạy 0.4
            entity.velocity.lerp(instantVel, 0.4);
        }
        window.lastPositions.set(entityKey, currentPos.clone());
    }


    // Check if it's a player
    if (isPlayer(entity)) {
      if (!entity.logged) {
        const skinnedMesh = entity[childrenKey][1][childrenKey][3];
        entity.isPlayer = true;
        entity.logged = true;
        entity.ennemy = isEnnemy(entity);
        const playerMesh = new THREE.Mesh(skinnedMesh.geometry, entity.ennemy ? meshMats.ennemy : meshMats.player);
        entity.myObject3D.add(playerMesh);
        entity.myObject3D.playerMesh = playerMesh;
        const playerMiniMap = new THREE.Mesh(skinnedMesh.geometry, entity.ennemy ? meshMats.ennemy : meshMats.player);
        playerMiniMap.visible = false;
        entity.myObject3D.add(playerMiniMap);
        entity.myObject3D.playerMiniMap = playerMiniMap;
        const outline = new THREE.LineSegments(edgesGeometry, entity.ennemy ? outlineMats.ennemy : outlineMats.player);
        outline.scale.set(0.5, 1.25, 0.5);
        outline.frustumCulled = false;
        entity.myObject3D.add(outline);
        entity.myObject3D.outline = outline;
        const boxMesh = new THREE.Mesh(boxPlayerGeometry, entity.ennemy ? meshMats.ennemy : meshMats.player);
        boxMesh.position.y = 0.625;
        entity.myObject3D.add(boxMesh);
        entity.myObject3D.boxMesh = boxMesh;
        const dir = new THREE.Vector3(0, 0, -1);
        const origin = new THREE.Vector3(0, 1, 0);
        const arrowLookingAt = new THREE.ArrowHelper(dir, origin, 1, entity.ennemy ? colors.ennemy : colors.player, 0.5, .4);
        playerMiniMap.add(arrowLookingAt);
        setTransform(entity.myObject3D, entity, false);
        scene.add(entity.myObject3D);
      }if (isPlayer(entity)) {
        // ... (các đoạn code cũ của bạn) ...

        if (entity.playerName) {
    const dist = entity.myObject3D.position.distanceTo(camera.position);

    // Mặc định: Đỏ cho địch (#ff4444), Xanh cho bạn (#44ff44)
    let playerColor = entity.ennemy ? "#ff4444" : "#44ff44";

    // TÍNH NĂNG MỚI: Nếu tên chứa "soldier" (không phân biệt hoa thường), hiện màu đỏ rực
    if (entity.playerName.toLowerCase().includes("soldier#")) {
        playerColor = "#ff0000";
    }

    // Cập nhật dữ liệu vào Radar
// --- ĐOẠN MÃ MŨI TÊN AN TOÀN ---
let playerArrow = "•";
try {
    // Lấy vị trí người chơi và camera
    const pPos = entity.myObject3D.position;
    const cPos = camera.position;

    // Tính hướng từ mình đến địch (chỉ tính mặt phẳng X-Z)
    const toP = new THREE.Vector3(pPos.x - cPos.x, 0, pPos.z - cPos.z).normalize();
    const cDir = new THREE.Vector3();
    camera.getWorldDirection(cDir);
    const forward = new THREE.Vector3(cDir.x, 0, cDir.z).normalize();

    // Tính góc xoay
    const angle = Math.atan2(toP.z, toP.x) - Math.atan2(forward.z, forward.x);
    let deg = angle * (180 / Math.PI);
    if (deg < 0) deg += 360;

    // Xác định mũi tên theo độ
    if (deg > 337.5 || deg <= 22.5) playerArrow = "↑";
    else if (deg > 22.5 && deg <= 67.5) playerArrow = "↗";
    else if (deg > 67.5 && deg <= 112.5) playerArrow = "→";
    else if (deg > 112.5 && deg <= 157.5) playerArrow = "↘";
    else if (deg > 157.5 && deg <= 202.5) playerArrow = "↓";
    else if (deg > 202.5 && deg <= 247.5) playerArrow = "↙";
    else if (deg > 247.5 && deg <= 292.5) playerArrow = "←";
    else if (deg > 292.5 && deg <= 337.5) playerArrow = "↖";
} catch(err) { /* Nếu lỗi thì hiện dấu chấm để không hỏng ESP */ playerArrow = "•"; }

// Lưu vào bộ nhớ Radar
window.playerMap.set(entity.playerName, {
    dist: Math.round(camera.position.distanceTo(entity.myObject3D.position)),
    color: playerColor,
    arrow: playerArrow
});
// --- HẾT ĐOẠN MÃ MŨI TÊN ---
}
    }

      entity.myObject3D.playerMesh.rotation.y = -entity[childrenKey][1].rotation._y;
      entity.myObject3D.playerMiniMap.rotation.y = -entity[childrenKey][1].rotation._y;
      const skinnedMesh = entity[childrenKey][1][childrenKey][3];
      const isSneak = skinnedMesh.skeleton.bones[4].rotation._x > 0.1;
      entity.myObject3D.boxMesh.scale.set(1, isSneak ? .4 : 1, 1);
      entity.myObject3D.outline.scale.set(0.5, isSneak ? .9 : 1.25, 0.5);
      entity.myObject3D.playerMesh.scale.set(1, isSneak ? .7 : 1, 1);

      entity.myObject3D.visible = true;
      entity.myObject3D.playerMesh.visible = espConfig.showPlayer === 2 || (espConfig.showPlayer === 1 && !entity.ennemy);
      entity.myObject3D.boxMesh.visible = espConfig.showBox === 2 || (espConfig.showBox === 1 && entity.ennemy);
      entity.myObject3D.outline.visible = espConfig.showOutline === 2 || (espConfig.showOutline === 1 && entity.ennemy);
      setTransform(entity.myObject3D, entity, false);

if (espConfig.showPlayerNames && entity.playerName) {
        // 1. Khởi tạo Sprite nếu chưa có (Phần này giữ nguyên như bạn nói)
        if (!entity.myObject3D.nameSprite) {
            const spriteColor = entity.ennemy ? "#ff0000" : "#00ff00";
            const sprite = makeTextSprite(entity.playerName, spriteColor);
            entity.myObject3D.add(sprite);
            entity.myObject3D.nameSprite = sprite;
        }

        const nameSprite = entity.myObject3D.nameSprite;
        nameSprite.visible = true;
        nameSprite.position.y = isSneak ? 1.8 : 2.3;

        // --- BẮT ĐẦU PHẦN THÊM MỚI: LOGIC PHÓNG TO/THU NHỎ ---

        // Bước 1: Tính khoảng cách từ bạn đến đối thủ
        const distance = entity.myObject3D.position.distanceTo(camera.position);

      // Bước 2: Tính toán tỷ lệ (Multiplier) - ĐÃ ĐIỀU CHỈNH ĐỂ TO HƠN
        let scaleMultiplier = 1.0;
        if (espConfig.nameScaling) {
            // Giải thích các con số:
            // 10: Khoảng cách bắt đầu tính (mét)
            // 150: Khoảng cách tối đa để đạt độ phóng to lớn nhất (tăng từ 80 lên 150)
            // 0.5: Độ nhỏ khi ở gần
            // 6.0: Độ to cực đại khi ở xa (tăng từ 2.5 lên 6.0 - bạn có thể chỉnh số này to hơn nữa)

            const t = Math.max(0, Math.min(1, (distance - 10) / (150 - 10)));
            scaleMultiplier = 0.5 + (8.0 - 0.5) * t; // Thay 6.0 bằng 12.0 để to gấp đôi khi ở xa
        }

        // Bước 3: Áp dụng kích thước mới vào Sprite
        // Lưu ý: baseScale thường là 1.5 trong hàm makeTextSprite của bạn
        const finalScale = (nameSprite.baseScale || 1.5) * scaleMultiplier;
        nameSprite.scale.set(0.5 * nameSprite.initialRatio * finalScale, 0.5 * finalScale, 1);

        // --- KẾT THÚC PHẦN THÊM MỚI ---
    }
      // aimbot and line
      const pos = entity.myObject3D.position.clone();
      pos.y -= isSneak ? espConfig.sneakHeight : 0;
      // line
      if (espConfig.showLine === 2 || (espConfig.showLine === 1 && entity.ennemy)) {
        if (espConfig.rainbow) {
          color.setHSL(time % 2000 / 2000, 1, 0.5);
        } else if (entity.ennemy) {
          color.lerpColors(colors.ennemy, colors.player, pos.distanceTo(camera.position) / espConfig.ennemyDistance);
          color.a = .8;
        } else {
          color.set(colors.blue);
          color.a = .3;
        }
        linePositions.push(lineOrigin.x, lineOrigin.y, lineOrigin.z);
        pos.y += 1.25;
        linePositions.push(pos.x, pos.y, pos.z);
        pos.y -= 1.25;
        colorArray.push(color.r, color.g, color.b, color.a);
        colorArray.push(color.r, color.g, color.b, color.a);
      }
      pos.y += espConfig.heightLine;
      // aimbot
      if (shouldAimbot && (entity.ennemy || espConfig.allEnnemies)) {
        if (entity.playerName && window.ignoredPlayers.has(entity.playerName)) return;
        const distance = pos.distanceTo(camera.position);
        // Nếu tên người này nằm trong danh sách né, thì bỏ qua không nhắm
    if (entity.playerName && window.ignoredPlayers.has(entity.playerName)) return;
  // Lấy vị trí hiện tại
        let target = pos.clone();

      if (entity.velocity) {
            // Tăng số này nếu muốn đón đầu xa hơn (Trái/Phải)
            const leadFactor = 1.5;

            // 1. Lệch ngang (Trái/Phải/Tới/Lui)
            const horizontalLead = new THREE.Vector3(entity.velocity.x, 0, entity.velocity.z).multiplyScalar(leadFactor);
            target.add(horizontalLead);

            // 2. Ghì tâm khi nhảy (Lên/Xuống)
            if (entity.velocity.y > 0.01) {
              const pullDownStrength = 0.02; // THAY ĐỔI SỐ NÀY
              target.y -= pullDownStrength;
            }
        }
        const dummy = new THREE.PerspectiveCamera();
        setTransform(dummy, worldCamera, false);
        dummy.lookAt(target);
        const cameraVector = new THREE.Vector3(0, 0, -1).applyQuaternion(camera.quaternion);
        const targetVector = new THREE.Vector3(0, 0, -1).applyQuaternion(dummy.quaternion);
        const angleDifference = cameraVector.angleTo(targetVector);
        const currentMaxAngle = espConfig.unlimitedAngle ? Math.PI : espConfig.maxAngleInRadians;
        if (angleDifference < currentMaxAngle && angleDifference < aimbotTarget.angleDifference) {
          const directionV3 = new THREE.Vector3();
          directionV3.subVectors(target, camera.position).normalize();
          raycaster.set(camera.position, directionV3);
          let behindBlock = false;
          if (espConfig.aimbotIgnoreWall) {
            aimbotTarget.angleDifference = angleDifference;
            aimbotTarget.target = target;
          } else {
            for (const chunk of chunks) {
              if (raycaster.ray.intersectsBox(chunk.box)) {
                const hit = raycaster.intersectObject(chunk)[0];
                if (hit && hit.distance < distance) {
                  behindBlock = true;
                  break;
                }
              }
            }
            if (!behindBlock) {
              aimbotTarget.angleDifference = angleDifference;
              aimbotTarget.target = target;
              color.setHSL(time % 2000 / 2000, 1, 0.5);
            }
          }
        }
      }
    }
    // NEW: Handle items (non-player entities)
    else if (isItem(entity) && espConfig.showItems) {
      if (!entity.itemBox) {
        entity.itemBox = new THREE.Mesh(itemBoxGeometry, meshMats.item);
        entity.itemBox.frustumCulled = false;
        scene.add(entity.itemBox);

        // Create item name sprite if showItemNames is enabled
        if (espConfig.showItemNames) {
          // Try to get item name from canvas text
          let itemName = "Item";
          for (const child of entity[childrenKey]) {
            try {
              const matImage = child.material?.map?.image;
              if (matImage instanceof HTMLCanvasElement && matImage.hasOwnProperty('lastText')) {
                itemName = matImage.lastText || "Item";
                break;
              }
            } catch {}
          }
          entity.itemName = itemName;
          const itemSprite = createItemSprite(itemName, "#D4AF37");
          itemSprite.position.y = 0.5;
          entity.itemBox.add(itemSprite);
          entity.itemNameSprite = itemSprite;
        }
      }

      setTransform(entity.itemBox, entity, false);
      entity.itemBox.visible = true;

      // Update item name sprite visibility
      if (entity.itemNameSprite) {
        entity.itemNameSprite.visible = espConfig.showItemNames;
      }
    }
    // Hide item if showItems is false
    else if (entity.itemBox) {
      entity.itemBox.visible = false;
      if (entity.itemNameSprite) {
        entity.itemNameSprite.visible = false;
      }
    }
  });

  // aim at target
  if (espConfig.aimbot && shouldAimbot && aimbotTarget.target) {
    setTransform(dummyLookAt, worldCamera, false);
    dummyLookAt.lookAt(aimbotTarget.target);
    worldCamera.rotation.set(
      dummyLookAt.rotation.x,
      dummyLookAt.rotation.y,
      dummyLookAt.rotation.z
    );
  }
  // triggerbot
  const shouldTrigger = espConfig.triggerBot === 3 || (espConfig.triggerBot === 1 && isLeftClick) || (espConfig.triggerBot === 2 && isRightClick);
  if (shouldTrigger) {
    raycaster.set(camera.position, camera.getWorldDirection(new THREE.Vector3()));
    let hasHit = false;
    for (const entity of entities) {
      if (!entity.myObject3D?.visible) continue;
      if (entity.isPlayer && (entity.ennemy || espConfig.allEnnemies)) {
        const hit = raycaster.intersectObject(entity.myObject3D.playerMesh);
        if (hit.length) {
          hasHit = true;
          const distance = hit[0].distance;
          for (const chunk of chunks) {
            if (raycaster.ray.intersectsBox(chunk.box)) {
              const hitBlock = raycaster.intersectObject(chunk)[0];
              if (hitBlock && hitBlock.distance < distance) {
                hasHit = false;
                break;
              }
            }
          }
          if (hasHit) {
            break;
          }
        }
      }
    }
    setFiring(hasHit);
  } else {
    setFiring(false);
  }

  line.geometry.setAttribute('color', new THREE.Float32BufferAttribute(colorArray, 4));
  line.geometry.setAttribute('position', new THREE.Float32BufferAttribute(linePositions, 3));
  line.visible = espConfig.showLine;

  renderer.render(scene, camera);

  // minimap
  // make entities larger for minimap
  const scale = espConfig.mapZoom / 3;
  entities.forEach(entity => {
    if (entity.isPlayer) {
      entity.myObject3D.playerMesh.visible = false;
      entity.myObject3D.boxMesh.visible = false;
      entity.myObject3D.outline.visible = false;
      if (entity.myObject3D.nameSprite) entity.myObject3D.nameSprite.visible = false; // Ẩn tên trên minimap
      entity.myObject3D.playerMiniMap.visible = true;
      entity.myObject3D.playerMiniMap.scale.set(scale, 1, scale);
    }
    // Hide items on minimap
    if (entity.itemBox) {
      entity.itemBox.visible = false;
    }
  });
  if (worldCamera) {
    line.visible = false;
    crosshair.visible = false;
    // update orthographic camera based on espConfig.mapZoom
    minimapCamera.left = -espConfig.mapZoom;
    minimapCamera.right = espConfig.mapZoom;
    minimapCamera.top = espConfig.mapZoom;
    minimapCamera.bottom = -espConfig.mapZoom;

    // update position with camera position
    minimapCamera.position.copy(camera.position);
    minimapCamera.position.y += 50;
    minimapCamera.position.z += espConfig.mapOffsetZ;
    minimapCamera.rotation.y = camera.rotation.y;
    minimapCamera.updateProjectionMatrix();

    renderer.getViewport(saveViewport);
    renderer.getScissor(saveScissor);
    let saveScissorTest = renderer.getScissorTest();
    renderer.setViewport(minimapViewport);
    renderer.setScissor(minimapViewport);
    renderer.setScissorTest(true);

    renderer.render(scene, minimapCamera);

    renderer.setViewport(saveViewport);
    renderer.setScissor(saveScissor);
    renderer.setScissorTest(saveScissorTest);
  }
  entities.forEach(entity => {
    if (entity.isPlayer) {
      entity.myObject3D.playerMiniMap.visible = false;
    }
  });

  scene.children.forEach(child => {
    if (child.type === 'Object3D') {
      child.visible = false;
    }
  });
}

window.addEventListener('resize', () => {
  renderer.setSize( window.innerWidth, window.innerHeight );
});

// add style to header
style.innerHTML = `
#overlayCanvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 1000;
}
#lil-gui {
  position: absolute;
  top: 50%;
  right: 0;
  z-index: 1001;
  transform: translateY(-50%);
}
.lil-gui {
  --background-color: rgba(0, 0, 0, 0.5);
}
`;
guiStyle.innerHTML = `
.lil-gui {
	--title-background-color: #ff0019;
	--number-color: #00ff33;
}
`;
document.head.appendChild(style);
document.head.appendChild(guiStyle);

setInterval(() => {
  if (espConfig.antiAFK) {
    // Gửi sự kiện đè phím (keydown) cho cả 4 hướng cùng lúc
    // Không gửi sự kiện nhả phím (keyup) để mô phỏng việc giữ chặt
    document.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 87 })); // W
    document.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 67 })); // A
    document.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 70 })); // S
  }
}, 20); // Lặp lại mỗi 20ms (cực nhanh, không có độ trễ)


// wait for load
window.addEventListener('load', () => {
  console.log('Loaded');
  if (espConfig.autoClaimAds) {
    setTimeout(() => {
      claimAds();
    }, 500);
  }
});
// Logic điều khiển Sit Mode
setInterval(() => {
  if (espConfig.sit) {
    // Nhấn phím C (keyCode 67)
    document.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 67 }));

    // Nhả phím C sau 1ms để tạo vòng lặp nhấp nhả cực nhanh
    setTimeout(() => {
      document.dispatchEvent(new KeyboardEvent('keyup', { keyCode: 67 }));
    }, 5);
  }
}, 0); // Lặp lại toàn bộ quá trình sau 2ms



setInterval(() => {
    const radarContainer = document.getElementById('side-player-list');
    if (!radarContainer) return;
  // Cập nhật số lượng người chơi vào tiêu đề
const countElement = document.getElementById('radar-count');
if (countElement && window.playerMap) {
    countElement.innerText = window.playerMap.size;
}

    // KIỂM TRA LỆNH TỪ MENU/PHÍM TẮT
    if (!espConfig.showRadar) {
        radarContainer.style.display = 'none'; // Tắt bảng
        return;
    } else {
        radarContainer.style.display = 'block'; // Mở bảng
    }

    const content = document.getElementById('list-content');
    if (!content) return;

    if (!window.playerMap || window.playerMap.size === 0) {
        content.innerHTML = '<div style="color:#ffcc00; font-size:12px; font-weight:bold; text-align:center;">🔍 ĐANG QUÉT...</div>';
    } else {
        const sortedPlayers = Array.from(window.playerMap.entries())
            .map(([name, data]) => ({ name, ...data }))
            .sort((a, b) => a.dist - b.dist);

    let html = '';
sortedPlayers.forEach((p, index) => {
    const isSoldier = p.color === "#ff0000";
    const shadow = isSoldier
        ? "1px 1px 0px #000, -1px -1px 0px #000, 1px -1px 0px #000, -1px 1px 0px #000, 0px 0px 3px #ffffff"
        : "1px 1px 1px #000";

    const isIgnored = window.ignoredPlayers && window.ignoredPlayers.has(p.name);
    const btnColor = isIgnored ? "#00ff00" : "#555";
    const btnText = isIgnored ? "✔" : "+";

    // Đổi thành window.selectedPlayerIndex để phím tắt điều khiển được
    const isSelected = (index === window.selectedPlayerIndex);

    html += `
        <div class="player-row ${isSelected ? 'selected' : ''}" style="color:${p.color}; text-shadow: ${shadow};">
            <span style="width:25px; text-align:center; font-size:18px; margin-right:5px; flex-shrink:0;">${p.arrow || "•"}</span>
            <button onmousedown="window.handlePlayerAction('${p.name}')" style="pointer-events: auto; margin-right: 10px; background: ${btnColor}; color: white; border: 1px solid rgba(255,255,255,0.3); border-radius: 4px; width: 26px; height: 26px; cursor: pointer; font-size: 16px; font-weight: bold; flex-shrink: 0; display: flex; align-items: center; justify-content: center;">${btnText}</button>
            <span style="flex-grow:1; overflow:hidden; text-overflow:ellipsis; font-weight:900;">${p.name}</span>
            <span class="dist-text" style="margin-left:auto; color:#00ffff; font-weight:bold; font-size:12px;">${p.dist}m</span>
        </div>
    `;
});

        content.innerHTML = html;
    }
    if (window.playerMap) window.playerMap.clear();
}, 250);
// --- Tính năng Phím tắt Điều khiển ---
let selectedPlayerIndex = 0;

window.addEventListener('keydown', (e) => {
    // Lấy danh sách người chơi hiện tại từ giao diện (các button handlePlayerAction)
    const playerRows = document.querySelectorAll('#side-player-list div[style*="margin-bottom:6px"]');
    if (playerRows.length === 0) return;

    // Phím '[' : Di chuyển lên
    if (e.key === '[') {
        selectedPlayerIndex = (selectedPlayerIndex <= 0) ? playerRows.length - 1 : selectedPlayerIndex - 1;
        updateSelectionHighlight(playerRows);
    }

    // Phím ']' : Di chuyển xuống
    if (e.key === ']') {
        selectedPlayerIndex = (selectedPlayerIndex >= playerRows.length - 1) ? 0 : selectedPlayerIndex + 1;
        updateSelectionHighlight(playerRows);
    }

    // Phím '/' : Kích hoạt né/hủy né cho người chơi đang chọn
    if (e.key === '/') {
        const selectedRow = playerRows[selectedPlayerIndex];
        if (selectedRow) {
            const btn = selectedRow.querySelector('button');
            if (btn) btn.onmousedown(); // Kích hoạt sự kiện nhấn nút
        }
    }
});

// Khởi tạo biến toàn cục
window.selectedPlayerIndex = -1;
let hideTimer = null;

// Thêm CSS cho class "selected" và hiệu ứng nháy khi nhấn "/"
if (!document.getElementById('selection-style')) {
    const s = document.createElement('style');
    s.id = 'selection-style';
    s.innerHTML = `
        .player-row { border: 1.5px solid transparent; transition: all 0.1s; padding: 2px 5px; border-radius: 5px; }
        .player-row.selected { background: rgba(0, 255, 0, 0.2) !important; border-color: #00ff00 !important; box-shadow: 0 0 10px #00ff00; }
        .player-row.clicked { background: rgba(255, 255, 0, 0.5) !important; border-color: yellow !important; }
    `;
    document.head.appendChild(s);
}

window.onkeydown = function(e) {
    if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') return;

    const rows = document.querySelectorAll('.player-row');
    if (rows.length === 0) return;

    if (e.key === '[') { // Lên
        window.selectedPlayerIndex = (window.selectedPlayerIndex <= 0) ? rows.length - 1 : window.selectedPlayerIndex - 1;
        e.preventDefault();
    }
    else if (e.key === ']') { // Xuống
        window.selectedPlayerIndex = (window.selectedPlayerIndex >= rows.length - 1) ? 0 : window.selectedPlayerIndex + 1;
        e.preventDefault();
    }
    else if (e.key === '/') { // Chọn
        if (window.selectedPlayerIndex >= 0 && rows[window.selectedPlayerIndex]) {
            const row = rows[window.selectedPlayerIndex];
            const btn = row.querySelector('button');
            if (btn) btn.onmousedown();

            // Hiệu ứng nháy vàng khi nhấn / (để không bị chọn ngầm)
            row.classList.add('clicked');
            setTimeout(() => row.classList.remove('clicked'), 200);
        }
        e.preventDefault();
    } else {
        return;
    }

    // Tự động ẩn viền sau 1 giây
    clearTimeout(hideTimer);
    hideTimer = setTimeout(() => {
        window.selectedPlayerIndex = -1;
    }, 3000);
};// 1. Xử lý thả phím Z để ngừng Zoom
window.addEventListener('keyup', (e) => {
    const keyL = e.key.toLowerCase();

    // Kiểm tra: Nếu nhả phím zoom mặc định (Z)
    // HOẶC nhả phím F (khi tính năng Zoom phím F đang được bật trong menu)
    if (keyL === espConfig.zoomKey.toLowerCase() || (keyL === 'f' && espConfig.fZoomEnabled)) {
        espConfig.isZooming = false;

        // Cập nhật lại giao diện Menu (để nút "Đang Zoom" tự tắt đi)
        if (typeof gui !== 'undefined') {
            gui.controllersRecursive().forEach(c => c.updateDisplay());
        }
    }
});

// 2. KHẮC PHỤC LỖI: Chặn đổi vũ khí khi đang cuộn chuột để Zoom
window.addEventListener('wheel', (e) => {
    if (espConfig.isZooming) {
        // e.preventDefault() ở đây giúp chặn sự kiện mặc định (đổi vũ khí) của game
        e.preventDefault();

        if (e.deltaY < 0) {
            // Cuộn lên: Giảm FOV = Phóng to hơn
            espConfig.zoomLevel = Math.max(1, espConfig.zoomLevel - 3);
        } else {
            // Cuộn xuống: Tăng FOV = Nhìn rộng hơn
            espConfig.zoomLevel = Math.min(175, espConfig.zoomLevel + 3);
        }

        // Cập nhật con số trên Menu khi đang lăn chuột
        if (typeof gui !== 'undefined') {
            gui.controllersRecursive().forEach(c => {
                if (c.property === 'zoomLevel') c.updateDisplay();
            });
        }
    }
}, { passive: false }); // Cần passive: false để preventDefault hoạt động

// 3. Ghi đè FOV của Camera game
Object.defineProperty(Object.prototype, 'fov', {
    get: function() {
        // Nếu là Camera và người dùng đang giữ phím Z
        if (this.isPerspectiveCamera && espConfig.isZooming) {
            return espConfig.zoomLevel;
        }
        return this._fov;
    },
    set: function(v) {
        this._fov = v;
    },
    configurable: true
});