Destiny V2

Premium external overlay for Deadshot.io — Aimbot, ESP, Prediction, TriggerBot

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

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

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

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

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name         Destiny V2
// @namespace    http://tampermonkey.net/
// @version      2.5
// @description  Premium external overlay for Deadshot.io — Aimbot, ESP, Prediction, TriggerBot
// @match        *://*deadshot.io/*
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const defaultConfig = {
        aimbotEnabled: true,
        aimSmooth: 1.5,
        lockDist: 40,
        hitbox: 0,
        priority: 1,
        randomize: false,
        espEnabled: true,
        fov: 100,
        showFov: false,
        showCrosshair: false,
        menuKey: "Insert",
        accentColor: "#a855f7",
        menuVisible: true,
        x: 100,
        y: 100,
        predictionEnabled: true,
        predictionStrength: 2.0,
        velocityTracking: true,
        showDistance: true,
        showTracers: false,
        espThickness: 2,
        triggerBot: false,
        triggerDelay: 100,
        fovGradient: true,
        performanceMode: false,
        showFPS: true,
        showStats: true,
        antiAFK: false,
        aimKey: "RightClick",
        smoothCurve: "ease",
        targetLock: false,
        lockTime: 2000,
        visibilityCheck: true,
        blockFullscreen: false
    };

    let config = { ...defaultConfig };

    const saved = localStorage.getItem("destiny_v1_config");
    if (saved) {
        try { config = { ...config, ...JSON.parse(saved) }; } catch (e) {}
    }

    let _saveTimer = null;
    function save() {
        if (_saveTimer) clearTimeout(_saveTimer);
        _saveTimer = setTimeout(() => {
            localStorage.setItem("destiny_v1_config", JSON.stringify(config));
        }, 200);
    }
    function saveImmediate() {
        if (_saveTimer) clearTimeout(_saveTimer);
        localStorage.setItem("destiny_v1_config", JSON.stringify(config));
    }

    function setupFullscreenBlocker() {
        if (!config.blockFullscreen) return;
        const block = () => Promise.resolve();
        ['requestFullscreen','webkitRequestFullscreen','mozRequestFullScreen','msRequestFullscreen'].forEach(fn => {
            if (Element.prototype[fn]) Element.prototype[fn] = block;
        });
    }
    setupFullscreenBlocker();

    // =================================================================
    // TRACKING STATE
    // =================================================================
    const state = {
        targetID: -1,
        programCounter: 0,
        modelMatrices: [],
        vpMatrices: [],
        input: {left:false, right:false},
        accX: 0, accY: 0,
        lastPositions: new Map(),
        deadPositions: new Map(),
        velocities: new Map(),
        lockedTarget: null,
        lockStartTime: 0,
        fps: 0,
        frameCount: 0,
        lastFPSUpdate: Date.now(),
        totalTargets: 0,
        hitCount: 0,
        missCount: 0,
        recoilPattern: [],
        currentRecoilIndex: 0,
        lastMouseMove: Date.now(),
        lastTriggerFire: 0,
        overlayCtx: null
    };

    // =================================================================
    // GUI
    // =================================================================
    let currentTab = 'aimbot';

    const CSS = `
        #d-ui *{box-sizing:border-box;margin:0;padding:0}
        #d-ui{position:fixed;width:280px;background:#0c0c0f;border:1px solid #1e1e24;border-radius:10px;font-family:'Segoe UI',system-ui,sans-serif;color:#c8c8d0;z-index:2147483646;user-select:none;box-shadow:0 8px 32px rgba(0,0,0,.6);overflow:hidden}
        #d-ui .d-head{padding:10px 14px;cursor:move;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid #1e1e24;background:#0e0e12}
        #d-ui .d-brand{font-size:13px;font-weight:700;letter-spacing:1.5px;background:linear-gradient(135deg,${config.accentColor},${config.accentColor}99);-webkit-background-clip:text;-webkit-text-fill-color:transparent}
        #d-ui .d-ver{font-size:9px;color:#555;font-family:monospace}
        #d-ui .d-tabs{display:flex;gap:2px;padding:6px 10px;background:#0a0a0d;border-bottom:1px solid #1e1e24}
        #d-ui .d-tab{flex:1;text-align:center;padding:5px 0;font-size:10px;font-weight:600;letter-spacing:.5px;color:#555;cursor:pointer;border-radius:6px;transition:all .15s}
        #d-ui .d-tab:hover{color:#888;background:#151518}
        #d-ui .d-tab.active{color:${config.accentColor};background:#1a1a20}
        #d-ui .d-body{padding:10px 12px;max-height:380px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:#222 transparent}
        #d-ui .d-body::-webkit-scrollbar{width:3px}
        #d-ui .d-body::-webkit-scrollbar-thumb{background:#333;border-radius:3px}
        #d-ui .d-section{font-size:9px;font-weight:600;letter-spacing:1px;color:#444;text-transform:uppercase;margin:10px 0 6px;padding-bottom:4px;border-bottom:1px solid #1a1a1e}
        #d-ui .d-section:first-child{margin-top:2px}
        #d-ui .d-row{display:flex;align-items:center;justify-content:space-between;padding:5px 0}
        #d-ui .d-row span{font-size:11px;color:#aaa}
        #d-ui .d-toggle{position:relative;width:32px;height:16px;cursor:pointer;display:inline-block;flex-shrink:0}
        #d-ui .d-toggle input{opacity:0;width:0;height:0;position:absolute}
        #d-ui .d-toggle .slider{position:absolute;inset:0;background:#222;border-radius:10px;transition:all .2s}
        #d-ui .d-toggle .slider:before{content:'';position:absolute;width:12px;height:12px;left:2px;top:2px;background:#555;border-radius:50%;transition:all .2s}
        #d-ui .d-toggle input:checked+.slider{background:${config.accentColor}30}
        #d-ui .d-toggle input:checked+.slider:before{transform:translateX(16px);background:${config.accentColor}}
        #d-ui .d-slider-row{padding:4px 0}
        #d-ui .d-slider-label{display:flex;justify-content:space-between;font-size:10px;color:#666;margin-bottom:3px}
        #d-ui .d-slider-label span:last-child{color:#aaa;font-family:monospace;font-size:10px}
        #d-ui input[type=range]{-webkit-appearance:none;width:100%;height:3px;background:#1e1e24;border-radius:3px;outline:none}
        #d-ui input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:10px;height:10px;background:${config.accentColor};border-radius:50%;cursor:pointer;border:none}
        #d-ui select{width:100%;background:#141418;color:#aaa;border:1px solid #1e1e24;padding:5px 8px;border-radius:6px;font-size:10px;outline:none;cursor:pointer}
        #d-ui select:focus{border-color:${config.accentColor}40}
        #d-ui .d-select-row{padding:4px 0}
        #d-ui .d-select-label{font-size:10px;color:#666;margin-bottom:3px}
        #d-ui .d-btn{width:100%;padding:7px;background:#141418;color:${config.accentColor};border:1px solid #1e1e24;border-radius:6px;cursor:pointer;font-size:10px;font-weight:600;letter-spacing:.5px;transition:all .15s}
        #d-ui .d-btn:hover{background:#1a1a20;border-color:${config.accentColor}40}
        #d-ui .d-stat-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px;margin-top:4px}
        #d-ui .d-stat{background:#111114;border-radius:6px;padding:8px;text-align:center;border:1px solid #1a1a1e}
        #d-ui .d-stat-val{font-size:16px;font-weight:700;color:${config.accentColor};font-family:monospace}
        #d-ui .d-stat-lbl{font-size:8px;color:#555;text-transform:uppercase;letter-spacing:.5px;margin-top:2px}
        #d-ui .d-footer{padding:6px 12px;border-top:1px solid #1e1e24;display:flex;justify-content:space-between;align-items:center;background:#0a0a0d}
        #d-ui .d-footer span{font-size:9px;color:#333;font-family:monospace}
        #d-ui .d-id-bar{display:flex;align-items:center;gap:6px;background:#111114;border-radius:6px;padding:6px 10px;margin-top:6px;border:1px solid #1a1a1e}
        #d-ui .d-id-bar .lbl{font-size:9px;color:#555;text-transform:uppercase;letter-spacing:.5px}
        #d-ui .d-id-bar .val{font-size:14px;font-weight:700;color:${config.accentColor};font-family:monospace;min-width:24px;text-align:center}
        #d-ui .d-id-bar .hint{font-size:8px;color:#333;margin-left:auto;font-family:monospace}
    `;

    function toggle(id, label, checked) {
        return `<div class="d-row"><span>${label}</span><label class="d-toggle"><input type="checkbox" id="${id}" ${checked?'checked':''}><span class="slider"></span></label></div>`;
    }
    function slider(id, label, valId, val, min, max, step) {
        return `<div class="d-slider-row"><div class="d-slider-label"><span>${label}</span><span id="${valId}">${val}</span></div><input type="range" id="${id}" min="${min}" max="${max}" step="${step}" value="${val}"></div>`;
    }
    function selectBox(id, label, options, current) {
        const opts = options.map(o => `<option value="${o.v}" ${current===o.v?'selected':''}>${o.l}</option>`).join('');
        return `<div class="d-select-row"><div class="d-select-label">${label}</div><select id="${id}">${opts}</select></div>`;
    }

    function getTabContent() {
        if (currentTab === 'aimbot') {
            return `
                <div class="d-section">Targeting</div>
                ${toggle('chk-aim','Aimbot',config.aimbotEnabled)}
                ${slider('sld-smooth','Smoothing','val-smooth',config.aimSmooth,1,10,0.1)}
                ${toggle('chk-pred','Prediction',config.predictionEnabled)}
                ${slider('sld-pred','Pred. Strength','val-pred',config.predictionStrength,0.5,3,0.1)}
                <div style="display:flex;gap:6px;padding:4px 0">
                    <div style="flex:1">${selectBox('sel-bone','Hitbox',[{v:0,l:'Head'},{v:1,l:'Neck'},{v:2,l:'Body'}],config.hitbox)}</div>
                    <div style="flex:1">${selectBox('sel-prio','Priority',[{v:1,l:'Crosshair'},{v:0,l:'Distance'}],config.priority)}</div>
                </div>
                <div class="d-section">Automation</div>
                ${toggle('chk-trigger','TriggerBot',config.triggerBot)}
                ${toggle('chk-lock','Target Lock',config.targetLock)}
                <div class="d-id-bar">
                    <span class="lbl">Target ID</span>
                    <span class="val" id="id-disp">${state.targetID}</span>
                    <span class="hint">Arrow Keys</span>
                </div>
            `;
        } else if (currentTab === 'visuals') {
            return `
                <div class="d-section">ESP</div>
                ${toggle('chk-esp','Box ESP',config.espEnabled)}
                ${toggle('chk-dist','Distance',config.showDistance)}
                ${toggle('chk-tracers','Tracers',config.showTracers)}
                ${slider('sld-thick','Box Thickness','val-thick',config.espThickness,1,5,0.5)}
                <div class="d-section">Overlay</div>
                ${toggle('chk-fov','FOV Circle',config.showFov)}
                ${toggle('chk-gradient','FOV Gradient',config.fovGradient)}
                ${slider('sld-fov','FOV Radius','val-fov',config.fov,50,600,10)}
                ${toggle('chk-crosshair','Crosshair',config.showCrosshair)}
                ${toggle('chk-fps','Show FPS',config.showFPS)}
            `;
        } else if (currentTab === 'config') {
            return `
                <div class="d-section">Engine</div>
                ${toggle('chk-velocity','Velocity Tracking',config.velocityTracking)}
                ${toggle('chk-visibility','Visibility Check',config.visibilityCheck)}
                ${toggle('chk-perfmode','Performance Mode',config.performanceMode)}
                ${selectBox('sel-curve','Smooth Curve',[{v:'linear',l:'Linear'},{v:'ease',l:'Ease'},{v:'exponential',l:'Exponential'}],config.smoothCurve)}
                <div class="d-section">Misc</div>
                ${toggle('chk-afk','Anti-AFK',config.antiAFK)}
                ${toggle('chk-blockfs','Block Fullscreen',config.blockFullscreen)}
                <div class="d-section">Stats</div>
                <div class="d-stat-grid">
                    <div class="d-stat"><div class="d-stat-val" id="stat-fps">${state.fps}</div><div class="d-stat-lbl">FPS</div></div>
                    <div class="d-stat"><div class="d-stat-val" id="stat-targets">${state.totalTargets}</div><div class="d-stat-lbl">Targets</div></div>
                    <div class="d-stat"><div class="d-stat-val" id="stat-accuracy">${state.hitCount+state.missCount>0?Math.round(state.hitCount/(state.hitCount+state.missCount)*100):0}%</div><div class="d-stat-lbl">Accuracy</div></div>
                </div>
                <div style="margin-top:10px"><button class="d-btn" id="btn-reset">Reset All Settings</button></div>
            `;
        }
        return '';
    }

    function createGUI() {
        if (document.getElementById('d-ui')) return;

        const style = document.createElement('style');
        style.textContent = CSS;
        document.head.appendChild(style);

        const div = document.createElement('div');
        div.id = 'd-ui';
        div.style.top = config.y + 'px';
        div.style.left = config.x + 'px';
        div.style.display = config.menuVisible ? 'block' : 'none';

        div.innerHTML = `
            <div class="d-head" id="d-header">
                <span class="d-brand">DESTINY</span>
                <span class="d-ver">v2.3</span>
            </div>
            <div class="d-tabs">
                <div class="d-tab${currentTab==='aimbot'?' active':''}" data-tab="aimbot">AIMBOT</div>
                <div class="d-tab${currentTab==='visuals'?' active':''}" data-tab="visuals">VISUALS</div>
                <div class="d-tab${currentTab==='config'?' active':''}" data-tab="config">CONFIG</div>
            </div>
            <div class="d-body" id="tab-content">${getTabContent()}</div>
            <div class="d-footer"><span>INS to toggle</span><span>deadshot.io</span></div>
        `;

        document.body.appendChild(div);

        // Drag
        const header = document.getElementById('d-header');
        let dragging = false, ox, oy;
        header.onmousedown = e => { dragging=true; ox=e.clientX-div.offsetLeft; oy=e.clientY-div.offsetTop; e.preventDefault(); };
        window.addEventListener('mousemove', e => { if(dragging){const x=e.clientX-ox,y=e.clientY-oy;div.style.left=x+'px';div.style.top=y+'px';config.x=x;config.y=y;} });
        window.addEventListener('mouseup', () => { if(dragging) save(); dragging=false; });

        // Tabs
        div.querySelectorAll('.d-tab').forEach(btn => {
            btn.onclick = () => { currentTab = btn.dataset.tab; refreshGUI(); };
        });

        attachEventHandlers();
    }

    function refreshGUI() {
        const content = document.getElementById('tab-content');
        if (content) content.innerHTML = getTabContent();
        const ui = document.getElementById('d-ui');
        if (ui) {
            ui.querySelectorAll('.d-tab').forEach(btn => {
                btn.classList.toggle('active', btn.dataset.tab === currentTab);
                btn.onclick = () => { currentTab = btn.dataset.tab; refreshGUI(); };
            });
        }
        attachEventHandlers();
    }

    function attachEventHandlers() {
        const handlers = {
            'chk-aim': e => { config.aimbotEnabled = e.target.checked; save(); },
            'chk-esp': e => { config.espEnabled = e.target.checked; save(); },
            'chk-fov': e => { config.showFov = e.target.checked; save(); },
            'chk-crosshair': e => { config.showCrosshair = e.target.checked; save(); },
            'chk-pred': e => { config.predictionEnabled = e.target.checked; save(); },
            'chk-trigger': e => { config.triggerBot = e.target.checked; save(); },
            'chk-lock': e => { config.targetLock = e.target.checked; save(); },
            'chk-dist': e => { config.showDistance = e.target.checked; save(); },
            'chk-tracers': e => { config.showTracers = e.target.checked; save(); },
            'chk-gradient': e => { config.fovGradient = e.target.checked; save(); },
            'chk-velocity': e => { config.velocityTracking = e.target.checked; save(); },
            'chk-visibility': e => { config.visibilityCheck = e.target.checked; save(); },
            'chk-afk': e => { config.antiAFK = e.target.checked; save(); },
            'chk-blockfs': e => {
                config.blockFullscreen = e.target.checked;
                saveImmediate();
                if(confirm('Reload to apply fullscreen setting?')) location.reload();
            },
            'chk-fps': e => { config.showFPS = e.target.checked; save(); },
            'chk-perfmode': e => { config.performanceMode = e.target.checked; save(); },
            'sld-smooth': e => { config.aimSmooth = parseFloat(e.target.value); const el = document.getElementById('val-smooth'); if(el) el.innerText = config.aimSmooth; save(); },
            'sld-fov': e => { config.fov = parseInt(e.target.value); const el = document.getElementById('val-fov'); if(el) el.innerText = config.fov; save(); },
            'sld-pred': e => { config.predictionStrength = parseFloat(e.target.value); const el = document.getElementById('val-pred'); if(el) el.innerText = config.predictionStrength; save(); },
            'sld-thick': e => { config.espThickness = parseFloat(e.target.value); const el = document.getElementById('val-thick'); if(el) el.innerText = config.espThickness; save(); },
            'sel-prio': e => { config.priority = parseInt(e.target.value); save(); },
            'sel-bone': e => { config.hitbox = parseInt(e.target.value); save(); },
            'sel-curve': e => { config.smoothCurve = e.target.value; save(); },
            'btn-reset': () => {
                if(confirm('Reset all settings?')) {
                    config = {...defaultConfig};
                    saveImmediate();
                    refreshGUI();
                }
            }
        };

        Object.keys(handlers).forEach(id => {
            const el = document.getElementById(id);
            if (el) {
                if (el.tagName === 'INPUT' && el.type === 'range') el.oninput = handlers[id];
                else if (el.tagName === 'BUTTON') el.onclick = handlers[id];
                else if (el.tagName === 'INPUT' && el.type === 'checkbox') el.onclick = handlers[id];
                else el.onchange = handlers[id];
            }
        });
    }

    // =================================================================
    // KEYBOARD
    // =================================================================
    document.addEventListener('keydown', (e) => {
        if (e.code === 'Insert' || e.code === 'Delete') {
            config.menuVisible = !config.menuVisible;
            const el = document.getElementById('d-ui');
            if (el) el.style.display = config.menuVisible ? 'block' : 'none';
            saveImmediate();
            e.preventDefault();
            e.stopImmediatePropagation();
        }
        if (e.code === 'ArrowRight') {
            state.targetID++;
            updateID();
            e.preventDefault();
            e.stopImmediatePropagation();
        }
        if (e.code === 'ArrowLeft') {
            state.targetID--;
            updateID();
            e.preventDefault();
            e.stopImmediatePropagation();
        }
    }, true);

    function updateID() {
        state.modelMatrices = [];
        const el = document.getElementById('id-disp');
        if (el) el.innerText = state.targetID;
    }

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

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

    function spoof(fake, real) {
        Object.defineProperty(fake, 'name', { value: real.name, configurable: true });
        Object.defineProperty(fake, 'toString', { value: () => real.toString(), configurable: true });
        return fake;
    }

    HTMLCanvasElement.prototype.getContext = spoof(function(type, options) {
        const ctx = originalGetContext.call(this, type, options);
        if (!ctx || (type !== 'webgl' && type !== '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 === 'uniformMatrix4fv') {
                        return function(location, transpose, value) {
                            if (value && value.length === 16) {
                                if (Math.abs(value[11] + 1) < 0.1 && Math.abs(value[15]) < 0.1) {
                                    if (state.vpMatrices.length > 3) state.vpMatrices.shift();
                                    state.vpMatrices.push(new Float32Array(value));
                                }
                                const gl = target;
                                const pid = programMap.get(gl.getParameter(gl.CURRENT_PROGRAM));
                                if (pid === state.targetID) {
                                    if (Math.abs(value[3]) < 1e-6 &&
                                        Math.abs(value[7]) < 1e-6 &&
                                        Math.abs(value[15] - 1) < 1e-6 &&
                                        state.modelMatrices.length < 100) {
                                        state.modelMatrices.push(new Float32Array(value));
                                    }
                                }
                            }
                            return val.apply(target, arguments);
                        }
                    }
                    if (prop === 'useProgram') {
                        return function(program) {
                            if (program && !programMap.has(program)) programMap.set(program, state.programCounter++);
                            return val.apply(target, arguments);
                        }
                    }
                    if (prop === 'drawElements') {
                        return function(mode, count, type, offset) {
                            const gl = target;
                            const pid = programMap.get(gl.getParameter(gl.CURRENT_PROGRAM));
                            if (config.aimbotEnabled && config.espEnabled && pid === state.targetID) gl.disable(gl.DEPTH_TEST);
                            const res = val.apply(target, arguments);
                            if (config.aimbotEnabled && config.espEnabled && pid === state.targetID) gl.enable(gl.DEPTH_TEST);
                            return res;
                        }
                    }
                    return val.bind(target);
                }
                return val;
            }
        };
        const proxied = new Proxy(ctx, handler);
        proxyCache.set(ctx, proxied);
        return proxied;
    }, originalGetContext);

    function setupCanvas() {
        const canvas = document.createElement('canvas');
        canvas.id = 'destiny-overlay-canvas';
        canvas.style.cssText = "position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:2147483646;pointer-events:none;";
        document.body.appendChild(canvas);

        function updateCanvasSize() {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        }

        window.addEventListener('resize', updateCanvasSize);
        document.addEventListener('fullscreenchange', () => { setTimeout(updateCanvasSize, 100); });
        document.addEventListener('webkitfullscreenchange', () => { setTimeout(updateCanvasSize, 100); });

        updateCanvasSize();

        function loop() {
            render(canvas);
            requestAnimationFrame(loop);
        }
        loop();
        setInterval(createGUI, 2000);
    }

    function getBoneOffset() {
        let y = (config.hitbox === 0) ? 2.15 : (config.hitbox === 1) ? 1.5 : 0.8;
        if (config.randomize) y += (Math.random() - 0.5) * 0.15;
        return y;
    }

    function applySmoothCurve(value, curve) {
        if (curve === 'ease') {
            return value < 0.5
                ? 4 * value * value * value
                : 1 - Math.pow(-2 * value + 2, 3) / 2;
        } else if (curve === 'exponential') {
            return 1 - Math.pow(1 - value, 3);
        }
        return value;
    }

    function easeOutQuart(x) {
        return 1 - Math.pow(1 - x, 4);
    }

    function easeInOutCubic(x) {
        return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
    }

    function calculateVelocity(posKey, currentPos) {
        const last = state.lastPositions.get(posKey);
        const now = Date.now();
        if (last) {
            const dt = (now - last.time) / 1000;
            if (dt > 0.001 && dt < 0.5) {
                const vx = (currentPos.x - last.x) / dt;
                const vy = (currentPos.y - last.y) / dt;
                const vz = (currentPos.z - last.z) / dt;
                const prev = state.velocities.get(posKey);
                if (prev) {
                    const blend = 0.6;
                    state.velocities.set(posKey, {
                        vx: vx * blend + prev.vx * (1 - blend),
                        vy: vy * blend + prev.vy * (1 - blend),
                        vz: vz * blend + prev.vz * (1 - blend),
                        time: now
                    });
                } else {
                    state.velocities.set(posKey, {vx, vy, vz, time: now});
                }
            }
        }
        state.lastPositions.set(posKey, {x: currentPos.x, y: currentPos.y, z: currentPos.z, time: now});
    }

    function render(canvas) {
        if (!state.overlayCtx) state.overlayCtx = canvas.getContext('2d');
        const ctx = state.overlayCtx;
        const w = canvas.width;
        const h = canvas.height;
        const cx = w / 2;
        const cy = h / 2;

        ctx.clearRect(0, 0, w, h);

        state.frameCount++;
        const now = Date.now();
        const shouldUpdateStats = now - state.lastFPSUpdate > 1000;

        if (shouldUpdateStats) {
            state.fps = state.frameCount;
            state.frameCount = 0;
            state.lastFPSUpdate = now;

            if (config.menuVisible && currentTab === 'config') {
                const fpsEl = document.getElementById('stat-fps');
                const targetsEl = document.getElementById('stat-targets');
                const accuracyEl = document.getElementById('stat-accuracy');
                if (fpsEl) fpsEl.innerText = state.fps;
                if (targetsEl) targetsEl.innerText = state.totalTargets;
                if (accuracyEl) {
                    const total = state.hitCount + state.missCount;
                    accuracyEl.innerText = total > 0 ? Math.round(state.hitCount/total*100) + '%' : '0%';
                }
            }
        }

        if (config.showFPS) {
            ctx.font = 'bold 16px monospace';
            ctx.fillStyle = config.accentColor;
            ctx.fillText(`FPS: ${state.fps}`, 10, 30);
        }

        if (config.showCrosshair) {
            const s = 10, g = 4;
            ctx.strokeStyle = config.accentColor;
            ctx.lineWidth = 2;
            ctx.beginPath();
            ctx.moveTo(cx, cy - g - s); ctx.lineTo(cx, cy - g);
            ctx.moveTo(cx, cy + g);     ctx.lineTo(cx, cy + g + s);
            ctx.moveTo(cx - g - s, cy); ctx.lineTo(cx - g, cy);
            ctx.moveTo(cx + g, cy);     ctx.lineTo(cx + g + s, cy);
            ctx.stroke();
            ctx.fillStyle = config.accentColor;
            ctx.fillRect(cx - 1, cy - 1, 2, 2);
        }

        if (config.showFov) {
            ctx.beginPath();
            ctx.arc(cx, cy, config.fov, 0, Math.PI * 2);
            if (config.fovGradient && !config.performanceMode) {
                const gradient = ctx.createRadialGradient(cx, cy, 0, cx, cy, config.fov);
                gradient.addColorStop(0, 'transparent');
                gradient.addColorStop(0.8, 'transparent');
                gradient.addColorStop(1, config.accentColor + '40');
                ctx.fillStyle = gradient;
                ctx.fill();
            }
            ctx.strokeStyle = config.accentColor;
            ctx.lineWidth = 1.5;
            ctx.stroke();
        }

        if(state.modelMatrices.length > 50) state.modelMatrices.length = 0;
        if (state.vpMatrices.length === 0) return;

        const vp = state.vpMatrices[state.vpMatrices.length - 1];
        let bestTarget = null;
        let bestScore = Infinity;
        let bestLockData = null;
        state.totalTargets = 0;

        const processedPositions = [];
        const MIN_DISTANCE = 0.5;

        for (let i = 0; i < state.modelMatrices.length; i++) {
            const mat = state.modelMatrices[i];
            const wx = mat[12], wy = mat[13], wz = mat[14];

            let isDuplicate = false;
            for (const pos of processedPositions) {
                const dx = wx - pos.x;
                const dy = wy - pos.y;
                const dz = wz - pos.z;
                const distSq = dx*dx + dy*dy + dz*dz;
                if (distSq < MIN_DISTANCE * MIN_DISTANCE) {
                    isDuplicate = true;
                    break;
                }
            }
            if (isDuplicate) continue;

            if (processedPositions.length < 20) {
                processedPositions.push({x: wx, y: wy, z: wz});
            }

            const posKey = `${Math.round(wx*10)}_${Math.round(wy*10)}_${Math.round(wz*10)}`;

            if (config.velocityTracking && config.predictionEnabled) {
                calculateVelocity(posKey, {x: wx, y: wy, z: wz});
            }

            const boneY = getBoneOffset();
            const head = project(vp, wx, wy + boneY, wz, w, h);
            const foot = project(vp, wx, wy, wz, w, h);

            let targetX = wx, targetY = wy + boneY, targetZ = wz;
            if (config.predictionEnabled && config.velocityTracking) {
                const vel = state.velocities.get(posKey);
                if (vel && now - vel.time < 200) {
                    const predTime = config.predictionStrength * 0.016;
                    targetX += vel.vx * predTime;
                    targetY += vel.vy * predTime;
                    targetZ += vel.vz * predTime;
                }
            }

            if (!head || !foot) continue;
            const boxH = foot.y - head.y;
            const boxW = boxH * 0.6;

            if (boxH < 30 || boxH > 400 || boxW < 15 || boxW > 250) continue;

            const aspectRatio = boxW / boxH;
            if (aspectRatio < 0.3 || aspectRatio > 1.0) continue;

            if (head.x < -100 || head.x > w + 100 || head.y < -100 || head.y > h + 100) continue;

            const prevDeadTime = state.deadPositions.get(posKey);
            if (!prevDeadTime) {
                state.deadPositions.set(posKey, now);
            }

            state.totalTargets++;
            const dist3D = Math.sqrt(wx*wx + wy*wy + wz*wz);
            const dist2D = Math.hypot(head.x - cx, head.y - cy);

            if (config.espEnabled) {
                const skipAdvancedESP = config.performanceMode;
                const inFov = dist2D <= config.fov;

                const espColor = inFov ? config.accentColor : config.accentColor + '80';
                ctx.strokeStyle = espColor;
                ctx.lineWidth = config.espThickness;
                ctx.strokeRect(head.x - boxW / 2, head.y, boxW, boxH);

                if (!skipAdvancedESP) {
                    ctx.fillStyle = '#00ff00';
                    ctx.fillRect(head.x - boxW / 2 - 5, head.y, 2, boxH);
                }

                if (config.showDistance && !skipAdvancedESP) {
                    ctx.font = '11px monospace';
                    ctx.fillStyle = config.accentColor;
                    ctx.fillText(`${Math.round(dist3D)}m`, head.x, head.y - 5);
                }

                if (config.showTracers && !skipAdvancedESP) {
                    ctx.beginPath();
                    ctx.moveTo(cx, h);
                    ctx.lineTo(foot.x, foot.y);
                    ctx.strokeStyle = config.accentColor + '60';
                    ctx.lineWidth = 1;
                    ctx.stroke();
                }
            }

            if (dist2D > config.fov) continue;

            const isDead = prevDeadTime && now - prevDeadTime > 2000;
            if (isDead) continue;

            if (config.visibilityCheck) {
                if (head.w < 0.01 || head.w > 100) continue;
                const screenToWorldRatio = dist3D / (dist2D + 1);
                if (screenToWorldRatio > 50) continue;
                if (boxH < 20 || boxH > 500) continue;
            }

            let score = (config.priority === 1) ? dist2D : head.w;
            if (score < bestScore) {
                bestScore = score;
                const predictedHead = project(vp, targetX, targetY, targetZ, w, h);
                bestTarget = predictedHead || head;
                bestLockData = {wx, wy, wz, boneY, posKey};
            }
        }

        if (config.targetLock && bestLockData) {
            if (!state.lockedTarget) {
                state.lockedTarget = bestLockData;
                state.lockStartTime = now;
            } else if (now - state.lockStartTime > config.lockTime) {
                state.lockedTarget = null;
            }
        } else if (!config.targetLock) {
            state.lockedTarget = null;
        }

        let activeTarget = bestTarget;
        if (state.lockedTarget) {
            const lt = state.lockedTarget;
            let lx = lt.wx, ly = lt.wy + lt.boneY, lz = lt.wz;
            if (config.predictionEnabled && config.velocityTracking) {
                const vel = state.velocities.get(lt.posKey);
                if (vel && now - vel.time < 200) {
                    const predTime = config.predictionStrength * 0.016;
                    lx += vel.vx * predTime;
                    ly += vel.vy * predTime;
                    lz += vel.vz * predTime;
                }
            }
            const locked = project(vp, lx, ly, lz, w, h);
            if (locked) activeTarget = locked;
        }

        if (config.triggerBot && activeTarget) {
            const trigDx = activeTarget.x - cx;
            const trigDy = activeTarget.y - cy;
            const trigDist = Math.hypot(trigDx, trigDy);
            if (trigDist < 15 && now - state.lastTriggerFire > config.triggerDelay) {
                window.dispatchEvent(new MouseEvent('mousedown', { button: 0, bubbles: true }));
                setTimeout(() => {
                    window.dispatchEvent(new MouseEvent('mouseup', { button: 0, bubbles: true }));
                }, 50);
                state.lastTriggerFire = now;
            }
        }

        if (config.aimbotEnabled && activeTarget && (state.input.right || state.input.left)) {
            const dx = activeTarget.x - cx;
            const dy = activeTarget.y - cy;
            const dist = Math.hypot(dx, dy);

            const DEADZONE = 3;
            if (dist < DEADZONE) {
                state.accX *= 0.7;
                state.accY *= 0.7;
                return;
            }

            let smooth = config.aimSmooth;
            const distRatio = Math.min(1, dist / config.fov);

            if (dist < config.lockDist * 0.5) {
                smooth *= 2.5;
            } else if (dist < config.lockDist) {
                const closeRatio = (dist - config.lockDist * 0.5) / (config.lockDist * 0.5);
                smooth *= 1.5 + easeOutQuart(closeRatio);
            } else if (dist < config.lockDist * 2) {
                const midRatio = (dist - config.lockDist) / config.lockDist;
                smooth *= 1.0 + (0.5 * easeInOutCubic(midRatio));
            }

            const easedProgress = applySmoothCurve(distRatio, config.smoothCurve);
            smooth = smooth * (0.8 + easedProgress * 0.4);

            let tx = dx / smooth;
            let ty = dy / smooth;

            tx += state.accX * 0.85;
            ty += state.accY * 0.85;

            let mx = Math.round(tx);
            let my = Math.round(ty);

            state.accX = (tx - mx) * 0.9;
            state.accY = (ty - my) * 0.9;

            const moveAmount = Math.hypot(mx, my);
            if (moveAmount >= 1) {
                const speedFactor = Math.min(1, moveAmount / 20);
                const smoothFactor = 0.92 + (speedFactor * 0.06);

                const smoothedMx = Math.round(mx * smoothFactor);
                const smoothedMy = Math.round(my * smoothFactor);

                if (smoothedMx !== 0 || smoothedMy !== 0) {
                    window.dispatchEvent(new MouseEvent('mousemove', {
                        movementX: smoothedMx,
                        movementY: smoothedMy,
                        bubbles: true
                    }));
                    state.lastMouseMove = now;
                }
            }
        } else {
            state.accX *= 0.5;
            state.accY *= 0.5;
        }

        if (config.antiAFK && now - state.lastMouseMove > 60000) {
            window.dispatchEvent(new MouseEvent('mousemove', {movementX: 1, movementY: 0, bubbles: true}));
            state.lastMouseMove = now;
        }

        if (now % 5000 < 16) {
            const cutoffTime = now - 5000;
            for (const [key, pos] of state.lastPositions.entries()) {
                if (pos && pos.time < cutoffTime) {
                    state.lastPositions.delete(key);
                }
            }
            for (const [key, vel] of state.velocities.entries()) {
                if (vel.time < cutoffTime) {
                    state.velocities.delete(key);
                }
            }
            for (const [key, time] of state.deadPositions.entries()) {
                if (time < cutoffTime) {
                    state.deadPositions.delete(key);
                }
            }
        }

        state.modelMatrices.length = 0;
    }

    function project(vp, x, y, z, w, h) {
        const X = x*vp[0] + y*vp[4] + z*vp[8] + vp[12];
        const Y = x*vp[1] + y*vp[5] + z*vp[9] + vp[13];
        const W = x*vp[3] + y*vp[7] + z*vp[11] + vp[15];
        if (W < 0.1) return null;
        return { x: (X/W + 1) * w * 0.5, y: (-Y/W + 1) * h * 0.5, w: W };
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => { setupCanvas(); });
    } else {
        setupCanvas();
    }

})();