BALLISTIC Client+ | AIMBOT+ESP

Cheat mod for deadshot.io with, Chams, Aimbot, and Crosshair. All tested and working. 100% UNDETECTED

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         BALLISTIC Client+ | AIMBOT+ESP
// @description  Cheat mod for deadshot.io with, Chams, Aimbot, and Crosshair. All tested and working. 100% UNDETECTED
// @author       levifrsn63
// @match        *://*/*
// @license      Nigga University
// @run-at       document-start
// @version      3.2
// @namespace https://greasyfork.org/users/
// ==/UserScript==

(function() {
    'use strict';

    // ====================================
    // DISABLE AUTO-FULLSCREEN
    // ====================================
    const blockFullscreen = () => {
        if (Element.prototype.requestFullscreen) {
            Element.prototype.requestFullscreen = function() {
                return Promise.reject(new Error('Fullscreen blocked'));
            };
        }
        ['webkitRequestFullscreen', 'mozRequestFullScreen', 'msRequestFullscreen'].forEach(m => {
            if (Element.prototype[m]) Element.prototype[m] = function() { return Promise.reject(); };
        });
        document.addEventListener('fullscreenchange', (e) => {
            if (document.fullscreenElement) document.exitFullscreen();
        }, true);
    };
    blockFullscreen();

    // ====================================
    // CONFIG & STATE
    // ====================================
    const defaultConfig = {
        showCrosshair: true, crosshairColor: "#3645B5",
        crosshairSize: 6, rgbCrosshair: false, mobile: false,
        menuVisible: true, x: 20, y: 20,
        espMaster: true, esp: false, espType: 'corner', tracers: false, showClass: false,
        chams: false, chamsMode: 'additive', chamsColor: '#a855f7',
        aimbotEnabled: false, aimFov: 100, aimSensitivity: 1.0, aimPrediction: 2,
        crosshairDot: false
    };

    let config = { ...defaultConfig };
    const saved = localStorage.getItem("ballistic_config");
    if (saved) { try { config = { ...config, ...JSON.parse(saved) }; } catch (e) {} }
    function save() { localStorage.setItem("ballistic_config", JSON.stringify(config)); }

    const state = {
        detectedPlayers: [],
        viewProjMatrix: null,
        PLAYER_HISTORY: new Map(),
        PLAYER_VERTEX_SET: new Set([8829, 10392, 10944, 16413]),
        VERTEX_CLASS_MAP: { 8829: 'Shotgun', 10392: 'Assault Rifle', 10944: 'Sniper', 16413: 'SMG' },
        uniformCache: new Map(),
        activeTextureUnit: 0,
        textureUnitBindings: new Array(32).fill(null),
        textureDataMap: new WeakMap(),
        currentProgram: null,
        isDepthEnabled: false,
        currentTarget: null,
        isAiming: false,
        aimRemainderX: 0,
        aimRemainderY: 0,
        lastAimbotFrame: 0,
        cachedSPos: null
    };

    // Mobile spoof
    if (config.mobile) {
        const ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1";
        Object.defineProperties(navigator, {
            userAgent: { get: () => ua }, platform: { get: () => "iPhone" },
            maxTouchPoints: { get: () => 5 }, vendor: { get: () => "Apple Computer, Inc." }
        });
        window.ontouchstart = () => {};
    }

    // ====================================
    // AIMBOT LOGIC
    // ====================================
    const originalX = Object.getOwnPropertyDescriptor(MouseEvent.prototype, 'movementX').get;
    const originalY = Object.getOwnPropertyDescriptor(MouseEvent.prototype, 'movementY').get;

    const applyAimbot = (orig, isY) => {
        if (config.aimbotEnabled && state.isAiming && state.currentTarget) {
            const now = performance.now();
            if (now !== state.lastAimbotFrame) {
                state.cachedSPos = worldToScreen(state.currentTarget.position);
                state.lastAimbotFrame = now;
            }

            if (state.cachedSPos && Number.isFinite(state.cachedSPos[0]) && Number.isFinite(state.cachedSPos[1])) {
                const center = isY ? window.innerHeight / 2 : window.innerWidth / 2;
                const delta = (state.cachedSPos[isY ? 1 : 0] - center) * config.aimSensitivity;

                let total = delta + (isY ? state.aimRemainderY : state.aimRemainderX);
                let movement = Math.round(total);

                if (isY) state.aimRemainderY = total - movement;
                else state.aimRemainderX = total - movement;

                if (Number.isFinite(movement)) {
                    const MAX_SNAP = 120;
                    return Math.max(-MAX_SNAP, Math.min(MAX_SNAP, movement));
                }
            }
        } else {
            state.aimRemainderX = 0;
            state.aimRemainderY = 0;
        }
        return typeof orig === 'number' ? orig : 0;
    };

    Object.defineProperty(MouseEvent.prototype, 'movementX', { get: function () { return applyAimbot(originalX.call(this), false); } });
    Object.defineProperty(MouseEvent.prototype, 'movementY', { get: function () { return applyAimbot(originalY.call(this), true); } });

    window.addEventListener('mousedown', (e) => { if (e.button === 2) state.isAiming = true; });
    window.addEventListener('mouseup', (e) => { if (e.button === 2) state.isAiming = false; });

    // ====================================
    // UI SYSTEM
    // ====================================
    let leftPanel, rightPanel, contentArea, highlight, tabBar, arrow, clientText, featureList;
    let minimized = false, activeTab = 'Visuals', selectedIndex = 0;
    let savedESPStates = { esp: false, tracers: false, showClass: false, chams: false };

    const options = {
        Visuals: [
            { label: 'ESP', type: 'checkbox', key: 'espMastaer' },
            { label: 'Player Boxes', type: 'checkbox', key: 'esp' },
            { label: 'Box Type', type: 'select', key: 'espType', options: ['corner', 'normal', 'circle', 'diamond', 'cross'] },
            { label: 'Lines Color', type: 'color', key: 'lineColor' },
            { label: 'Snaplines', type: 'checkbox', key: 'tracers' },
            { label: 'Player Info', type: 'checkbox', key: 'showClass' },
            { label: 'Chams', type: 'checkbox', key: 'chams' },
            { label: 'Chams Mode', type: 'select', key: 'chamsMode', options: ['additive', 'wireframe', 'flat', 'darken', 'tint', 'hide'] },
            { label: 'Chams Color', type: 'color', key: 'chamsColor' }
        ],
        Aimbot: [
            { label: 'Aimbot', type: 'checkbox', key: 'aimbotEnabled' },
            { label: 'Aim FOV', type: 'slider', key: 'aimFov', min: 10, max: 1000, step: 10 },
            { label: 'Sensitivity', type: 'slider', key: 'aimSensitivity', min: 0.1, max: 2.5, step: 0.05 },
            { label: 'Prediction', type: 'slider', key: 'aimPrediction', min: 0, max: 2, step: 0.1 }
        ],
        Settings: [
            { label: 'Mobile Mode [M] (BETA)', type: 'checkbox', key: 'mobile' },
            { label: 'Crosshair Dot', type: 'checkbox', key: 'crosshairDot' },
            { label: 'Crosshair Size', type: 'slider', key: 'crosshairSize', min: 1, max: 20, step: 1 }
        ]
    };

    // ====================================
    // HELPER FUNCTIONS
    // ====================================
    const isDeadshotDomain = () => window.location.hostname.includes('deadshot.io');

    function multiplyMatrixVec4(m, x, y, z, w) {
        return [
            m[0] * x + m[4] * y + m[8] * z + m[12] * w,
            m[1] * x + m[5] * y + m[9] * z + m[13] * w,
            m[2] * x + m[6] * y + m[10] * z + m[14] * w,
            m[3] * x + m[7] * y + m[11] * z + m[15] * w
        ];
    }

    function worldToScreen(pos, overrideMatrix) {
        const m = overrideMatrix || state.viewProjMatrix;
        if (!m) return null;
        const clip = multiplyMatrixVec4(m, pos[0], pos[1], pos[2], 1);
        if (clip[3] <= 0.001) return null;
        return [
            (clip[0] / clip[3] + 1) * 0.5 * window.innerWidth,
            (1 - clip[1] / clip[3]) * 0.5 * window.innerHeight,
            clip[3]
        ];
    }

    function getCachedMatrices(program) {
        const cache = state.uniformCache.get(program);
        if (!cache) return { vp: null, model: null, boneUnit: null, opacity: 1.0, isEnemy: true };

        let vp = null, model = null, boneUnit = null, opacity = 1.0, isEnemy = false;
        for (const [name, val] of cache) {
            if (val?.length === 16) {
                if (val[11] !== 0 && Math.abs(val[15]) > 1.0) vp = val;
                else if (/modelMatrix/i.test(name)) model = val;
            } else if (name === 'boneTexture') boneUnit = val;
            else if (name === 'opacity') opacity = val;
            else if (typeof val === 'number') {
                const nameLower = name.toLowerCase();
                if (nameLower.includes('isenemy') && val === 1) isEnemy = true;
                else if (nameLower.includes('teamid') || nameLower.includes('team_id')) isEnemy = (val !== window._wxLocalTeam);
                else if (val === 1 && !['left', 'specMultMult', 'opacity'].includes(name) && name.length > 5) {
                    isEnemy = true;
                }
            }
        }
        return { vp, model, boneUnit, opacity, isEnemy };
    }

    function processDrawCall(gl, program, vertexCount) {
        const { vp, model, boneUnit, opacity, isEnemy } = getCachedMatrices(program);
        if (vp) state.viewProjMatrix = vp;

        const isPlayer = state.PLAYER_VERTEX_SET.has(vertexCount) || (boneUnit !== null && vertexCount > 3000);

        if (!model || !isPlayer || opacity < 0.1) return;

        let headPos = [model[12], model[13] + 0.6, model[14]];

        if (boneUnit !== null && state.textureUnitBindings[boneUnit]) {
            const boneData = state.textureDataMap.get(state.textureUnitBindings[boneUnit]);
            if (boneData?.length >= 23 * 16) {
                const b22 = 22 * 16;
                headPos = [boneData[b22 + 12], boneData[b22 + 13] + 0.6, boneData[b22 + 14]];
            }
        }

        if (!headPos.every(Number.isFinite)) return;

        const chestPos = [headPos[0], headPos[1] - 0.6 * 0.35, headPos[2]];

        const playerClass = state.VERTEX_CLASS_MAP[vertexCount] || 'Unknown';

        const playerKey = `${vertexCount}_${model[12].toFixed(1)}_${model[14].toFixed(1)}`;
        let finalHead = [...headPos];
        let finalChest = [...chestPos];

        const hist = state.PLAYER_HISTORY.get(playerKey) || { last: headPos, vel: [0, 0, 0], acc: [0, 0, 0], tick: Date.now(), enemyTick: 0, visTick: 0 };
        const now = Date.now();
        if (isEnemy) hist.enemyTick = now;
        if (state.isDepthEnabled) hist.visTick = now;

        if (!isEnemy && hist.enemyTick === 0) {
            state.PLAYER_HISTORY.set(playerKey, hist);
            return;
        }

        if (now - hist.enemyTick > 4000) {
            state.PLAYER_HISTORY.set(playerKey, hist);
            return;
        }

        let depth = 5;
        if (state.viewProjMatrix) {
            const clip = multiplyMatrixVec4(state.viewProjMatrix, headPos[0], headPos[1], headPos[2], 1);
            if (clip[3] > 0) depth = clip[3];
        }

        // Aimbot prediction logic from aimbot.js
        if (config.aimPrediction > 0) {
            const dt = (now - hist.tick) / 1000;
            if (dt > 0.008 && dt < 0.2) {
                const instVel = [(headPos[0] - hist.last[0]) / dt, (headPos[1] - hist.last[1]) / dt, (headPos[2] - hist.last[2]) / dt];
                hist.vel = hist.vel.map((v, i) => v * 0.7 + instVel[i] * 0.3);
                const lookAhead = 0.05 * config.aimPrediction;
                finalHead = headPos.map((v, i) => v + hist.vel[i] * lookAhead);
                finalChest = chestPos.map((v, i) => v + hist.vel[i] * lookAhead);
            }
        }

        if (finalHead.every(Number.isFinite)) {
            state.detectedPlayers.push({
                position: finalHead,
                bodyPos: finalChest,
                playerClass: playerClass,
                vertexCount: vertexCount,
                playerDepth: depth,
                playerKey: playerKey,
                isVisible: (hist.visTick === 0 || now - hist.visTick < 250),
                ctxProjMatrix: state.viewProjMatrix ? state.viewProjMatrix.slice() : null
            });
        }
        hist.last = headPos;
        hist.tick = now;
        state.PLAYER_HISTORY.set(playerKey, hist);
    }

    function drawChams(gl, mode, colorHex, originalArgs, originalDrawFunc) {
        if (mode === 'hide') return;

        const washEnabled = gl.isEnabled(gl.DEPTH_TEST);
        const wCull = gl.isEnabled(gl.CULL_FACE);
        const wBlend = gl.isEnabled(gl.BLEND);

        gl.disable(gl.CULL_FACE);
        if (!washEnabled) gl.enable(gl.DEPTH_TEST);
        gl.depthFunc(gl.ALWAYS);

        const r = parseInt(colorHex.slice(1, 3), 16) / 255;
        const g = parseInt(colorHex.slice(3, 5), 16) / 255;
        const b = parseInt(colorHex.slice(5, 7), 16) / 255;
        gl.blendColor(r, g, b, 1.0);
        if (!gl.isEnabled(gl.BLEND)) gl.enable(gl.BLEND);

        const primMode = mode === 'wireframe' ? gl.LINES : originalArgs[0];

        if (mode === 'flat') {
            gl.blendEquation(gl.FUNC_ADD);
            gl.blendFunc(gl.CONSTANT_COLOR, gl.ZERO);
        } else if (mode === 'darken') {
            gl.blendEquation(gl.FUNC_ADD);
            gl.blendFunc(gl.ZERO, gl.CONSTANT_COLOR);
        } else if (mode === 'additive' || mode === 'tint') {
            gl.blendEquation(gl.FUNC_ADD);
            gl.blendFuncSeparate(gl.CONSTANT_COLOR, gl.ONE, gl.SRC_ALPHA, gl.ONE);
        } else {
            gl.blendEquation(gl.FUNC_ADD);
            gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
        }

        const passes = (mode === 'additive') ? 3 : 1;
        for (let i = 0; i < passes; i++) {
            originalDrawFunc.apply(gl, [primMode, ...Array.prototype.slice.call(originalArgs, 1)]);
        }

        gl.depthFunc(gl.LEQUAL);
        if (wCull) gl.enable(gl.CULL_FACE);
        if (!washEnabled) gl.disable(gl.DEPTH_TEST);
        if (!wBlend) gl.disable(gl.BLEND);
        gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    }

    // ====================================
    // WEBGL HOOKS
    // ====================================
    const originalGetContext = HTMLCanvasElement.prototype.getContext;
    const proxyCache = new WeakMap();

    HTMLCanvasElement.prototype.getContext = new Proxy(HTMLCanvasElement.prototype.getContext, {
        apply(target, thisArgs, args) {
            const ctx = Reflect.apply(target, thisArgs, args);
            if (!ctx || (args[0] !== 'webgl' && args[0] !== 'webgl2')) return ctx;
            if (proxyCache.has(ctx)) return proxyCache.get(ctx);

            const handler = {
                get(target, prop) {
                    const val = target[prop];
                    if (typeof val === 'function') {
                        if (prop === 'enable') {
                            return function(...args) {
                                if (args[0] === 2929) state.isDepthEnabled = true;
                                return Reflect.apply(val, target, args);
                            };
                        }
                        if (prop === 'disable') {
                            return function(...args) {
                                if (args[0] === 2929) state.isDepthEnabled = false;
                                return Reflect.apply(val, target, args);
                            };
                        }
                        if (prop === 'useProgram') {
                            return function(program) {
                                state.currentProgram = program;
                                return Reflect.apply(val, target, arguments);
                            };
                        }
                        if (prop === 'getUniformLocation') {
                            return function(...args) {
                                const loc = Reflect.apply(val, target, args);
                                if (loc) loc._name = args[1];
                                return loc;
                            };
                        }
                        if (prop === 'activeTexture') {
                            return function(...args) {
                                state.activeTextureUnit = args[0] - target.TEXTURE0;
                                return Reflect.apply(val, target, args);
                            };
                        }
                        if (prop === 'bindTexture') {
                            return function(...args) {
                                if (args[0] === target.TEXTURE_2D) state.textureUnitBindings[state.activeTextureUnit] = args[1];
                                return Reflect.apply(val, target, args);
                            };
                        }
                        if (prop === 'texImage2D') {
                            return function(...args) {
                                const p = args[args.length - 1];
                                if (p instanceof Float32Array) {
                                    const tex = state.textureUnitBindings[state.activeTextureUnit];
                                    if (tex) state.textureDataMap.set(tex, p);
                                }
                                return Reflect.apply(val, target, args);
                            };
                        }
                        if (prop === 'uniformMatrix4fv' || prop === 'uniform1f' || prop === 'uniform1i') {
                            return function(...args) {
                                const loc = args[0];
                                if (state.currentProgram && loc?._name) {
                                    if (!state.uniformCache.has(state.currentProgram)) state.uniformCache.set(state.currentProgram, new Map());
                                    let val = args[1];

                                    if (prop === 'uniformMatrix4fv') {
                                        const name = loc._name;
                                        const mat = args[2];
                                        if (mat[11] !== 0 && Math.abs(mat[15]) > 1.0) {
                                            state.viewProjMatrix = mat.slice();
                                            val = state.viewProjMatrix;
                                        } else if (name.toLowerCase().includes('modelmatrix')) {
                                            val = mat.slice();
                                        } else {
                                            val = mat;
                                        }
                                    }
                                    state.uniformCache.get(state.currentProgram).set(loc._name, val);
                                }
                                return Reflect.apply(val, target, args);
                            };
                        }
                        if (prop === 'drawElements') {
                            return function(...args) {
                                const gl = target;
                                const vC = args[1];

                                if (state.currentProgram && vC > 1000) {
                                    try { processDrawCall(gl, state.currentProgram, vC); } catch(e) {}
                                }

                                if (config.chams && state.PLAYER_VERTEX_SET.has(vC)) {
                                    drawChams(gl, config.chamsMode, config.chamsColor, args, val);
                                    return;
                                }

                                return Reflect.apply(val, target, args);
                            };
                        }
                        return val.bind(target);
                    }
                    return val;
                }
            };
            const proxied = new Proxy(ctx, handler);
            proxyCache.set(ctx, proxied);
            return proxied;
        }
    });

    // ====================================
    // ESP CANVAS & RENDERING
    // ====================================
    let espCanvas, espCtx;

    function setupCanvas() {
        if (!isDeadshotDomain()) return;
        if (espCanvas) return;

        espCanvas = document.createElement('canvas');
        espCanvas.id = 'esp-overlay-canvas';
        espCanvas.style.cssText = "position:fixed;top:0;left:0;width:100%;height:100%;z-index:999999;pointer-events:none;";
        document.documentElement.appendChild(espCanvas);

        function updateCanvasSize() { espCanvas.width = window.innerWidth; espCanvas.height = window.innerHeight; }
        window.addEventListener('resize', updateCanvasSize);
        updateCanvasSize();
        espCtx = espCanvas.getContext('2d');

        function loop() { renderESP(); requestAnimationFrame(loop); }
        loop();
    }

    function renderESP() {
        if (!espCtx) return;
        const w = espCanvas.width, h = espCanvas.height;
        const cx = w / 2, cy = h / 2;
        espCtx.clearRect(0, 0, w, h);

        // Draw FOV circle for aimbot
        if (config.aimbotEnabled && config.aimFov > 0) {
            espCtx.beginPath();
            espCtx.arc(cx, cy, config.aimFov, 0, Math.PI * 2);
            espCtx.strokeStyle = 'rgba(168, 85, 247, 0.4)';
            espCtx.lineWidth = 1.5;
            espCtx.stroke();
        }

        // Draw crosshair dot
        if (config.crosshairDot) {
            espCtx.beginPath();
            espCtx.arc(cx, cy, config.crosshairSize, 0, Math.PI * 2);
            espCtx.fillStyle = config.crosshairColor || '#3645B5';
            espCtx.fill();
        }

        // Aimbot target selection
        if (config.aimbotEnabled) {
            let best = null, minDist = config.aimFov;
            state.detectedPlayers.forEach(p => {
                if (!p.position || !p.ctxProjMatrix) return;
                const sPos = worldToScreen(p.position, p.ctxProjMatrix);
                if (!sPos) return;
                const d = Math.hypot(sPos[0] - cx, sPos[1] - cy);
                if (d < minDist) { minDist = d; best = p; }
            });
            state.currentTarget = best;
        }

        state.detectedPlayers.forEach(p => {
            if (!p.position || !p.ctxProjMatrix) return;
            const headY = p.position[1];
            const feetY = headY - 2.3;

            // Project head and feet to screen space
            const top = worldToScreen([p.position[0], headY + 0.3, p.position[2]], p.ctxProjMatrix);
            const bot = worldToScreen([p.position[0], feetY, p.position[2]], p.ctxProjMatrix);
            if (!top || !bot) return;

            const boxH = Math.abs(bot[1] - top[1]);
            if (boxH < 5 || boxH > h * 2) return;
            const boxW = boxH * 0.6;
            const sx = top[0];
            const sy = Math.min(top[1], bot[1]);
            const depth = top[2];

            if (config.esp) {
                espCtx.strokeStyle = config.lineColor || '#a855f7';
                espCtx.lineWidth = 1.5;

                if (config.espType === 'corner') {
                    const cl = Math.min(boxW, boxH) * 0.25;
                    espCtx.beginPath();
                    espCtx.moveTo(sx - boxW / 2, sy + cl); espCtx.lineTo(sx - boxW / 2, sy); espCtx.lineTo(sx - boxW / 2 + cl, sy);
                    espCtx.moveTo(sx + boxW / 2 - cl, sy); espCtx.lineTo(sx + boxW / 2, sy); espCtx.lineTo(sx + boxW / 2, sy + cl);
                    espCtx.moveTo(sx + boxW / 2, sy + boxH - cl); espCtx.lineTo(sx + boxW / 2, sy + boxH); espCtx.lineTo(sx + boxW / 2 - cl, sy + boxH);
                    espCtx.moveTo(sx - boxW / 2 + cl, sy + boxH); espCtx.lineTo(sx - boxW / 2, sy + boxH); espCtx.lineTo(sx - boxW / 2, sy + boxH - cl);
                    espCtx.stroke();
                } else if (config.espType === 'normal') {
                    espCtx.strokeRect(sx - boxW / 2, sy, boxW, boxH);
                } else if (config.espType === 'circle') {
                    espCtx.beginPath();
                    espCtx.arc(sx, sy + boxH/2, boxW/2, 0, Math.PI * 2);
                    espCtx.stroke();
                } else if (config.espType === 'diamond') {
                    espCtx.beginPath();
                    espCtx.moveTo(sx, sy);
                    espCtx.lineTo(sx + boxW/2, sy + boxH/2);
                    espCtx.lineTo(sx, sy + boxH);
                    espCtx.lineTo(sx - boxW/2, sy + boxH/2);
                    espCtx.closePath();
                    espCtx.stroke();
                } else if (config.espType === 'cross') {
                    espCtx.beginPath();
                    espCtx.moveTo(sx - boxW/2, sy);
                    espCtx.lineTo(sx + boxW/2, sy + boxH);
                    espCtx.moveTo(sx + boxW/2, sy);
                    espCtx.lineTo(sx - boxW/2, sy + boxH);
                    espCtx.stroke();
                }

                // Draw snaplines
                if (config.tracers) {
                    espCtx.strokeStyle = config.lineColor || '#a855f7';
                    espCtx.lineWidth = 1;
                    espCtx.beginPath();
                    espCtx.moveTo(cx, h);
                    espCtx.lineTo(sx, sy + boxH);
                    espCtx.stroke();
                }

                // Draw player info
                if (config.showClass) {
                    espCtx.fillStyle = 'white';
                    espCtx.font = 'bold 10px Consolas, monospace';
                    espCtx.textAlign = 'center';
                    espCtx.fillText(p.playerClass.toUpperCase(), sx, sy - 6);
                    espCtx.fillStyle = 'white';
                    espCtx.font = 'bold 14px Consolas, monospace';
                    espCtx.textAlign = 'left';
                    espCtx.fillText(Math.round(depth) + 'm', sx + boxW / 2 + 5, sy + boxH / 2);
                }
            }
        });

        state.detectedPlayers.length = 0;

        if (state.PLAYER_HISTORY.size > 50) {
            const now = Date.now();
            for (const [id, data] of state.PLAYER_HISTORY) {
                if (now - data.tick > 2000) state.PLAYER_HISTORY.delete(id);
            }
        }
    }

    // ====================================
    // UI FUNCTIONS
    // ====================================

    // Style definitions
    const UI_STYLES = {
        panel: {
            position: 'fixed', width: '320px', background: '#2b2b2b', color: '#f1f1f1',
            fontFamily: 'Consolas, monospace', zIndex: 99999, border: '1px solid #3a3a3a',
            boxShadow: '0 2px 8px rgba(0,0,0,0.5)', padding: '0', userSelect: 'none',
            transition: 'width 0.2s ease'
        },
        tabBar: { display: 'flex', borderBottom: '1px solid #3a3a3a', background: '#232323' },
        tab: (active) => ({
            flex: '1', padding: '8px 0', textAlign: 'center', cursor: 'pointer',
            background: active ? '#2b2b2b' : '#232323', borderRight: '1px solid #3a3a3a',
            fontSize: '12px', fontWeight: '500', color: active ? '#ddd' : '#888',
            transition: 'color 0.2s'
        }),
        content: {
            padding: '10px', fontSize: '12px', lineHeight: '1.4', background: '#2b2b2b',
            position: 'relative', overflow: 'hidden', maxHeight: '500px', overflowY: 'auto'
        },
        highlight: {
            position: 'absolute', left: '6px', width: 'calc(100% - 12px)', height: '28px',
            background: 'rgba(54, 69, 181, 0.2)', transition: 'top 0.2s ease', pointerEvents: 'none'
        },
        row: {
            marginBottom: '4px', display: 'flex', alignItems: 'center',
            padding: '4px 6px 4px 8px', position: 'relative', cursor: 'pointer',
            minHeight: '28px', borderLeft: '2px solid transparent',
            transition: 'border-left 0.2s ease'
        }
    };

    // Helper: Create element with styles
    function createEl(tag, styles = {}, text = '') {
        const el = document.createElement(tag);
        if (text) el.textContent = text;
        Object.assign(el.style, styles);
        return el;
    }

    // Helper: Create checkbox row
    function createCheckbox(opt, index) {
        const isESPOption = ['esp', 'tracers', 'showClass', 'chams'].includes(opt.key);
        const isDisabled = !config.espMastaer && activeTab === 'Visuals' && opt.key !== 'espMastaer';
        const isChecked = config[opt.key];

        const row = createEl('div', {
            ...UI_STYLES.row,
            borderLeft: isChecked ? '2px solid #A5ACE4' : '2px solid transparent',
            opacity: isDisabled ? '0.4' : '1',
            cursor: isDisabled ? 'not-allowed' : 'pointer'
        });

        const box = createEl('div', {
            width: '12px', height: '12px', border: isDisabled ? '1px solid #333' : '1px solid #666', marginRight: '8px',
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            background: isChecked ? '#3645B5' : 'transparent', flexShrink: '0'
        });

        if (isChecked) {
            const check = createEl('span', { color: '#fff', fontSize: '9px', fontWeight: 'bold' }, '✓');
            box.appendChild(check);
        }

        const label = createEl('span', {
            color: isDisabled ? '#444' : (isChecked ? '#A5ACE4' : '#ddd'),
            fontSize: '12px', fontWeight: isChecked ? 'bold' : 'normal',
            transition: 'color 0.2s, font-weight 0.2s'
        }, opt.label);

        row.append(box, label);
        row.addEventListener('mouseenter', () => { if (!isDisabled) { selectedIndex = index; moveHighlight(); } });
        row.addEventListener('click', (e) => {
            if (isDisabled) return;
            e.stopPropagation();
            const newVal = !config[opt.key];
            config[opt.key] = newVal;

            if (opt.key === 'espMastaer') {
                if (newVal) {
                    // Restore saved states
                    config.esp = savedESPStates.esp;
                    config.tracers = savedESPStates.tracers;
                    config.showClass = savedESPStates.showClass;
                    config.chams = savedESPStates.chams;
                } else {
                    // Save current states and turn off
                    savedESPStates.esp = config.esp;
                    savedESPStates.tracers = config.tracers;
                    savedESPStates.showClass = config.showClass;
                    savedESPStates.chams = config.chams;
                    config.esp = false;
                    config.tracers = false;
                    config.showClass = false;
                    config.chams = false;
                }
            }

            save();
            renderContent();
            updateRightPanel();
        });
        return row;
    }

    // Helper: Create slider row
    function createSlider(opt, index) {
        const row = createEl('div', UI_STYLES.row);
        const label = createEl('span', { color: '#ddd', fontSize: '12px' }, opt.label);

        const container = createEl('div', { marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: '6px' });
        const slider = createEl('input');
        slider.type = 'range';
        slider.min = opt.min;
        slider.max = opt.max;
        slider.step = opt.step || 1;
        const scale = opt.scale || 1;
        slider.value = config[opt.key] / scale;
        Object.assign(slider.style, { width: '80px', accentColor: '#3645B5' });

        const valueLabel = createEl('span', { minWidth: '30px', fontSize: '11px', color: '#aaa' },
            Math.round(config[opt.key] * 100) / 100);

        slider.addEventListener('input', (e) => {
            e.stopPropagation();
            config[opt.key] = parseFloat(slider.value) * scale;
            valueLabel.textContent = Math.round(config[opt.key] * 100) / 100;
            save();
        });

        container.append(slider, valueLabel);
        row.append(label, container);
        row.addEventListener('mouseenter', () => { selectedIndex = index; moveHighlight(); });
        return row;
    }

    // Helper: Create color picker row
    function createColor(opt, index) {
        const isDisabled = !config.espMaster && activeTab === 'Visuals';

        const row = createEl('div', {
            ...UI_STYLES.row,
            opacity: isDisabled ? '0.4' : '1',
            cursor: isDisabled ? 'not-allowed' : 'pointer'
        });

        const label = createEl('span', {
            color: isDisabled ? '#444' : '#ddd',
            fontSize: '12px'
        }, opt.label);

        const input = createEl('input');
        input.type = 'color';
        input.value = config[opt.key];
        input.disabled = isDisabled;
        Object.assign(input.style, {
            marginLeft: 'auto', border: 'none', width: '30px', height: '20px',
            background: 'none', cursor: isDisabled ? 'not-allowed' : 'pointer'
        });

        input.addEventListener('input', (e) => {
            e.stopPropagation();
            config[opt.key] = input.value;
            save();
        });

        row.append(label, input);
        row.addEventListener('mouseenter', () => { if (!isDisabled) { selectedIndex = index; moveHighlight(); } });
        return row;
    }

    // Helper: Create select dropdown row
    function createSelect(opt, index) {
        const isDisabled = !config.espMaster && activeTab === 'Visuals';

        const row = createEl('div', {
            ...UI_STYLES.row,
            opacity: isDisabled ? '0.4' : '1',
            cursor: isDisabled ? 'not-allowed' : 'pointer'
        });

        const label = createEl('span', {
            color: isDisabled ? '#444' : '#ddd',
            fontSize: '12px'
        }, opt.label);

        const select = createEl('select');
        Object.assign(select.style, {
            marginLeft: 'auto', background: '#2b2b2b', border: isDisabled ? '1px solid #333' : '1px solid #3a3a3a',
            color: isDisabled ? '#444' : '#f1f1f1', padding: '4px 8px', borderRadius: '3px',
            fontSize: '11px', fontFamily: 'Consolas, monospace', outline: 'none',
            cursor: isDisabled ? 'not-allowed' : 'pointer'
        });
        select.disabled = isDisabled;

        opt.options.forEach(val => {
            const option = createEl('option', {}, val.charAt(0).toUpperCase() + val.slice(1));
            option.value = val;
            if (config[opt.key] === val) option.selected = true;
            select.appendChild(option);
        });

        select.addEventListener('change', (e) => {
            e.stopPropagation();
            config[opt.key] = select.value;
            save();
        });
        select.addEventListener('click', (e) => e.stopPropagation());

        row.append(label, select);
        row.addEventListener('mouseenter', () => { if (!isDisabled) { selectedIndex = index; moveHighlight(); } });
        return row;
    }

    function createUI() {
        if (!isDeadshotDomain()) return;
        if (document.getElementById('esp-eclipse-ui')) return;

        // Right panel (enabled features)
        rightPanel = createEl('div', {
            ...UI_STYLES.panel, right: '20px', width: '180px', display: config.menuVisible ? 'block' : 'none',
            background: 'transparent', border: 'none', boxShadow: 'none'
        });
        document.body.appendChild(rightPanel);

        featureList = createEl('div', { padding: '0', textAlign: 'right' });
        rightPanel.appendChild(featureList);

        // Left panel (main menu)
        leftPanel = createEl('div', { ...UI_STYLES.panel, id: 'esp-eclipse-ui', left: config.x + 'px', top: config.y + 'px' });
        leftPanel.style.display = config.menuVisible ? 'block' : 'none';
        document.body.appendChild(leftPanel);

        // Client text
        clientText = createEl('div', {
            position: 'absolute', bottom: '-25px', left: '0', color: '#888',
            fontFamily: 'Consolas, monospace', fontSize: '15px', fontStyle: 'italic',
            userSelect: 'none', transition: 'opacity 0.2s ease', opacity: config.menuVisible ? '1' : '0',
            whiteSpace: 'nowrap', pointerEvents: 'none'
        }, 'Ballistic Client');
        leftPanel.appendChild(clientText);

        // Minimize arrow
        arrow = createEl('div', {
            position: 'absolute', bottom: '-25px', left: '85px', cursor: 'pointer',
            fontWeight: 'bold', fontSize: '14px', userSelect: 'none', color: '#888',
            padding: '2px 4px', transition: 'left 0.2s ease', fontFamily: 'Consolas, monospace'
        }, '◀');
        arrow.addEventListener('mouseenter', () => arrow.style.color = '#aaa');
        arrow.addEventListener('mouseleave', () => arrow.style.color = '#888');
        arrow.addEventListener('click', () => toggleMinimize());
        leftPanel.appendChild(arrow);

        // Tab bar
        tabBar = createEl('div', UI_STYLES.tabBar);
        leftPanel.appendChild(tabBar);

        // Create tabs
        const tabs = ['Visuals', 'Aimbot', 'Settings'];
        const tabButtons = {};
        tabs.forEach(name => {
            const btn = createEl('div', UI_STYLES.tab(name === activeTab), name);
            btn.addEventListener('mouseenter', () => { if (activeTab !== name) btn.style.color = '#aaa'; });
            btn.addEventListener('mouseleave', () => { if (activeTab !== name) btn.style.color = '#888'; });
            btn.addEventListener('click', () => switchTab(name));
            tabBar.appendChild(btn);
            tabButtons[name] = btn;
        });

        // Tab switching functions
        window.switchTab = (name) => {
            activeTab = name;
            tabs.forEach(n => {
                const btn = tabButtons[n];
                const active = n === name;
                btn.style.background = active ? '#2b2b2b' : '#232323';
                btn.style.color = active ? '#ddd' : '#888';
            });
            renderContent();
        };

        window.toggleMinimize = () => {
            minimized = !minimized;
            config.menuVisible = !minimized;
            leftPanel.style.width = minimized ? '30px' : '320px';
            arrow.style.left = minimized ? '35px' : '85px';
            arrow.textContent = minimized ? '⚙' : '◀';
            arrow.style.fontSize = minimized ? '16px' : '14px';
            contentArea.style.display = minimized ? 'none' : 'block';
            tabBar.style.display = minimized ? 'none' : 'flex';
            clientText.style.opacity = minimized ? '0' : '1';
            rightPanel.style.display = config.menuVisible ? 'block' : 'none';
            save();
        };

        // Content area
        contentArea = createEl('div', UI_STYLES.content);
        leftPanel.appendChild(contentArea);

        // Initial render
        renderContent();
        updateRightPanel();
        setupDraggable();

        // Watch for external custom dropdown elements and remove them
        const observer = new MutationObserver(() => {
            document.querySelectorAll('.new-select2, .new-option, [class*="select2"]').forEach(el => el.remove());
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }

    function renderContent() {
        // Clear content and recreate highlight
        while (contentArea.firstChild) contentArea.removeChild(contentArea.firstChild);

        // Remove any external custom dropdown elements
        document.querySelectorAll('.new-select2, .new-option, [class*="select2"]').forEach(el => el.remove());

        highlight = createEl('div', UI_STYLES.highlight);
        contentArea.appendChild(highlight);

        // Render options using helper functions
        const handlers = { checkbox: createCheckbox, slider: createSlider, color: createColor, select: createSelect };
        options[activeTab].forEach((opt, i) => {
            const row = handlers[opt.type](opt, i);
            contentArea.appendChild(row);
        });

        selectedIndex = 0;
        moveHighlight();
    }

    function moveHighlight() {
        const rows = Array.from(contentArea.children).filter(c => c !== highlight);
        if (rows[selectedIndex]) {
            highlight.style.top = rows[selectedIndex].offsetTop + 'px';
            highlight.style.height = rows[selectedIndex].offsetHeight + 'px';
        }
    }

    function updateRightPanel() {
        const activeFeatures = Object.values(options).flat()
            .filter(opt => opt.type === 'checkbox' && config[opt.key])
            .map(opt => opt.label.replace(/\s*\[.*?\]\s*/g, ''));

        featureList.innerHTML = '';
        activeFeatures.forEach(feature => {
            featureList.appendChild(createEl('div', {
                padding: '2px 0', marginBottom: '2px', color: '#a855f7', fontSize: '12px', fontWeight: 'bold'
            }, feature));
        });
    }

    function setupDraggable() {
        let isDragging = false, offsetX, offsetY;

        const start = (e) => {
            isDragging = true;
            offsetX = e.clientX - leftPanel.offsetLeft;
            offsetY = e.clientY - leftPanel.offsetTop;
            e.preventDefault();
        };

        tabBar.addEventListener('mousedown', start);
        leftPanel.addEventListener('mousedown', (e) => minimized && e.target === leftPanel && start(e));

        window.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            leftPanel.style.left = (e.clientX - offsetX) + 'px';
            leftPanel.style.top = (e.clientY - offsetY) + 'px';
            rightPanel.style.top = (e.clientY - offsetY) + 'px';
            config.x = e.clientX - offsetX;
            config.y = e.clientY - offsetY;
            save();
        });

        window.addEventListener('mouseup', () => isDragging = false);
    }

    // ====================================
    // KEYBOARD CONTROLS
    // ====================================
    window.addEventListener('keydown', (e) => {
        if (!isDeadshotDomain()) return;
        if (document.activeElement?.tagName === 'INPUT' || document.activeElement?.tagName === 'SELECT') return;

        if (e.code === 'Insert' || e.code === 'Delete' || e.code === 'KeyP' || (e.key === 'Shift' && e.location === 2)) {
            config.menuVisible = !config.menuVisible;
            if (leftPanel) leftPanel.style.display = config.menuVisible ? 'block' : 'none';
            if (rightPanel) rightPanel.style.display = config.menuVisible ? 'block' : 'none';
            if (clientText) clientText.style.opacity = config.menuVisible ? '1' : '0';
            save();
            e.preventDefault();
            e.stopPropagation();
        }
        if (e.code === 'KeyM') { config.mobile = !config.mobile; save(); renderContent(); }
    }, true);

    // ====================================
    // AD REMOVAL
    // ====================================
    function removeAds() {
        // Remove common ad elements
        const adSelectors = [
            'iframe[src*="ads"]',
            'iframe[src*="doubleclick"]',
            'iframe[src*="googlesyndication"]',
            'div[id*="ad"]',
            'div[class*="ad"]',
            'div[id*="banner"]',
            'div[class*="banner"]',
            '.ad-container',
            '.ad-banner',
            '.sidebar-ad',
            '#ad-sidebar',
            '.side-ad'
        ];

        adSelectors.forEach(selector => {
            document.querySelectorAll(selector).forEach(el => {
                el.style.display = 'none';
                el.remove();
            });
        });

        // Remove side panels that might be ads
        const sidePanels = document.querySelectorAll('aside, .sidebar, .side-panel');
        sidePanels.forEach(panel => {
            if (panel.offsetWidth > 50 && panel.offsetHeight > 50) {
                const rect = panel.getBoundingClientRect();
                // If it's on the left or right side of the screen
                if (rect.left < 100 || rect.right > window.innerWidth - 100) {
                    panel.style.display = 'none';
                }
            }
        });
    }

    // ====================================
    // INITIALIZE
    // ====================================
    function init() {
        if (!isDeadshotDomain()) return;
        createUI();
        setupCanvas();
        removeAds();
        // Run ad removal periodically
        setInterval(removeAds, 2000);
    }

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

})();