Limax Client[1.3]

Hud(RAlt): Ad Blocker, Auto Play(new kill mode auto-reconnect), ZoomHack, Tracers, SkinHack, and more functions!!!

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name        Limax Client[1.3]
// @namespace   Violentmonkey Scripts
// @match       *://limax.io/*
// @icon        https://limax.io/img/limax.ico
// @grant       GM_addStyle
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_deleteValue
// @grant       GM.getValue
// @grant       GM.setValue
// @grant       GM.deleteValue
// @grant       unsafeWindow
// @version     1.3
// @author      Drik
// @description Hud(RAlt): Ad Blocker, Auto Play(new kill mode auto-reconnect), ZoomHack, Tracers, SkinHack, and more functions!!!
// @run-at      document-idle
// @license     MIT
// ==/UserScript==

// version 1.2: new functions, ZoomHack, SkinHack
// version 1.3: new function(Skip Animations), fixed nickname save, fix bugs(tracers,esp draws), HUD update: added ping counter, Fixed time bug, Auto Play: added auto-reconnect function, Auto nick has been removed


(async function() {
    'use strict';

    const STORAGE_KEY = 'lt';

    const defaults = {
        visible: false,
        AdBlocker: false,
        BetterLeaderBoard: false,
        AutoPlay: false,
        AutoPlayKillMode: false,
        AutoReconnect: false,
        Tracers: false,
        ESP: false,
        SkipAnimations: false,
        HUD: false,
        Zoom: false,
        SkinHack: false,
        ToggleKey: 'AltRight',
        Theme: 'dark'
    };

    async function gmGet(key, def) {
        try {
            if (typeof GM_getValue === 'function') return GM_getValue(key, def);
            if (typeof GM === 'object' && typeof GM.getValue === 'function') return await GM.getValue(key, def);
        } catch (e) {}
        return def;
    }

    async function gmSet(key, val) {
        try {
            if (typeof GM_setValue === 'function') return GM_setValue(key, val);
            if (typeof GM === 'object' && typeof GM.setValue === 'function') return await GM.setValue(key, val);
        } catch (e) {}
    }

    async function gmDelete(key) {
        try {
            if (typeof GM_deleteValue === 'function') return GM_deleteValue(key);
            if (typeof GM === 'object' && typeof GM.deleteValue === 'function') return await GM.deleteValue(key);
        } catch (e) {}
    }

    const raw = await gmGet(STORAGE_KEY, null);
    let state = (() => {
        try {
            if (!raw) return Object.assign({}, defaults);
            const p = JSON.parse(raw);
            return Object.assign({}, defaults, p);
        } catch (e) {
            return Object.assign({}, defaults);
        }
    })();

    GM_addStyle(`
    @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700;800;900&display=swap');

    :root {
      --bg: rgba(18,18,20,0.95);
      --panel: linear-gradient(135deg, rgba(255,255,255,0.03), rgba(255,255,255,0.01));
      --accent: linear-gradient(90deg,#6ee7b7,#3b82f6);
      --muted: rgba(255,255,255,0.62);
      --shadow: 0 6px 24px rgba(2,6,23,0.6);
    }

    .theme-white {
      --bg: rgba(255,255,255,0.98);
      --panel: linear-gradient(135deg, rgba(255,255,255,0.9), rgba(250,250,255,0.85));
      --accent: linear-gradient(90deg,#fef3c7,#c7d2fe);
      --muted: rgba(12,34,56,0.6);
      --shadow: 0 8px 30px rgba(2,6,23,0.06);
    }

    #limax-toolbox {
      font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif !important;
      -webkit-font-smoothing: antialiased !important;
      -moz-osx-font-smoothing: grayscale !important;
      text-rendering: optimizeLegibility !important;
      position: fixed;
      right: 40px;
      top: 40px;
      width: 720px;
      max-width: calc(100% - 80px);
      z-index: 2147483647;
      border-radius: 12px;
      background: var(--bg);
      padding: 18px;
      box-shadow: var(--shadow);
      color: #e6eef8;
      display: none;
      backdrop-filter: blur(8px) saturate(120%);
      border: 1px solid rgba(255,255,255,0.03);
      line-height: 1.18;
    }

    #limax-toolbox, #limax-toolbox * { font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif !important; }

    #limax-toolbox.show { display:block; animation: dropIn 220ms cubic-bezier(.2,.9,.3,1); }
    @keyframes dropIn { from { transform: translateY(-8px) scale(.995); opacity: 0; } to { transform: translateY(0) scale(1); opacity: 1; } }

    .lt-header { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:12px; }
    .lt-title { display:flex; gap:12px; align-items:center; }
    .lt-logo { min-width:120px; height:44px; border-radius:10px; background:var(--accent); display:flex; align-items:center; justify-content:center; font-weight:800; color:#04263b; font-size:14px; padding:0 12px; }
    .lt-h1 { font-size:18px; font-weight:700; margin:0; color: var(--muted); }
    .lt-sub { font-size:12px; color:var(--muted); margin-top:2px; }

    .lt-grid { display:grid; grid-template-columns:1fr 1fr; gap:14px; }

    .lt-card { background:var(--panel); border-radius:10px; padding:12px; min-height:92px; display:flex; flex-direction:column; justify-content:space-between; transition: transform .12s, box-shadow .12s; border:1px solid rgba(0,0,0,0.03); color: var(--muted);}
    .lt-card:hover { transform: translateY(-4px); box-shadow: 0 10px 30px rgba(2,6,23,0.06); }
    .title-row { display:flex; justify-content:space-between; align-items:center; gap:8px; }
    .lt-card h3 { margin:0; font-size:14px; font-weight:700; color: inherit; }
    .lt-card p { margin:8px 0 0 0; font-size:12px; color:var(--muted); line-height:1.25; }

    .lt-switch { position:relative; width:56px; height:30px; border-radius:999px; background: rgba(255,255,255,0.06); display:flex; align-items:center; padding:4px; cursor:pointer; box-sizing:border-box; }
    .lt-switch.on { background: linear-gradient(90deg,#34d399,#3b82f6); box-shadow: 0 6px 18px rgba(59,130,246,0.18); }
    .lt-switch .knob { width:22px; height:22px; border-radius:50%; background:#fff; transform: translateX(0); transition: transform .14s; box-shadow: 0 6px 16px rgba(2,6,23,0.25); }
    .lt-switch.on .knob { transform: translateX(26px); }

    .lt-controls { margin-top:10px; display:flex; gap:10px; align-items:center; flex-wrap:wrap; }
    .lt-input { background: rgba(0,0,0,0.12); border: 1px solid rgba(255,255,255,0.04); color: #eaf6ff; padding:8px 10px; border-radius:8px; outline:none; min-width:160px; font-size:13px; }
    .lt-small { font-size:12px; color:var(--muted); }

    .lt-footer { margin-top:14px; display:flex; justify-content:space-between; align-items:center; gap:12px; }
    .lt-toggle-key { font-weight:700; font-size:12px; color:#cfefff; }
    .lt-footer .save { background: linear-gradient(90deg,#60a5fa,#7dd3fc); color:#04263b; border-radius:10px; padding:8px 12px; font-weight:700; cursor:pointer; border:none; }

    .lt-btn { padding:8px 10px; border-radius:8px; background: rgba(0,0,0,0.12); border:1px solid rgba(255,255,255,0.02); cursor:pointer; color:var(--muted); font-size:13px; }

    @media (max-width:780px) { #limax-toolbox{ right:16px; left:16px;} .lt-grid{grid-template-columns:1fr;} .lt-logo{min-width:96px;font-size:13px;padding:0 8px;} }
  `);

    const root = document.createElement('div');
    root.id = 'limax-toolbox';
    if (state.Theme === 'white') root.classList.add('theme-white');
    document.body.appendChild(root);

    let adIv = null;
    let lbIv = null;
    let trRunner = null;
    let espRunner = null;

    let hudRunner = null;

    let _arWasInGame = false;
    let _arFired = false;

    let _pingMs = -1;
    let _pingPending = false;
    let _pingSentAt = 0;
    let _lastPingTime = 0;
    let _hudSessionStart = 0;
    const _PING_IV = 0x7D0;

    const _NativeWS = unsafeWindow.WebSocket;
    const _nativeSend = _NativeWS.prototype.send;
    const _nativeAEL = _NativeWS.prototype.addEventListener;

    _NativeWS.prototype.send = function(data) {
        if (!_pingPending && typeof data === 'string' && performance.now() - _lastPingTime >= _PING_IV) {
            try {
                const p = JSON.parse(data);
                if (p[0] === 0) {
                    _pingPending = true;
                    _pingSentAt = performance.now();
                }
            } catch {}
        }
        return _nativeSend.call(this, data);
    };

    _NativeWS.prototype.addEventListener = function(type, fn, ...rest) {
        if (type === 'message') {
            const wrapped = function(e) {
                if (_pingPending && e.data instanceof ArrayBuffer) {
                    _pingMs = Math.round(performance.now() - _pingSentAt);
                    _pingPending = false;
                    _lastPingTime = performance.now();
                }
                return fn.call(this, e);
            };
            return _nativeAEL.call(this, type, wrapped, ...rest);
        }
        if (type === 'close' && this.url?.includes('limax')) {
            const wrapped = (e) => {
                fn.call(this, e);
                if (_arWasInGame && state.AutoReconnect) _arSchedule('socket.close');
            };
            return _nativeAEL.call(this, type, wrapped, ...rest);
        }
        return _nativeAEL.call(this, type, fn, ...rest);
    };

    const _onmsgDesc = Object.getOwnPropertyDescriptor(_NativeWS.prototype, 'onmessage');
    const _msgStore = new WeakMap();
    Object.defineProperty(_NativeWS.prototype, 'onmessage', {
        configurable: true,
        get() {
            return _msgStore.get(this) ?? null;
        },
        set(fn) {
            _msgStore.set(this, fn);
            if (typeof fn !== 'function') {
                _onmsgDesc?.set?.call(this, fn);
                return;
            }
            _onmsgDesc?.set?.call(this, function(e) {
                if (_pingPending && e.data instanceof ArrayBuffer) {
                    _pingMs = Math.round(performance.now() - _pingSentAt);
                    _pingPending = false;
                    _lastPingTime = performance.now();
                }
                return fn.call(this, e);
            });
        },
    });

    const _oncloseDesc = Object.getOwnPropertyDescriptor(_NativeWS.prototype, 'onclose');
    const _closeStore = new WeakMap();
    Object.defineProperty(_NativeWS.prototype, 'onclose', {
        configurable: true,
        get() {
            return _closeStore.get(this) ?? null;
        },
        set(fn) {
            _closeStore.set(this, fn);
            if (typeof fn !== 'function') {
                _oncloseDesc?.set?.call(this, fn);
                return;
            }
            _oncloseDesc?.set?.call(this, function(e) {
                fn.call(this, e);
                if (_arWasInGame && state.AutoReconnect && this.url?.includes('limax')) _arSchedule('onclose');
            });
        },
    });

    unsafeWindow.WebSocket = function(...args) {
        const ws = new _NativeWS(...args);
        if (ws.url?.includes('limax')) {
            ws.addEventListener('open', () => {
                _hudSessionStart = Date.now();
                _pingMs = -1;
                _pingPending = false;
            });
            ws.addEventListener('close', () => {
                _hudSessionStart = 0;
                _pingMs = -1;
                _pingPending = false;
            });
        }
        return ws;
    };
    unsafeWindow.WebSocket.prototype = _NativeWS.prototype;
    Object.assign(unsafeWindow.WebSocket, {
        CONNECTING: 0,
        OPEN: 1,
        CLOSING: 2,
        CLOSED: 3
    });

    function _arWaitAndStart(src) {
        if (_arFired || !_arWasInGame || unsafeWindow.game_is_show || unsafeWindow.wait_banner_rendering || typeof unsafeWindow.start !== 'function') return;
        if (unsafeWindow.disa_interface) {
            requestAnimationFrame(() => _arWaitAndStart(src));
            return;
        }
        _arFired = true;
        unsafeWindow.disa_interface = true;
        unsafeWindow.start();
    }

    function _arSchedule(src) {
        _arFired = false;
        requestAnimationFrame(() => requestAnimationFrame(() => _arWaitAndStart(src)));
    }

    function _hookQuitForAR() {
        if (typeof unsafeWindow.quit_game !== 'function') {
            requestAnimationFrame(_hookQuitForAR);
            return;
        }
        const orig = unsafeWindow.quit_game;
        unsafeWindow.quit_game = function() {
            orig.call(this);
            if (_arWasInGame && state.AutoReconnect) _arSchedule('quit_game');
        };
    }
    _hookQuitForAR();

    function _watchGameForAR() {
        let prev = false;

        function tick() {
            const cur = Boolean(unsafeWindow.game_is_show);
            if (cur && !prev) {
                _arWasInGame = true;
                _arFired = false;
            }
            prev = cur;
            requestAnimationFrame(tick);
        }
        requestAnimationFrame(tick);
    }
    _watchGameForAR();

    let _saOrigDisplay = null;
    let _saOrigQuit = null;
    let _saOrigSTO = null;
    let _saCssEl = null;

    function startSkipAnimations() {
        _saCssEl = document.createElement('style');
        _saCssEl.textContent = `*:not(#limax-toolbox):not(#limax-toolbox *):not(#logo):not(#logoi){transition:none!important;animation-duration:0.001ms!important;animation-delay:0ms!important;}`;
        document.head.appendChild(_saCssEl);

        _saOrigSTO = unsafeWindow.setTimeout;
        unsafeWindow.setTimeout = function(fn, delay, ...args) {
            if (typeof fn === 'function' && (fn.name === 'display_game' || fn === unsafeWindow.display_game)) return _saOrigSTO.call(unsafeWindow, fn, 0, ...args);
            return _saOrigSTO.call(unsafeWindow, fn, delay, ...args);
        };

        function patchSA() {
            if (typeof unsafeWindow.display_game !== 'function' || typeof unsafeWindow.quit_game !== 'function') {
                requestAnimationFrame(patchSA);
                return;
            }
            if (!_saOrigDisplay) {
                _saOrigDisplay = unsafeWindow.display_game;
                unsafeWindow.display_game = function() {
                    if (typeof unsafeWindow.opacity === 'number' && unsafeWindow.opacity > 0) unsafeWindow.opacity = 0;
                    return _saOrigDisplay.call(this);
                };
            }
            if (!_saOrigQuit) {
                _saOrigQuit = unsafeWindow.quit_game;
                unsafeWindow.quit_game = function() {
                    _saOrigQuit.call(this);
                    requestAnimationFrame(() => {
                        const playi = document.getElementById('playi');
                        if (playi && playi.src && playi.src.includes('.gif')) playi.src = playi.src.replace('.gif', '.png');
                    });
                };
            }
        }
        requestAnimationFrame(patchSA);
    }

    function stopSkipAnimations() {
        if (_saCssEl) {
            _saCssEl.remove();
            _saCssEl = null;
        }
        if (_saOrigSTO) {
            unsafeWindow.setTimeout = _saOrigSTO;
            _saOrigSTO = null;
        }
        if (_saOrigDisplay && unsafeWindow.display_game !== _saOrigDisplay) {
            unsafeWindow.display_game = _saOrigDisplay;
            _saOrigDisplay = null;
        }
        if (_saOrigQuit && unsafeWindow.quit_game !== _saOrigQuit) {
            unsafeWindow.quit_game = _saOrigQuit;
            _saOrigQuit = null;
        }
    }

    let zoomValue = 1.0;
    const ZOOM_MIN = 0.2;
    const ZOOM_MAX = 2.0;
    const ZOOM_STEP = 0.1;

    const _wDesc = Object.getOwnPropertyDescriptor(unsafeWindow, 'innerWidth') ||
        Object.getOwnPropertyDescriptor(Object.getPrototypeOf(unsafeWindow), 'innerWidth');
    const _hDesc = Object.getOwnPropertyDescriptor(unsafeWindow, 'innerHeight') ||
        Object.getOwnPropertyDescriptor(Object.getPrototypeOf(unsafeWindow), 'innerHeight');
    const _realW = () => _wDesc.get.call(unsafeWindow);
    const _realH = () => _hDesc.get.call(unsafeWindow);

    Object.defineProperty(unsafeWindow, 'innerWidth', {
        configurable: true,
        get: () => (state.Zoom && zoomValue !== 1.0) ? Math.round(_realW() / zoomValue) : _realW()
    });
    Object.defineProperty(unsafeWindow, 'innerHeight', {
        configurable: true,
        get: () => (state.Zoom && zoomValue !== 1.0) ? Math.round(_realH() / zoomValue) : _realH()
    });

    const _nativeGBCR = Element.prototype.getBoundingClientRect;
    Element.prototype.getBoundingClientRect = function() {
        if (!state.Zoom || this !== unsafeWindow.canvas || zoomValue === 1.0) return _nativeGBCR.call(this);
        return {
            left: 0,
            top: 0,
            right: _realW(),
            bottom: _realH(),
            width: _realW(),
            height: _realH(),
            x: 0,
            y: 0
        };
    };

    function _patchGetMousePos() {
        if (typeof unsafeWindow.getMousePos !== 'function') {
            requestAnimationFrame(_patchGetMousePos);
            return;
        }
        const _orig = unsafeWindow.getMousePos;
        unsafeWindow.getMousePos = function(canvas, e) {
            if (!state.Zoom || zoomValue === 1.0) return _orig(canvas, e);
            return {
                x: e.clientX / zoomValue,
                y: e.clientY / zoomValue
            };
        };
    }
    _patchGetMousePos();

    function _applyZoomCss() {
        const cvs = unsafeWindow.canvas;
        if (!cvs) return;
        if (!state.Zoom || zoomValue === 1.0) {
            cvs.style.transform = '';
            cvs.style.transformOrigin = '';
            cvs.style.position = '';
            cvs.style.left = '';
            cvs.style.top = '';
        } else {
            cvs.style.transformOrigin = 'top left';
            cvs.style.transform = `scale(${zoomValue})`;
            cvs.style.position = 'fixed';
            cvs.style.left = '0';
            cvs.style.top = '0';
        }
        unsafeWindow.dispatchEvent(new Event('resize'));
        _updateZoomLabel();
    }

    function _updateZoomLabel() {
        const lbl = document.getElementById('_zoom_label');
        if (lbl) lbl.textContent = `zoom: ${zoomValue.toFixed(1)}x`;
    }

    let _zoomWheelBound = false;

    function _bindZoomWheel() {
        if (_zoomWheelBound) return;
        _zoomWheelBound = true;
        window.addEventListener('wheel', (e) => {
            if (!state.Zoom || !e.ctrlKey) return;
            e.preventDefault();
            zoomValue = e.deltaY < 0 ?
                Math.min(ZOOM_MAX, +(zoomValue + ZOOM_STEP).toFixed(2)) :
                Math.max(ZOOM_MIN, +(zoomValue - ZOOM_STEP).toFixed(2));
            _applyZoomCss();
        }, {
            passive: false
        });
        window.addEventListener('keydown', (e) => {
            if (state.Zoom && e.ctrlKey && e.key === '0') {
                zoomValue = 1.0;
                _applyZoomCss();
            }
        });
    }

    const _SH_THEMES = ['c1', 'c2', 'c3', 'c4'];
    const _SH_TOTAL = 40;
    let _shVirtual = 0;
    let _shTheme = 'c2';
    let _shActive = false;
    let _shBtnL = null;
    let _shBtnR = null;
    const _origGetById = document.getElementById.bind(document);

    document.getElementById = function(id) {
        if (_shActive && typeof id === 'string' && id.startsWith('skin_')) {
            const parts = id.split('_');
            if (parts.length === 3) return _origGetById(`skin_${_shTheme}_${parts[2]}`) || _origGetById(id);
        }
        return _origGetById(id);
    };

    function _shRenderGrdbpi(slot, color) {
        const arr = [];
        for (let d = 1; d < 50; d++) {
            const f = document.createElement('canvas');
            f.width = d;
            f.height = d;
            const e = d / 2,
                l = Math.max(e - 2, 1);
            const ctx = f.getContext('2d');
            ctx.beginPath();
            ctx.globalAlpha = 0.1;
            ctx.arc(e, e, l, 0, Math.PI * 2);
            ctx.fillStyle = color;
            ctx.fill();
            ctx.globalAlpha = 1;
            ctx.beginPath();
            ctx.arc(e, e, l / 1.4, 0, Math.PI * 2);
            ctx.fillStyle = color;
            ctx.fill();
            arr.push(f);
        }
        unsafeWindow.txt_pck.grdbpi[slot] = arr;
    }

    function _shApply(v) {
        const win = unsafeWindow;
        const pack = Math.floor(v / 10);
        const slot = v % 10;
        const theme = _SH_THEMES[pack];
        _shTheme = theme;
        win.current_skin = slot;
        if (!win._sh_color_patched) {
            win.skin_color = [...win.pack_skin_color[1]];
            win._sh_color_patched = true;
        }
        const color = win.pack_skin_color[pack][slot];
        win.skin_color[slot] = color;
        win.skin_scale[slot] = win.pack_skin_scale[pack][slot];
        const img = _origGetById(`skin_${theme}_${slot}`);
        if (img) win.txt_pck.skin[slot] = img;
        _shRenderGrdbpi(slot, color);
        const names = {
            c1: 'Candy',
            c2: 'Space',
            c3: 'Ice',
            c4: 'Dark'
        };
        const lbl = _origGetById('_sh_label');
        if (lbl) lbl.textContent = `${names[theme]}  ·  ${slot + 1}/10  (${v + 1}/${_SH_TOTAL})`;
    }

    function _shWaitReady(fn) {
        const win = unsafeWindow;
        if (win.pack_skin_color && win.pack_skin_scale && win.skin_color && win.skin_scale && win.txt_pck?.skin && win.txt_pck?.grdbpi && _origGetById('select_left')) fn();
        else setTimeout(() => _shWaitReady(fn), 100);
    }

    function startSkinHack() {
        if (_shActive) return;
        _shActive = true;
        _shWaitReady(() => {
            _shVirtual = unsafeWindow.current_skin || 0;
            const btnL = _origGetById('select_left');
            const btnR = _origGetById('select_right');
            if (!btnL || !btnR) return;
            _shBtnL = btnL.cloneNode(true);
            _shBtnR = btnR.cloneNode(true);
            btnL.parentNode.replaceChild(_shBtnL, btnL);
            btnR.parentNode.replaceChild(_shBtnR, btnR);
            _shBtnL.addEventListener('click', () => {
                _shVirtual = (_shVirtual - 1 + _SH_TOTAL) % _SH_TOTAL;
                _shApply(_shVirtual);
            });
            _shBtnR.addEventListener('click', () => {
                _shVirtual = (_shVirtual + 1) % _SH_TOTAL;
                _shApply(_shVirtual);
            });
            _shApply(_shVirtual);
            if (!_origGetById('_sh_label')) {
                const lbl = document.createElement('div');
                lbl.id = '_sh_label';
                Object.assign(lbl.style, {
                    textAlign: 'center',
                    marginTop: '430px',
                    color: '#2fcc6e',
                    fontFamily: 'monospace',
                    fontSize: '11px',
                    letterSpacing: '1px',
                });
                const skinSel = _origGetById('select_skin');
                if (skinSel) skinSel.after(lbl);
            }
        });
    }

    function stopSkinHack() {
        _shActive = false;
        const lbl = _origGetById('_sh_label');
        if (lbl) lbl.remove();

        if (_shBtnL) {
            const origL = _shBtnL.cloneNode(true);
            origL.id = 'select_left';
            if (_shBtnL.parentNode) _shBtnL.parentNode.replaceChild(origL, _shBtnL);
            origL.onclick = function() {
                if (unsafeWindow.disa_interface) return;
                unsafeWindow.current_skin--;
                if (unsafeWindow.game_mode === unsafeWindow.TEAM_MODE && unsafeWindow.current_skin < 0) unsafeWindow.current_skin = 1;
                else if (unsafeWindow.current_skin < 0) unsafeWindow.current_skin = unsafeWindow.MAX_SKIN - 1;
            };
            _shBtnL = null;
        }
        if (_shBtnR) {
            const origR = _shBtnR.cloneNode(true);
            origR.id = 'select_right';
            if (_shBtnR.parentNode) _shBtnR.parentNode.replaceChild(origR, _shBtnR);
            origR.onclick = function() {
                if (unsafeWindow.disa_interface) return;
                unsafeWindow.current_skin++;
                if (unsafeWindow.game_mode === unsafeWindow.TEAM_MODE && unsafeWindow.current_skin >= 2) unsafeWindow.current_skin = 0;
                else if (unsafeWindow.current_skin >= unsafeWindow.MAX_SKIN) unsafeWindow.current_skin = 0;
            };
            _shBtnR = null;
        }
    }

    function adStart() {
        const S = ['#advert', '#vertad', '#crossPromotion'];
        const w = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window;
        const hide = el => {
            if (!el) return;
            try {
                el.style.setProperty('pointer-events', 'none', 'important');
                el.style.setProperty('opacity', '0', 'important');
                el.style.setProperty('visibility', 'hidden', 'important');
                el.style.setProperty('display', 'none', 'important');
            } catch (e) {}
        };
        const hideAll = () => S.forEach(sel => document.querySelectorAll(sel).forEach(hide));
        const patch = () => {
            try {
                hideAll();
                if (!w) return;
                w.wait_banner_rendering = 0;
                w.adinplay_counter = 0;
                w.ADINPLAY_LOOP = 1e9;
                if (w.Widget && typeof w.Widget === 'object') {
                    try {
                        w.Widget.preroll = function() {
                            try {
                                w.start && w.start();
                            } catch (e) {}
                        };
                    } catch (e) {}
                    try {
                        w.Widget.play = function() {
                            try {
                                w.start && w.start();
                            } catch (e) {}
                        };
                    } catch (e) {}
                    try {
                        w.Widget.adsRefresh = function() {};
                    } catch (e) {}
                    try {
                        w.Widget.refresh = function() {};
                    } catch (e) {}
                    try {
                        w.Widget.stop = function() {};
                    } catch (e) {}
                }
                const p = document.getElementById('play');
                if (p) p.onclick = function() {
                    try {
                        if (!w.disa_interface && w.wait_banner_rendering === 0) {
                            w.disa_interface = true;
                            w.start && w.start();
                        }
                    } catch (e) {}
                };
            } catch (e) {}
        };
        patch();
        adIv = setInterval(patch, 777);
    }

    function adStop() {
        if (adIv) {
            clearInterval(adIv);
            adIv = null;
        }
    }

    function lbStart() {
        const w = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window;

        function tick() {
            try {
                if (!w) return;
                const arr = Array.isArray(w.players) ? w.players.filter(p => p != null) : [];
                const map = {};
                arr.forEach(p => map[p.id] = p.score || 0);
                const cand = [];
                if (Array.isArray(w.players_nickname)) {
                    for (let i = 0; i < w.players_nickname.length; i++) {
                        const name = w.players_nickname[i];
                        if (name && name !== " ") cand.push({
                            id: i,
                            nickname: (typeof w.filterBadWords === 'function' ? w.filterBadWords(name) : name),
                            score: map[i] || 0
                        });
                    }
                }
                arr.forEach(p => {
                    if (!cand.find(x => x.id === p.id)) cand.push({
                        id: p.id,
                        nickname: (w.players_nickname && w.players_nickname[p.id]) ? (typeof w.filterBadWords === 'function' ? w.filterBadWords(w.players_nickname[p.id]) : w.players_nickname[p.id]) : " ",
                        score: p.score || 0
                    });
                });
                if (cand.length === 0) return;
                cand.sort((a, b) => b.score - a.score);
                const N = Math.min(10, cand.length);
                const top = {
                    nickname: [],
                    score: [],
                    id: [],
                    rank: "?",
                    total: cand.length
                };
                for (let i = 0; i < N; i++) {
                    top.nickname.push(cand[i].nickname);
                    top.score.push(cand[i].score);
                    top.id.push(cand[i].id);
                }
                const idx = cand.findIndex(x => x.id === w.true_id);
                if (idx >= 0) top.rank = idx + 1;
                if (typeof w.draw_leaderboard === 'function') w.draw_leaderboard(top);
                if (typeof w.draw_personal_info === 'function') w.draw_personal_info(top);
            } catch (e) {}
        }
        tick();
        lbIv = setInterval(tick, 150);
    }

    function lbStop() {
        if (lbIv) {
            clearInterval(lbIv);
            lbIv = null;
        }
    }

    function makeTracers() {
        let ctx = null,
            canvas = null,
            raf = null,
            lastPatched = null;

        function getCanvas() {
            return document.getElementById('myCanvas');
        }

        function safeHas(a, i) {
            return a && typeof a[i] !== 'undefined';
        }

        function hexToRgba(hex, a) {
            if (!hex) return 'rgba(255,255,255,' + a + ')';
            if (hex[0] === '#') hex = hex.slice(1);
            if (hex.length === 3) hex = hex.split('').map(c => c + c).join('');
            let r = parseInt(hex.slice(0, 2), 16);
            let g = parseInt(hex.slice(2, 4), 16);
            let b = parseInt(hex.slice(4, 6), 16);
            return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
        }

        function draw() {
            try {
                if (!state.Tracers) return;
                if (typeof players === 'undefined' || typeof players_show_pos === 'undefined') return;
                if (typeof id === 'undefined' || !players || !players[id]) return;
                let meIndex = players[id].id;
                if (typeof players_show_pos[meIndex] === 'undefined') return;
                canvas = canvas || getCanvas();
                if (!canvas) return;
                ctx = ctx || canvas.getContext('2d');
                let cam = {
                    x: canvas.width / 2 - players_show_pos[meIndex].x,
                    y: canvas.height / 2 - players_show_pos[meIndex].y
                };
                ctx.save();
                ctx.setTransform(1, 0, 0, 1, 0, 0);
                let ps = typeof player_scale !== 'undefined' && player_scale !== -1 ? player_scale : 1;
                ctx.scale(ps, ps);
                let offset = (ps - 1) / (2 * ps);
                ctx.translate(-canvas.width * offset, -canvas.height * offset);
                ctx.lineCap = 'round';
                ctx.lineJoin = 'round';
                for (let i = 0; i < players.length; i++) {
                    let p = players[i];
                    if (!p) continue;
                    let pid = p.id;
                    if (pid === meIndex) continue;
                    if (!safeHas(players_show_pos, pid)) continue;
                    if (safeHas(players_alpha, pid) && players_alpha[pid] <= 0) continue;
                    let sx = players_show_pos[pid].x + cam.x,
                        sy = players_show_pos[pid].y + cam.y;
                    let mx = players_show_pos[meIndex].x + cam.x,
                        my = players_show_pos[meIndex].y + cam.y;
                    let dx = sx - mx,
                        dy = sy - my,
                        dist = Math.hypot(dx, dy) || 1;
                    let baseW = Math.max(0.6, Math.min(2.2, 1.8 - dist * 0.004));
                    let skinIdx = safeHas(players_skin, pid) ? players_skin[pid] : 0;
                    let rawColor = (typeof skin_color !== 'undefined' && skin_color[skinIdx]) ? skin_color[skinIdx] : '#ffffff';
                    let alphaFactor = Math.min(1, (safeHas(players_alpha, pid) ? players_alpha[pid] / 100 : 1) * 0.95);
                    let glow = hexToRgba(rawColor, 0.12 * alphaFactor);
                    let coreS = hexToRgba(rawColor, 0.98 * alphaFactor);
                    let coreE = hexToRgba(rawColor, 0.36 * alphaFactor);
                    let gx = mx + dx * 0.5,
                        gy = my + dy * 0.5;
                    let nx = -dy,
                        ny = dx;
                    let nlen = Math.hypot(nx, ny) || 1;
                    nx /= nlen;
                    ny /= nlen;
                    let side = (pid % 2 === 0) ? 1 : -1;
                    let curve = Math.min(100, dist * 0.10);
                    let cx = gx + nx * curve * side,
                        cy = gy + ny * curve * side;
                    ctx.save();
                    ctx.shadowBlur = Math.max(5, baseW * 2.5);
                    ctx.shadowColor = glow;
                    ctx.lineWidth = baseW * 1.8;
                    ctx.beginPath();
                    ctx.moveTo(mx, my);
                    ctx.quadraticCurveTo(cx, cy, sx, sy);
                    ctx.strokeStyle = hexToRgba(rawColor, 0.20 * alphaFactor);
                    ctx.globalCompositeOperation = 'lighter';
                    ctx.stroke();
                    ctx.restore();
                    ctx.save();
                    let grad = ctx.createLinearGradient(mx, my, sx, sy);
                    grad.addColorStop(0, coreS);
                    grad.addColorStop(0.6, coreE);
                    grad.addColorStop(1, hexToRgba(rawColor, 0.06 * alphaFactor));
                    ctx.lineWidth = baseW;
                    ctx.beginPath();
                    ctx.moveTo(mx, my);
                    ctx.quadraticCurveTo(cx, cy, sx, sy);
                    ctx.strokeStyle = grad;
                    ctx.globalCompositeOperation = 'lighter';
                    ctx.stroke();
                    ctx.restore();
                    ctx.save();
                    let dotR = Math.max(2.5, Math.min(6, baseW * 1.1));
                    let rg = ctx.createRadialGradient(sx, sy, 0, sx, sy, dotR * 3);
                    rg.addColorStop(0, hexToRgba(rawColor, 0.98 * alphaFactor));
                    rg.addColorStop(0.3, hexToRgba(rawColor, 0.45 * alphaFactor));
                    rg.addColorStop(1, hexToRgba(rawColor, 0.0));
                    ctx.globalCompositeOperation = 'lighter';
                    ctx.beginPath();
                    ctx.fillStyle = rg;
                    ctx.arc(sx, sy, dotR * 1.8, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.beginPath();
                    ctx.fillStyle = hexToRgba('#ffffff', 0.85 * alphaFactor);
                    ctx.arc(sx - Math.min(2, dotR * 0.5), sy - Math.min(2, dotR * 0.5), Math.max(0.8, dotR * 0.45), 0, Math.PI * 2);
                    ctx.fill();
                    ctx.restore();
                }
                ctx.restore();
                ctx.globalAlpha = 1;
                ctx.globalCompositeOperation = 'source-over';
            } catch (e) {}
        }

        function loop() {
            if (!state.Tracers) {
                raf = null;
                return;
            }
            try {
                if (typeof unsafeWindow.animateGame === 'function' && unsafeWindow.animateGame !== lastPatched) {
                    const origAG = unsafeWindow.animateGame;
                    lastPatched = unsafeWindow.animateGame = function() {
                        const res = origAG.apply(this, arguments);
                        try {
                            draw();
                        } catch (e) {}
                        return res;
                    };
                }
                draw();
            } catch (e) {}
            raf = requestAnimationFrame(loop);
        }
        return {
            start: () => {
                if (!raf) loop();
            },
            stop: () => {
                if (raf) {
                    cancelAnimationFrame(raf);
                    raf = null;
                }
            }
        };
    }

    function makeESP() {
        let ctx = null,
            canvas = null,
            raf = null,
            prevPred = {};
        const MAX_TARGETS = 12,
            SMOOTH = 0.22,
            LEAD_MIN = 0.06,
            LEAD_MAX = 1.0,
            DIST_TO_LEAD = 600;

        function getCanvas() {
            return document.getElementById('myCanvas');
        }

        function safeHas(a, i) {
            return a && typeof a[i] !== 'undefined';
        }

        function hexToRgba(hex, a) {
            if (!hex) return 'rgba(255,255,255,' + a + ')';
            if (hex[0] === '#') hex = hex.slice(1);
            if (hex.length === 3) hex = hex.split('').map(c => c + c).join('');
            let r = parseInt(hex.slice(0, 2), 16);
            let g = parseInt(hex.slice(2, 4), 16);
            let b = parseInt(hex.slice(4, 6), 16);
            return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
        }

        function draw() {
            try {
                if (!state.ESP) return;
                if (typeof players === 'undefined' || typeof players_show_pos === 'undefined') return;
                if (typeof id === 'undefined' || !players || players === -1) return;
                if (!players[id]) return;
                let meNum = players[id].id;
                if (typeof players_show_pos[meNum] === 'undefined') return;
                canvas = canvas || getCanvas();
                if (!canvas) return;
                ctx = ctx || canvas.getContext('2d');
                ctx.save();
                ctx.setTransform(1, 0, 0, 1, 0, 0);
                let ps = (typeof player_scale !== 'undefined' && player_scale !== -1) ? player_scale : 1;
                ctx.scale(ps, ps);
                let offset = (ps - 1) / (2 * ps);
                ctx.translate(-canvas.width * offset, -canvas.height * offset);
                let cam = {
                    x: canvas.width / 2 - players_show_pos[meNum].x,
                    y: canvas.height / 2 - players_show_pos[meNum].y
                };
                let targets = [];
                for (let i = 0; i < players.length; i++) {
                    let p = players[i];
                    if (!p) continue;
                    let pid = p.id;
                    if (pid === meNum) continue;
                    if (!safeHas(players_show_pos, pid)) continue;
                    if (safeHas(players_alpha, pid) && players_alpha[pid] <= 0) continue;
                    let sx = players_show_pos[pid].x + cam.x,
                        sy = players_show_pos[pid].y + cam.y,
                        mx = players_show_pos[meNum].x + cam.x,
                        my = players_show_pos[meNum].y + cam.y;
                    let dx = sx - mx,
                        dy = sy - my,
                        dist = Math.hypot(dx, dy);
                    targets.push({
                        p,
                        dist,
                        px: sx,
                        py: sy
                    });
                }
                targets.sort((a, b) => a.dist - b.dist);
                targets = targets.slice(0, MAX_TARGETS);
                for (let t of targets) {
                    let p = t.p,
                        pid = p.id,
                        dist = t.dist;
                    let ang = (safeHas(players_angle, pid) ? players_angle[pid] : 0) + Math.PI;
                    let speed = safeHas(players_speed, pid) ? players_speed[pid] : 0;
                    let lead = Math.min(LEAD_MAX, Math.max(LEAD_MIN, dist / DIST_TO_LEAD));
                    let lx = players_show_pos[pid].x + Math.cos(ang) * speed * lead;
                    let ly = players_show_pos[pid].y + Math.sin(ang) * speed * lead;
                    if (!prevPred[pid]) prevPred[pid] = {
                        x: lx,
                        y: ly
                    };
                    prevPred[pid].x = prevPred[pid].x * (1 - SMOOTH) + lx * SMOOTH;
                    prevPred[pid].y = prevPred[pid].y * (1 - SMOOTH) + ly * SMOOTH;
                    let px = prevPred[pid].x + cam.x,
                        py = prevPred[pid].y + cam.y;
                    let size = Math.max(8, Math.min(48, (safeHas(players_radius, pid) ? players_radius[pid] : 12) * 0.95));
                    ctx.save();
                    ctx.globalCompositeOperation = 'lighter';
                    ctx.shadowBlur = Math.max(6, size * 1.8);
                    ctx.shadowColor = 'rgba(255,50,50,0.55)';
                    let g = ctx.createLinearGradient(px - size, py - size, px + size, py + size);
                    g.addColorStop(0, hexToRgba('#ff3b3b', 0.98));
                    g.addColorStop(0.6, hexToRgba('#ff6767', 0.42));
                    g.addColorStop(1, hexToRgba('#ff3b3b', 0.06));
                    ctx.fillStyle = g;
                    ctx.strokeStyle = hexToRgba('#ff1a1a', 0.98);
                    ctx.lineWidth = Math.max(1, size * 0.12);
                    ctx.beginPath();
                    ctx.rect(px - size, py - size, size * 2, size * 2);
                    ctx.fill();
                    ctx.stroke();
                    ctx.restore();
                    ctx.save();
                    ctx.beginPath();
                    ctx.globalAlpha = 0.92;
                    ctx.fillStyle = hexToRgba('#ffffff', 0.9);
                    ctx.arc(px - Math.min(3, size * 0.12), py - Math.min(3, size * 0.12), Math.max(1, size * 0.18), 0, Math.PI * 2);
                    ctx.fill();
                    ctx.restore();
                }
                ctx.restore();
                ctx.globalCompositeOperation = 'source-over';
            } catch (e) {}
        }

        function loop() {
            if (!state.ESP) {
                raf = null;
                return;
            }
            try {
                draw();
            } catch (e) {}
            raf = requestAnimationFrame(loop);
        }
        return {
            start: () => {
                if (!raf) loop();
            },
            stop: () => {
                if (raf) {
                    cancelAnimationFrame(raf);
                    raf = null;
                }
            }
        };
    }

    function injectBot() {
        try {
            if (unsafeWindow && unsafeWindow.AutoBot) return;
        } catch (e) {}
        const botSrc = "(" + (function() {
            try {
                var OrigWS = window.WebSocket;
                var sockRef = null;
                var enemyPositionHistory = [];
                var lastLoggedMyRadius = 0;

                function wrapSocket(url, protocols) {
                    var s = protocols ? new OrigWS(url, protocols) : new OrigWS(url);
                    try {
                        if ((url && url.indexOf("limax.io") !== -1) || (url && url.indexOf("127.0.0.1") !== -1)) sockRef = s;
                    } catch (e) {}
                    s.addEventListener("open", function() {
                        try {
                            var initialRadius = (window.players_radius && window.players_radius[window.true_id]) ? window.players_radius[window.true_id] : 25;
                            lastLoggedMyRadius = initialRadius;
                        } catch (e) {}
                    });
                    var origSend = s.send.bind(s);
                    s.send = function(data) {
                        return origSend(data);
                    };
                    s.addEventListener("close", function() {
                        if (sockRef === s) sockRef = null;
                    });
                    return s;
                }
                window.WebSocket = function(url, protocols) {
                    return wrapSocket(url, protocols);
                };
                window.WebSocket.prototype = OrigWS.prototype;
                var enabled = false;
                var loopIv = null;
                var RATE_MS = 16;
                var F_D = 300;
                var F_P = 700;
                var P_F = 2.3;
                var T_C = 10;
                var ltt = 0;
                var PBW = 6;
                var killMode = false;
                var KMS = 300;
                var K_R = 250;
                var KTS = 55;
                var KTSI = 10;
                var S_B = 200;
                var S_R_D = 200;
                var EST = 1777;
                var KCR = 148;
                var KTIM = 195;
                var KRTB = 24;
                var KTBS = 15;
                var KTBD = 13;
                var SER = 27;
                var MTR = 520;
                var MTMD = 380;
                var STW = 2.5;
                var kltp = 0;
                var DRIK_XD = Date.now();
                var leva = 0;

                function getMyPos() {
                    try {
                        if (typeof window.true_id === 'undefined' || window.true_id === -1) return null;
                        return (window.players_show_pos && window.players_show_pos[window.true_id]) ? window.players_show_pos[window.true_id] : null;
                    } catch (e) {
                        return null;
                    }
                }

                function getMyScore() {
                    try {
                        if (typeof window.id !== 'undefined' && window.players && window.players[window.id] && window.players[window.id].id === window.true_id) return window.players[window.id].score || 0;
                        if (window.players && Array.isArray(window.players)) {
                            for (var i = 0; i < window.players.length; i++) {
                                var p = window.players[i];
                                if (p && p.id === window.true_id) return p.score || 0;
                            }
                        }
                        return (typeof window.score !== 'undefined') ? window.score : 0;
                    } catch (e) {
                        return 0;
                    }
                }

                function getMyRadius() {
                    return (window.players_radius && window.players_radius[window.true_id]) ? window.players_radius[window.true_id] : 25;
                }

                function getPlayerRadius(pid) {
                    return (window.players_radius && window.players_radius[pid]) ? window.players_radius[pid] : 25;
                }

                function gatherTraps() {
                    var traps = [];
                    try {
                        var pt = window.players_trap || window.trap_map || [];
                        if (Array.isArray(pt)) {
                            for (var pid = 0; pid < pt.length; pid++) {
                                var arr = pt[pid];
                                if (!arr) continue;
                                for (var ti = 0; ti < arr.length; ti++) {
                                    var t = arr[ti];
                                    if (!t) continue;
                                    var tx = (typeof t.x !== 'undefined') ? t.x : ((typeof t.rx !== 'undefined') ? t.rx : 0);
                                    var ty = (typeof t.y !== 'undefined') ? t.y : ((typeof t.ry !== 'undefined') ? t.ry : 0);
                                    var tr = (typeof t.radius !== 'undefined') ? t.radius : ((typeof t.r !== 'undefined') ? t.r : (t.instRadius || 0));
                                    traps.push({
                                        x: tx,
                                        y: ty,
                                        r: tr,
                                        owner: pid,
                                        lifetime: (t.lifetime || 0)
                                    });
                                }
                            }
                        } else if (typeof pt === 'object') {
                            for (var k in pt) {
                                if (!pt.hasOwnProperty(k)) continue;
                                var list = pt[k];
                                if (!list) continue;
                                for (var j = 0; j < list.length; j++) {
                                    var t = list[j];
                                    if (!t) continue;
                                    var tx = (typeof t.x !== 'undefined') ? t.x : ((typeof t.rx !== 'undefined') ? t.rx : 0);
                                    var ty = (typeof t.y !== 'undefined') ? t.y : ((typeof t.ry !== 'undefined') ? t.ry : 0);
                                    var tr = (typeof t.radius !== 'undefined') ? t.radius : ((typeof t.r !== 'undefined') ? t.r : 0);
                                    traps.push({
                                        x: tx,
                                        y: ty,
                                        r: tr,
                                        owner: k,
                                        lifetime: (t.lifetime || 0)
                                    });
                                }
                            }
                        }
                    } catch (e) {}
                    return traps;
                }

                function distance(x1, y1, x2, y2) {
                    var dx = x1 - x2,
                        dy = y1 - y2;
                    return Math.sqrt(dx * dx + dy * dy);
                }

                function PJP(px, py, x1, y1, x2, y2) {
                    var Cx = x2 - x1,
                        Cy = y2 - y1;
                    var len_sq = Cx * Cx + Cy * Cy;
                    if (len_sq === 0) return 0;
                    return ((px - x1) * Cx + (py - y1) * Cy) / len_sq;
                }

                function PLD(px, py, x1, y1, x2, y2) {
                    var A = px - x1,
                        B = py - y1,
                        C = x2 - x1,
                        D = y2 - y1;
                    var dot = A * C + B * D;
                    var len_sq = C * C + D * D;
                    var param = -1;
                    if (len_sq !== 0) param = dot / len_sq;
                    var xx, yy;
                    if (param < 0) {
                        xx = x1;
                        yy = y1;
                    } else if (param > 1) {
                        xx = x2;
                        yy = y2;
                    } else {
                        xx = x1 + param * C;
                        yy = y1 + param * D;
                    }
                    var dx = px - xx,
                        dy = py - yy;
                    return Math.sqrt(dx * dx + dy * dy);
                }

                function TNP(traps, x, y, buf) {
                    buf = buf || 0;
                    for (var i = 0; i < traps.length; i++) {
                        var t = traps[i];
                        if (distance(t.x, t.y, x, y) <= (t.r || 0) + buf) return true;
                    }
                    return false;
                }

                function PIT(traps, x1, y1, x2, y2, excludeOwner) {
                    for (var i = 0; i < traps.length; i++) {
                        var t = traps[i];
                        if (typeof excludeOwner !== 'undefined' && t.owner == excludeOwner) continue;
                        var extra = (typeof window.true_id !== 'undefined' && t.owner != window.true_id) ? 30 : 0;
                        var d = PLD(t.x, t.y, x1, y1, x2, y2);
                        if (d <= (t.r || 0) + 14 + extra) return true;
                    }
                    return false;
                }

                function PlayerAndID() {
                    try {
                        var me = getMyPos();
                        if (!me || !window.players_show_pos || !window.players) return null;
                        var bestD = Infinity;
                        var bestId = null;
                        for (var i = 0; i < window.players.length; i++) {
                            var p = window.players[i];
                            if (!p || p.id === window.true_id) continue;
                            var pos = window.players_show_pos[p.id];
                            if (!pos) continue;
                            var dx = pos.x - me.x,
                                dy = pos.y - me.y,
                                d2 = dx * dx + dy * dy;
                            if (d2 < bestD) {
                                bestD = d2;
                                bestId = p.id;
                            }
                        }
                        return bestId === null ? null : {
                            id: bestId,
                            d2: bestD,
                            dist: Math.sqrt(bestD)
                        };
                    } catch (e) {
                        return null;
                    }
                }

                function NPI() {
                    try {
                        var best = PlayerAndID();
                        if (!best) return null;
                        var p = null;
                        for (var i = 0; i < window.players.length; i++) {
                            if (window.players[i] && window.players[i].id === best.id) {
                                p = window.players[i];
                                break;
                            }
                        }
                        var pos = (window.players_show_pos && window.players_show_pos[best.id]) ? window.players_show_pos[best.id] : null;
                        return {
                            id: best.id,
                            dist: best.dist,
                            player: p,
                            pos: pos
                        };
                    } catch (e) {
                        return null;
                    }
                }

                function GNT(me, excludeId, maxCount) {
                    var threats = [];
                    try {
                        for (var i = 0; i < window.players.length; i++) {
                            var p = window.players[i];
                            if (!p || p.id === window.true_id || p.id === excludeId) continue;
                            var pos = window.players_show_pos ? window.players_show_pos[p.id] : null;
                            if (!pos) continue;
                            var d = distance(me.x, me.y, pos.x, pos.y);
                            if (d > 520) continue;
                            var r = (window.players_radius && window.players_radius[p.id]) ? window.players_radius[p.id] : 25;
                            var score = p.score || 0;
                            var pvx = p.vx || 0;
                            var pvy = p.vy || 0;
                            var speed = Math.sqrt(pvx * pvx + pvy * pvy);
                            threats.push({
                                id: p.id,
                                pos: pos,
                                dist: d,
                                radius: r,
                                score: score,
                                vx: pvx,
                                vy: pvy,
                                speed: speed
                            });
                        }
                        threats.sort(function(a, b) {
                            return a.dist - b.dist;
                        });
                        return threats.slice(0, maxCount || 4);
                    } catch (e) {
                        return [];
                    }
                }

                function CMR(me, threats) {
                    var rx = 0,
                        ry = 0;
                    for (var i = 0; i < threats.length; i++) {
                        var t = threats[i];
                        var dx = me.x - t.pos.x;
                        var dy = me.y - t.pos.y;
                        var d = Math.max(t.dist - t.radius - getMyRadius(), 40);
                        var w = (t.score / 200 + t.radius / 30 + (380 - t.dist) * 0.02) / (d * d);
                        if (t.speed > 25) w *= 1.6;
                        rx += dx * w;
                        ry += dy * w;
                    }
                    return normalize(rx, ry);
                }

                function sendControl(angle, trapFlag) {
                    try {
                        if (!sockRef && window.socket) sockRef = window.socket;
                        if (!sockRef) return;
                        if (!isFinite(angle)) angle = 0;
                        var t = trapFlag ? 1 : 0;
                        sockRef.send("[" + 0 + "," + angle + "," + t + "]");
                    } catch (e) {}
                }

                function normalize(x, y) {
                    var L = Math.sqrt(x * x + y * y);
                    if (L === 0) return {
                        x: 0,
                        y: 0
                    };
                    return {
                        x: x / L,
                        y: y / L
                    };
                }

                function safeApproach(targetX, targetY, me, traps, excludeOwner) {
                    var angle = Math.atan2(targetY - me.y, targetX - me.x) + Math.PI;
                    if (!PIT(traps, me.x, me.y, targetX, targetY, excludeOwner)) return {
                        x: targetX,
                        y: targetY,
                        angle: angle
                    };
                    var best = null;
                    var bestScore = Infinity;
                    var steps = 36;
                    var dists = [40, 80, 140, 220];
                    for (var s = 0; s < dists.length; s++) {
                        var distOffset = dists[s];
                        for (var i = 0; i < steps; i++) {
                            var a = -Math.PI + (i / steps) * (2 * Math.PI);
                            var ca = Math.cos(a),
                                sa = Math.sin(a);
                            var nx = targetX + ca * distOffset,
                                ny = targetY + sa * distOffset;
                            var penalty = 0;
                            if (PIT(traps, me.x, me.y, nx, ny, excludeOwner)) penalty += 1000000;
                            for (var ti = 0; ti < traps.length; ti++) {
                                var t = traps[ti];
                                if (typeof excludeOwner !== 'undefined' && t.owner == excludeOwner) continue;
                                var td = distance(nx, ny, t.x, t.y) - (t.r || 0);
                                if (td < 0) penalty += (15000 + Math.abs(td) * 80);
                                else if (td < 120) penalty += (1200 - td * 6);
                            }
                            var d = distance(me.x, me.y, nx, ny);
                            var score = d + penalty + distOffset * 0.2;
                            if (score < bestScore) {
                                bestScore = score;
                                best = {
                                    x: nx,
                                    y: ny,
                                    angle: Math.atan2(ny - me.y, nx - me.x) + Math.PI
                                };
                            }
                        }
                    }
                    if (best) return best;
                    return {
                        x: targetX,
                        y: targetY,
                        angle: angle
                    };
                }

                function GCT(me, enemyPos, enemyR, myR, desiredBase) {
                    var dx = me.x - enemyPos.x;
                    var dy = me.y - enemyPos.y;
                    var dist = Math.sqrt(dx * dx + dy * dy) || 1;
                    var ux = dx / dist;
                    var uy = dy / dist;
                    var px = -uy;
                    var py = ux;
                    var extra = enemyR * 0.6;
                    var targetX = enemyPos.x + ux * (desiredBase + extra) + px * 85;
                    var targetY = enemyPos.y + uy * (desiredBase + extra) + py * 85;
                    return {
                        x: targetX,
                        y: targetY
                    };
                }

                function UEPH(info) {
                    if (!info || !info.pos) return;
                    var now = Date.now();
                    enemyPositionHistory.push({
                        ts: now,
                        x: info.pos.x,
                        y: info.pos.y
                    });
                    while (enemyPositionHistory.length > 0 && now - enemyPositionHistory[0].ts > 3000) enemyPositionHistory.shift();
                }

                function EMS(info) {
                    UEPH(info);
                    var now = Date.now();
                    if (enemyPositionHistory.length < 5) return false;
                    var relevant = enemyPositionHistory.filter(function(p) {
                        return now - p.ts <= EST;
                    });
                    if (relevant.length < 4) return false;
                    var first = relevant[0];
                    var last = relevant[relevant.length - 1];
                    var totalDx = last.x - first.x;
                    var totalDy = last.y - first.y;
                    var totalDist = Math.sqrt(totalDx * totalDx + totalDy * totalDy);
                    if (totalDist < 35) return false;
                    var mainAngle = Math.atan2(totalDy, totalDx);
                    var maxDeviation = 0;
                    for (var i = 1; i < relevant.length; i++) {
                        var prev = relevant[i - 1];
                        var curr = relevant[i];
                        var segDx = curr.x - prev.x;
                        var segDy = curr.y - prev.y;
                        var segDist = Math.sqrt(segDx * segDx + segDy * segDy);
                        if (segDist < 6) continue;
                        var segAngle = Math.atan2(segDy, segDx);
                        var delta = Math.abs(segAngle - mainAngle);
                        if (delta > Math.PI) delta = 2 * Math.PI - delta;
                        if (delta > maxDeviation) maxDeviation = delta;
                    }
                    return maxDeviation < 0.25;
                }

                function PKB() {
                    var me = getMyPos();
                    if (!me) return false;
                    var myScore = getMyScore();
                    if (myScore <= KMS) return false;
                    var info = NPI();
                    if (!info || !info.pos || !info.player) return false;
                    var enemyScore = info.player.score || 0;
                    if (enemyScore < 100) return false;
                    var myR = getMyRadius();
                    var enemyR = getPlayerRadius(info.id);
                    var traps = gatherTraps();
                    if (EEE(me, traps)) return true;
                    var currentRadius = myR;
                    lastLoggedMyRadius = currentRadius;
                    var threats = GNT(me, info.id, 4);
                    var HST = false;
                    var secondaryDir = {
                        x: 0,
                        y: 0
                    };
                    if (threats.length > 0) {
                        var rep = CMR(me, threats);
                        if (rep.x !== 0 || rep.y !== 0) {
                            HST = true;
                            secondaryDir = rep;
                        }
                    }
                    var IST = EMS(info);
                    var desiredCircleR = myR + enemyR + KCR + (enemyR * 0.55);
                    var pvx = info.player.vx || 0;
                    var pvy = info.player.vy || 0;
                    var predX = info.pos.x + pvx * P_F * 1.75;
                    var predY = info.pos.y + pvy * P_F * 1.75;
                    var distToPred = distance(me.x, me.y, predX, predY);
                    var now = Date.now();
                    var shouldRam = IST || (enemyR < SER);
                    if (shouldRam) {
                        var ramAngle = Math.atan2(predY - me.y, predX - me.x) + Math.PI;
                        if (now - kltp > 90) {
                            for (var i = 0; i < KRTB; i++) {
                                (function(a, d) {
                                    setTimeout(function() {
                                        sendControl(a, 1);
                                    }, d);
                                })(ramAngle, i * KTBD);
                            }
                            kltp = now;
                            setTimeout(function() {
                                sendControl(ramAngle, 0);
                            }, KRTB * KTBD + 55);
                        } else {
                            sendControl(ramAngle, 0);
                        }
                        return true;
                    }
                    if (HST && threats.length >= 1) {
                        var threatAngle = Math.atan2(secondaryDir.y, secondaryDir.x) + Math.PI;
                        sendControl(threatAngle, 0);
                        return true;
                    }
                    var currDist = distance(me.x, me.y, info.pos.x, info.pos.y);
                    if (currDist < desiredCircleR - 48) {
                        var pushAngle = Math.atan2(me.y - info.pos.y, me.x - info.pos.x) + Math.PI;
                        sendControl(pushAngle, 0);
                        return true;
                    }
                    var target = GCT(me, info.pos, enemyR, myR, desiredCircleR);
                    var safe = safeApproach(target.x, target.y, me, traps, info.id);
                    var moveAngle = safe ? safe.angle : Math.atan2(target.y - me.y, target.x - me.x) + Math.PI;
                    if (now - kltp > KTIM) {
                        var trapAngle = moveAngle;
                        for (var k = 0; k < KTBS; k++) {
                            (function(a, d) {
                                setTimeout(function() {
                                    sendControl(a, 1);
                                }, d);
                            })(trapAngle, k * KTBD);
                        }
                        kltp = now;
                        setTimeout(function() {
                            sendControl(moveAngle, 0);
                        }, KTBS * KTBD + 65);
                    } else {
                        sendControl(moveAngle, 0);
                    }
                    return true;
                }

                function EEE(me, traps) {
                    var rep = RVR(me, traps);
                    if (!rep || rep.minDanger > 160) return false;
                    var v = normalize(rep.rx, rep.ry);
                    if (v.x === 0 && v.y === 0) return false;
                    var push = 920;
                    var targetX = me.x + v.x * push;
                    var targetY = me.y + v.y * push;
                    var angle = Math.atan2(targetY - me.y, targetX - me.x) + Math.PI;
                    sendControl(angle, 0);
                    for (var k = 1; k <= 3; k++) {
                        (function(a, d) {
                            setTimeout(function() {
                                sendControl(a, 0);
                            }, d);
                        })(angle, k * 40);
                    }
                    return true;
                }

                function RVR(me, traps) {
                    var rx = 0,
                        ry = 0,
                        minDanger = Infinity;
                    for (var i = 0; i < traps.length; i++) {
                        var t = traps[i];
                        if (typeof window.true_id !== 'undefined' && t.owner == window.true_id) continue;
                        var dcenter = distance(me.x, me.y, t.x, t.y);
                        var d = dcenter - (t.r || 0);
                        if (d < minDanger) minDanger = d;
                        var dd = Math.max(d, 0.1);
                        var w = 1 / (dd * dd);
                        rx += (me.x - t.x) * w;
                        ry += (me.y - t.y) * w;
                    }
                    return {
                        rx: rx,
                        ry: ry,
                        minDanger: minDanger
                    };
                }

                function FCBS(traps) {
                    try {
                        var update_map = window.update_bonus_map || window.player_update_bonus_map || [];
                        var bonus_map = window.bonus_map || window.bonusMap || null;
                        var player_bonus_map = window.player_bonus_map || window.playerBonusMap || window.player_bonus_map;
                        var me = getMyPos();
                        if (!me) return null;
                        var best = null;
                        var bestScore = Infinity;
                        for (var i = 0; i < update_map.length; i++) {
                            var idb = update_map[i];
                            var bx = 0,
                                by = 0,
                                isPlayerBonus = false;
                            if (typeof idb === 'number' && bonus_map && typeof bonus_map[idb] !== 'undefined') {
                                var b = bonus_map[idb];
                                if (!b) continue;
                                bx = (typeof b.rx !== 'undefined') ? b.rx : ((typeof b.x !== 'undefined') ? b.x : 0);
                                by = (typeof b.ry !== 'undefined') ? b.ry : ((typeof b.y !== 'undefined') ? b.y : 0);
                            } else {
                                isPlayerBonus = true;
                                try {
                                    var BIG = (typeof window.BONUS_DEAD_KEY !== 'undefined') ? window.BONUS_DEAD_KEY : 1000000;
                                    if (BIG && idb >= BIG) {
                                        var j = Math.floor(idb / BIG) - 1;
                                        var k = idb % BIG;
                                        var pb = (player_bonus_map && player_bonus_map[j]) ? player_bonus_map[j][k] : null;
                                        if (!pb) continue;
                                        bx = (typeof pb.rx !== 'undefined') ? pb.rx : ((typeof pb.x !== 'undefined') ? pb.x : 0);
                                        by = (typeof pb.ry !== 'undefined') ? pb.ry : ((typeof pb.y !== 'undefined') ? pb.y : 0);
                                    } else continue;
                                } catch (e) {
                                    continue;
                                }
                            }
                            var dx = bx - me.x,
                                dy = by - me.y;
                            var d = Math.sqrt(dx * dx + dy * dy);
                            if (isPlayerBonus && TNP(traps, bx, by, PBW)) continue;
                            var penalty = 0;
                            if (PIT(traps, me.x, me.y, bx, by)) penalty += 1000000;
                            for (var tI = 0; tI < traps.length; tI++) {
                                var t = traps[tI];
                                var td = distance(bx, by, t.x, t.y) - (t.r || 0);
                                if (td < 0) penalty += (10000 + Math.abs(td) * 50);
                                else if (td < 60) penalty += (600 - td * 5);
                            }
                            var score = d + penalty;
                            if (score < bestScore) {
                                bestScore = score;
                                best = {
                                    x: bx,
                                    y: by,
                                    isPlayerBonus: isPlayerBonus,
                                    d: d
                                };
                            }
                        }
                        return best;
                    } catch (e) {
                        return null;
                    }
                }

                function botTick() {
                    try {
                        if (!sockRef && window.socket) sockRef = window.socket;
                        if (!sockRef) return;
                        if (typeof window.game_is_show !== 'undefined' && !window.game_is_show) return;
                        var me = getMyPos();
                        if (!me) return;
                        var traps = gatherTraps();
                        if (EEE(me, traps)) return;
                        if (killMode) {
                            if (PKB()) return;
                        }
                        var nearestP = PlayerAndID();
                        var isFlee = nearestP && nearestP.dist < F_D;
                        if (isFlee) {
                            var pPos = window.players_show_pos[nearestP.id];
                            if (!pPos) return;
                            var pvx = 0,
                                pvy = 0;
                            try {
                                for (var i = 0; i < window.players.length; i++) {
                                    var pe = window.players[i];
                                    if (pe && pe.id === nearestP.id) {
                                        if (typeof pe.vx !== 'undefined') pvx = pe.vx;
                                        if (typeof pe.vy !== 'undefined') pvy = pe.vy;
                                        break;
                                    }
                                }
                            } catch (e) {}
                            var predX = pPos.x + pvx * P_F;
                            var predY = pPos.y + pvy * P_F;
                            var dx = me.x - predX,
                                dy = me.y - predY;
                            var dist = Math.sqrt(dx * dx + dy * dy) || 1;
                            var ux = dx / dist,
                                uy = dy / dist;
                            var push = F_P + Math.max(0, (F_D - dist)) * 2;
                            var targetX = me.x + ux * push,
                                targetY = me.y + uy * push;
                            if (PIT(traps, me.x, me.y, targetX, targetY)) {
                                var rx = 0,
                                    ry = 0,
                                    totalw = 0;
                                for (var ti = 0; ti < traps.length; ti++) {
                                    var t = traps[ti];
                                    var td = distance(me.x, me.y, t.x, t.y) - Math.max(1, t.r || 0);
                                    if (td <= 0) td = 0.1;
                                    var w = 1 / (td * td);
                                    rx += (me.x - t.x) * w;
                                    ry += (me.y - t.y) * w;
                                    totalw += w;
                                }
                                if (totalw > 0) {
                                    rx /= totalw;
                                    ry /= totalw;
                                    var rlen = Math.sqrt(rx * rx + ry * ry) || 1;
                                    rx /= rlen;
                                    ry /= rlen;
                                    targetX = me.x + rx * push;
                                    targetY = me.y + ry * push;
                                }
                            }
                            var angle = Math.atan2(targetY - me.y, targetX - me.x) + Math.PI;
                            var now = Date.now();
                            var wantTrap = (getMyScore() > 1000 && (now - ltt) > T_C);
                            if (wantTrap) {
                                ltt = now;
                                sendControl(angle, 1);
                                setTimeout(function() {
                                    sendControl(angle, 0);
                                }, 80);
                            } else sendControl(angle, 0);
                            return;
                        }
                        var target = FCBS(traps);
                        if (target) {
                            var dx = target.x - me.x,
                                dy = target.y - me.y;
                            var angle = Math.atan2(dy, dx) + Math.PI;
                            sendControl(angle, 0);
                            return;
                        }
                        var jitter = (Math.random() - 0.5) * 0.6;
                        var base = (typeof window.mouseangle !== 'undefined') ? window.mouseangle : 0;
                        sendControl(base + jitter, 0);
                    } catch (e) {}
                }

                function startBot() {
                    if (loopIv) clearInterval(loopIv);
                    loopIv = setInterval(botTick, RATE_MS);
                }

                function stopBot() {
                    if (loopIv) {
                        clearInterval(loopIv);
                        loopIv = null;
                    }
                }
                window.AutoBot = {
                    start: function() {
                        startBot();
                    },
                    stop: function() {
                        stopBot();
                    },
                    setKill: function(v) {
                        killMode = !!v;
                    },
                    isRunning: function() {
                        return !!loopIv;
                    }
                };
                try {
                    if (window.socket) sockRef = window.socket;
                } catch (e) {}
                return {};
            } catch (e) {}
        }).toString() + ")();";
        try {
            const s = document.createElement('script');
            s.textContent = botSrc;
            (document.documentElement).appendChild(s);
            s.parentNode.removeChild(s);
        } catch (e) {}
    }

    try {
        injectBot();
    } catch (e) {}

    function startHUD() {
        if (hudRunner) return;
        const W = unsafeWindow;
        const css = `
    #HUD {
      position: fixed;
      top: 8px;
      left: 50%;
      transform: translateX(-50%);
      z-index: 99999;
      padding: 8px 14px;
      font-family: Arial, Helvetica, sans-serif;
      font-size: 13px;
      color: #ffffff;
      background: rgba(6,10,20,0.55);
      border-radius: 8px;
      display: none;
      white-space: nowrap;
      pointer-events: none;
      user-select: none;
    }
    #HUD.show { display: block; }
    #HUD.hidden { display: none; }
    #HUD .item { margin: 0 8px; display: inline-block; }
    #HUD .ping-good { color: #4ade80; }
    #HUD .ping-mid  { color: #facc15; }
    #HUD .ping-bad  { color: #f87171; }
    `;
        if (typeof GM_addStyle === 'function') GM_addStyle(css);
        if (document.getElementById('HUD')) return;
        const hud = document.createElement('div');
        hud.id = 'HUD';
        const spanFPS = document.createElement('span');
        spanFPS.className = 'item';
        const spanTime = document.createElement('span');
        spanTime.className = 'item';
        const spanPlayers = document.createElement('span');
        spanPlayers.className = 'item';
        const spanPing = document.createElement('span');
        spanPing.className = 'item';
        hud.appendChild(spanFPS);
        hud.appendChild(spanTime);
        hud.appendChild(spanPlayers);
        hud.appendChild(spanPing);
        document.body.appendChild(hud);
        let lastGameShow = Boolean(W.game_is_show);
        let rafLast = performance.now();
        let rafFPS = 0;
        let lastUpdate = 0;
        const Interval = 0xC7;

        function pad(v) {
            return v.toString().padStart(2, '0');
        }

        function formatTime(ms) {
            if (!ms || ms <= 0) return '00:00:00';
            const s = Math.floor(ms / 1000);
            return `${pad(Math.floor(s / 3600))}:${pad(Math.floor((s % 3600) / 60))}:${pad(s % 60)}`;
        }

        function readFPS() {
            try {
                if (W.fps && typeof W.fps.fps === 'number') return Math.round(W.fps.fps);
            } catch (e) {}
            return null;
        }

        function countPlayers() {
            try {
                const el = document.getElementById('perso_information');
                if (el) {
                    const m = el.textContent.match(/out of (\d+)/);
                    if (m) return parseInt(m[1], 10);
                }
            } catch (e) {}
            return 0;
        }

        function pingClass(ms) {
            if (ms < 0) return '';
            if (ms < 0x50) return 'ping-good';
            if (ms < 0x96) return 'ping-mid';
            return 'ping-bad';
        }

        function updateLogic(now) {
            const gameShow = Boolean(W.game_is_show);
            if (!gameShow && lastGameShow) {
                _pingMs = -1;
                _pingPending = false;
            }
            lastGameShow = gameShow;
            if (!state.HUD || !gameShow) {
                hud.className = 'hidden';
                return;
            }
            hud.className = 'show';
            let fpsVal = readFPS();
            if (fpsVal === null) fpsVal = rafFPS || 0;
            const timeVal = _hudSessionStart ? formatTime(Date.now() - _hudSessionStart) : '00:00:00';
            const playersVal = countPlayers();
            const pc = pingClass(_pingMs);
            const ping = _pingMs >= 0 ? _pingMs : '-';
            spanFPS.textContent = `FPS: ${fpsVal}`;
            spanTime.textContent = `Time: ${timeVal}`;
            spanPlayers.textContent = `Players: ${playersVal}`;
            spanPing.innerHTML = `Ping: <span class="${pc}">${ping}${_pingMs >= 0 ? 'ms' : ''}</span>`;
        }

        function rafLoop(now) {
            const dt = now - rafLast;
            rafLast = now;
            if (dt > 0) rafFPS = Math.round(1000 / dt);
            if (now - lastUpdate >= Interval) {
                lastUpdate = now;
                updateLogic(now);
            }
            requestAnimationFrame(rafLoop);
        }
        requestAnimationFrame(rafLoop);
        hudRunner = {
            stop: () => {
                try {
                    hud.remove();
                } catch (e) {}
                hudRunner = null;
            }
        };
    }

    function stopHUD() {
        if (!hudRunner && document.getElementById('HUD')) {
            try {
                document.getElementById('HUD').remove();
            } catch (e) {}
            hudRunner = null;
        } else if (hudRunner) {
            try {
                document.getElementById('HUD') && document.getElementById('HUD').remove();
            } catch (e) {}
            hudRunner = null;
        }
    }

    function applyFeature(key, on) {
        try {
            if (key === 'AdBlocker') {
                if (on) adStart();
                else adStop();
            } else if (key === 'BetterLeaderBoard') {
                if (on) lbStart();
                else lbStop();
            } else if (key === 'Tracers') {
                if (on) {
                    trRunner = trRunner || makeTracers();
                    trRunner.start();
                } else {
                    if (trRunner) trRunner.stop();
                }
            } else if (key === 'ESP') {
                if (on) {
                    espRunner = espRunner || makeESP();
                    espRunner.start();
                } else {
                    if (espRunner) espRunner.stop();
                }
            } else if (key === 'SkipAnimations') {
                if (on) startSkipAnimations();
                else stopSkipAnimations();
            } else if (key === 'AutoReconnect') {} else if (key === 'AutoPlay') {
                try {
                    const api = unsafeWindow && unsafeWindow.AutoBot;
                    if (api && typeof api.start === 'function') {
                        if (on) {
                            api.setKill(!!state.AutoPlayKillMode);
                            api.start();
                        } else {
                            api.stop();
                        }
                    } else {
                        injectBot();
                        setTimeout(() => {
                            try {
                                const api2 = unsafeWindow && unsafeWindow.AutoBot;
                                if (api2 && on) {
                                    api2.setKill(!!state.AutoPlayKillMode);
                                    api2.start();
                                } else if (api2 && !on) {
                                    api2.stop();
                                }
                            } catch (e) {}
                        }, 0x12c);
                    }
                } catch (e) {}
            } else if (key === 'HUD') {
                if (on) startHUD();
                else stopHUD();
            } else if (key === 'Zoom') {
                if (on) {
                    _bindZoomWheel();
                    _applyZoomCss();
                } else {
                    zoomValue = 1.0;
                    _applyZoomCss();
                }
            } else if (key === 'SkinHack') {
                if (on) startSkinHack();
                else stopSkinHack();
            }
        } catch (e) {}
    }

    function applyAll() {
        Object.keys(defaults).forEach(k => {
            if (k === 'visible' || k === 'ToggleKey' || k === 'Theme') return;
            applyFeature(k, !!state[k]);
        });
    }

    function escapeHtml(s) {
        return String(s || '').replace(/[&<>"']/g, function(m) {
            return ({
                '&': '&amp;',
                '<': '&lt;',
                '>': '&gt;',
                '"': '&quot;',
                "'": '&#39;'
            })[m];
        });
    }

    function render() {
        root.classList.toggle('theme-white', state.Theme === 'white');
        root.innerHTML = `
      <div class="lt-header">
        <div class="lt-title">
          <div class="lt-logo">Limax Client</div>
          <div>
            <div class="lt-h1">Limax Client</div>
            <div class="lt-sub">The game is better with this script :D</div>
          </div>
        </div>
        <div style="display:flex;gap:10px;align-items:center"></div>
      </div>

      <div class="lt-grid">
        <div class="lt-card" data-feature="AdBlocker">
          <div class="title-row">
            <h3>AdBlocker</h3>
            <div class="lt-switch ${state.AdBlocker ? 'on' : ''}" data-switch="AdBlocker" role="switch" aria-checked="${!!state.AdBlocker}"><div class="knob"></div></div>
          </div>
          <p class="lt-small">Removes common ads/overlays and forces play handlers to skip banners</p>
        </div>

        <div class="lt-card" data-feature="BetterLeaderBoard">
          <div class="title-row">
            <h3>Better LeaderBoard</h3>
            <div class="lt-switch ${state.BetterLeaderBoard ? 'on' : ''}" data-switch="BetterLeaderBoard" role="switch" aria-checked="${!!state.BetterLeaderBoard}"><div class="knob"></div></div>
          </div>
          <p class="lt-small">Collects player scores and redraws leaderboard with accurate sorting and rank</p>
        </div>

        <div class="lt-card" data-feature="AutoPlay">
          <div class="title-row">
            <h3>Auto Play</h3>
            <div class="lt-switch ${state.AutoPlay ? 'on' : ''}" data-switch="AutoPlay" role="switch" aria-checked="${!!state.AutoPlay}"><div class="knob"></div></div>
          </div>
          <p class="lt-small">Auto-gather && basic combat routines</p>
          <div class="lt-controls" data-controls-for="AutoPlay" style="display:${state.AutoPlay ? 'flex' : 'none'};flex-direction:column;gap:6px">
            <label class="lt-small" style="display:flex;align-items:center;gap:8px">
              <input type="checkbox" class="lt-input-checkbox" id="autoPlayKill" ${state.AutoPlayKillMode ? 'checked' : ''}>
              <span>Kill Mode</span>
            </label>
            <label class="lt-small" style="display:flex;align-items:center;gap:8px">
              <input type="checkbox" class="lt-input-checkbox" id="autoReconnect" ${state.AutoReconnect ? 'checked' : ''}>
              <span>Auto-reconnect</span>
            </label>
          </div>
        </div>

        <div class="lt-card" data-feature="Tracers">
          <div class="title-row">
            <h3>Tracers</h3>
            <div class="lt-switch ${state.Tracers ? 'on' : ''}" data-switch="Tracers" role="switch" aria-checked="${!!state.Tracers}"><div class="knob"></div></div>
          </div>
          <p class="lt-small">Draws smooth curved lines from you to players for easier tracking</p>
        </div>

        <div class="lt-card" data-feature="ESP">
          <div class="title-row">
            <h3>ESP</h3>
            <div class="lt-switch ${state.ESP ? 'on' : ''}" data-switch="ESP" role="switch" aria-checked="${!!state.ESP}"><div class="knob"></div></div>
          </div>
          <p class="lt-small">Predictive lead boxes and visual markers for nearby players</p>
        </div>

        <div class="lt-card" data-feature="SkipAnimations">
          <div class="title-row">
            <h3>Skip Animations</h3>
            <div class="lt-switch ${state.SkipAnimations ? 'on' : ''}" data-switch="SkipAnimations" role="switch" aria-checked="${!!state.SkipAnimations}"><div class="knob"></div></div>
          </div>
          <p class="lt-small">Skips death and server join animations instantly</p>
        </div>

        <div class="lt-card" data-feature="HUD">
          <div class="title-row">
            <h3>HUD</h3>
            <div class="lt-switch ${state.HUD ? 'on' : ''}" data-switch="HUD" role="switch" aria-checked="${!!state.HUD}"><div class="knob"></div></div>
          </div>
          <p class="lt-small">HUD showing FPS, in-game session time, and active players count</p>
        </div>

        <div class="lt-card" data-feature="ClickGUI">
          <div class="title-row">
            <h3>ClickGUI</h3>
            <div class="lt-switch on" role="switch" aria-checked="true" style="opacity:0.6;cursor:default;"><div class="knob"></div></div>
          </div>
          <p class="lt-small">Menu controls: keybind and theme</p>
          <div class="lt-controls" data-controls-for="ClickGUI" style="display:flex;flex-direction:column;gap:8px;margin-top:8px">
            <div style="display:flex;gap:8px;align-items:center">
              <button class="lt-btn" id="changeKeyBtn">Change Key</button>
              <div class="lt-small" id="currentKeyDisplay">${FKD(state.ToggleKey)} - toggle</div>
            </div>
            <div style="display:flex;gap:8px;align-items:center">
              <button class="lt-btn" id="themeDarkBtn">Dark</button>
              <button class="lt-btn" id="themeWhiteBtn">White</button>
              <div class="lt-small">Current: ${escapeHtml(capitalize(state.Theme || 'dark'))}</div>
            </div>
          </div>
        </div>

        <div class="lt-card" data-feature="Zoom">
          <div class="title-row">
            <h3>Zoom</h3>
            <div class="lt-switch ${state.Zoom ? 'on' : ''}" data-switch="Zoom" role="switch" aria-checked="${!!state.Zoom}"><div class="knob"></div></div>
          </div>
          <p class="lt-small">Default zoom hack, CTRL+ mouse wheel</p>
          <div class="lt-controls" style="display:${state.Zoom ? 'flex' : 'none'};align-items:center;gap:8px;margin-top:4px">
            <span class="lt-small" id="_zoom_label">zoom: ${zoomValue.toFixed(1)}x</span>
          </div>
        </div>

        <div class="lt-card" data-feature="SkinHack">
          <div class="title-row">
            <h3>SkinHack</h3>
            <div class="lt-switch ${state.SkinHack ? 'on' : ''}" data-switch="SkinHack" role="switch" aria-checked="${!!state.SkinHack}"><div class="knob"></div></div>
          </div>
          <p class="lt-small">Visual skin hack. Select as in the game (arrows)</p>
        </div>

      </div>

      <div class="lt-footer">
        <div></div>
        <div style="display:flex;gap:10px;align-items:center">
          <div class="lt-toggle-key" id="lt-toggle-key">${FKD(state.ToggleKey)} - toggle</div>
          <button class="save" id="lt-close">Close</button>
        </div>
      </div>
    `;
        attachHandlers();
    }

    function FKD(code) {
        if (!code) return 'AltRight';
        return code.replace('Key', '').replace('Digit', '').replace('Arrow', '').replace('Right', 'Right').replace('Left', 'Left');
    }

    function capitalize(s) {
        if (!s) return s;
        return s.charAt(0).toUpperCase() + s.slice(1);
    }

    function attachHandlers() {
        const switches = root.querySelectorAll('[data-switch]');
        switches.forEach(el => {
            const key = el.getAttribute('data-switch');
            if (key === 'ClickGUI') return;
            el.onclick = async function() {
                state[key] = !state[key];
                if (key === 'AutoPlay' && !state.AutoPlay) state.AutoPlayKillMode = false;
                await saveState();
                applyFeature(key, !!state[key]);
                render();
            };
        });

        const autoPlayKill = root.querySelector('#autoPlayKill');
        if (autoPlayKill) {
            autoPlayKill.onchange = async function() {
                state.AutoPlayKillMode = !!this.checked;
                await saveState();
                try {
                    if (unsafeWindow && unsafeWindow.AutoBot) unsafeWindow.AutoBot.setKill(!!state.AutoPlayKillMode);
                } catch (e) {}
                render();
            };
        }

        const autoReconnect = root.querySelector('#autoReconnect');
        if (autoReconnect) {
            autoReconnect.onchange = async function() {
                state.AutoReconnect = !!this.checked;
                await saveState();
                render();
            };
        }

        const closeBtn = root.querySelector('#lt-close');
        closeBtn.onclick = function() {
            toggle(false);
            render();
        };

        const changeKeyBtn = root.querySelector('#changeKeyBtn');
        const currentKeyDisplay = root.querySelector('#currentKeyDisplay');
        const ltToggleKey = root.querySelector('#lt-toggle-key');
        if (changeKeyBtn) {
            changeKeyBtn.onclick = function() {
                startBinding(changeKeyBtn, currentKeyDisplay, ltToggleKey);
            };
        }

        const themeDarkBtn = root.querySelector('#themeDarkBtn');
        const themeWhiteBtn = root.querySelector('#themeWhiteBtn');
        if (themeDarkBtn) {
            themeDarkBtn.onclick = async function() {
                state.Theme = 'dark';
                await saveState();
                render();
            };
        }
        if (themeWhiteBtn) {
            themeWhiteBtn.onclick = async function() {
                state.Theme = 'white';
                await saveState();
                render();
            };
        }

        function startBinding(buttonEl, displayEl, footerEl) {
            buttonEl.textContent = 'Press key...';
            let done = false;

            function finish(ok, code) {
                if (done) return;
                done = true;
                window.removeEventListener('keydown', onKey, true);
                window.removeEventListener('mousedown', onMouse, true);
                buttonEl.textContent = 'Change Key';
                if (ok && code) {
                    const invalid = (code === 'Escape' || code === 'MouseLeft' || code === 'MouseRight');
                    if (invalid) {
                        state.ToggleKey = defaults.ToggleKey;
                    } else {
                        state.ToggleKey = code;
                    }
                } else {
                    state.ToggleKey = defaults.ToggleKey;
                }
                saveState().then(() => {
                    render();
                });
            }

            function onKey(e) {
                e.stopPropagation();
                e.preventDefault();
                const code = e.code || e.key || null;
                if (!code) {
                    finish(false);
                    return;
                }
                if (code === 'Escape') {
                    finish(false);
                    return;
                }
                finish(true, code);
            }

            function onMouse(e) {
                e.stopPropagation();
                e.preventDefault();
                finish(false);
            }
            window.addEventListener('keydown', onKey, true);
            window.addEventListener('mousedown', onMouse, true);
        }
    }

    function toggle(force) {
        const should = typeof force === 'boolean' ? force : !state.visible;
        state.visible = should;
        saveState();
        if (should) root.classList.add('show');
        else root.classList.remove('show');
    }

    async function saveState() {
        try {
            await gmSet(STORAGE_KEY, JSON.stringify(state));
        } catch (e) {}
    }

    document.addEventListener('keydown', function(e) {
        const bind = state.ToggleKey || defaults.ToggleKey;
        if (e.code === bind) {
            e.preventDefault();
            toggle();
            render();
            return;
        }
        if (e.key === 'Escape') {
            toggle(false);
            render();
        }
    }, true);

    render();
    applyAll();

    try {
        if (state.AutoPlay) {
            try {
                if (unsafeWindow && unsafeWindow.AutoBot) {
                    unsafeWindow.AutoBot.setKill(!!state.AutoPlayKillMode);
                    unsafeWindow.AutoBot.start();
                }
            } catch (e) {}
        }
    } catch (e) {}

    if (state.visible) toggle(true);

    window.LimaxClient = {
        getState: () => JSON.parse(JSON.stringify(state)),
        setState: async (ns) => {
            state = Object.assign({}, state, ns);
            await saveState();
            applyAll();
            render();
        },
        gmDelete
    };

})();

// XD

GM_addStyle(`
  #logo {
    position: absolute !important;
    overflow: visible !important;
    background: transparent !important;
    text-align: center !important;
    display: block !important;
    isolation: isolate !important;
  }

  #logo > img#logoi {
    display: none !important;
  }

  #logo::after {
    content: "Limax Client" !important;
    position: absolute !important;
    left: 50% !important;
    top: 50% !important;
    transform: translate(-50%, -50%) !important;
    white-space: nowrap !important;
    pointer-events: none !important;
    user-select: none !important;
    -webkit-user-select: none !important;
    font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif !important;
    font-size: 27px !important;
    font-weight: 900 !important;
    letter-spacing: 0.04em !important;
    color: transparent !important;
    background: linear-gradient(
      90deg,
      #f7ffff 0%,
      #8cf3ff 18%,
      #76ffb4 36%,
      #f7ff8d 52%,
      #79d9ff 70%,
      #ffffff 100%
    ) !important;
    background-size: 100% 100% !important;
    -webkit-background-clip: text !important;
    background-clip: text !important;
    -webkit-text-fill-color: transparent !important;
    text-shadow:
      0 1px 0 rgba(255,255,255,0.22),
      0 0 10px rgba(118, 255, 180, 0.14),
      0 0 18px rgba(121, 217, 255, 0.18),
      0 8px 18px rgba(0,0,0,0.18) !important;
    filter:
      drop-shadow(0 0 2px rgba(255,255,255,0.12))
      drop-shadow(0 0 10px rgba(110,255,180,0.10))
      drop-shadow(0 0 14px rgba(120,210,255,0.10)) !important;
  }

  #logo::before {
    content: "" !important;
    position: absolute !important;
    left: 50% !important;
    top: 58% !important;
    width: 78% !important;
    height: 2px !important;
    transform: translateX(-50%) !important;
    background: linear-gradient(
      90deg,
      rgba(0,0,0,0) 0%,
      rgba(120,255,190,0.0) 15%,
      rgba(120,255,190,0.45) 42%,
      rgba(120,220,255,0.45) 58%,
      rgba(0,0,0,0) 100%
    ) !important;
    box-shadow:
      0 0 10px rgba(120,255,190,0.10),
      0 0 14px rgba(120,220,255,0.10) !important;
    pointer-events: none !important;
  }
`);

(function() {
    'use strict';

    const win = unsafeWindow;

    const PREFIX = 'lx_';
    const EXPIRE_DAYS = 365;

    function encode(val) {
        try {
            return encodeURIComponent(String(val));
        } catch {
            return String(val);
        }
    }

    function decode(val) {
        try {
            return decodeURIComponent(String(val));
        } catch {
            return String(val);
        }
    }

    function setRaw(key, value, days) {
        const d = new Date();
        d.setTime(d.getTime() + (days || EXPIRE_DAYS) * 864e5);
        document.cookie = encode(key) + '=' + encode(value) + '; expires=' + d.toUTCString() + '; path=/';
        try {
            localStorage.setItem(PREFIX + key, value);
        } catch {}
    }

    function getRaw(key) {
        try {
            const ls = localStorage.getItem(PREFIX + key);
            if (ls !== null) return ls;
        } catch {}
        const name = encode(key) + '=';
        const parts = document.cookie.split(';');
        for (let i = 0; i < parts.length; i++) {
            const c = parts[i].trim();
            if (c.startsWith(name)) {
                try {
                    return decode(c.substring(name.length));
                } catch {
                    return c.substring(name.length);
                }
            }
        }
        return null;
    }

    function removeRaw(key) {
        document.cookie = encode(key) + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/';
        try {
            localStorage.removeItem(PREFIX + key);
        } catch {}
    }

    function getAll() {
        const res = {};
        try {
            for (let i = 0; i < localStorage.length; i++) {
                const k = localStorage.key(i);
                if (k && k.startsWith(PREFIX)) res[k.slice(PREFIX.length)] = localStorage.getItem(k);
            }
        } catch {}
        const parts = document.cookie.split(';');
        for (let i = 0; i < parts.length; i++) {
            const eq = parts[i].indexOf('=');
            if (eq < 0) continue;
            const k = decode(parts[i].slice(0, eq).trim());
            const v = decode(parts[i].slice(eq + 1).trim());
            if (!(k in res)) res[k] = v;
        }
        return res;
    }

    const api = function(key, value, attributes) {
        if (arguments.length > 1) {
            const days = (attributes && typeof attributes.expires === 'number') ? attributes.expires : EXPIRE_DAYS;
            setRaw(key, value, days);
            return value;
        }
        if (!key) return getAll();
        return getRaw(key);
    };

    api.set = function(key, value, attributes) {
        const days = (attributes && typeof attributes.expires === 'number') ? attributes.expires : EXPIRE_DAYS;
        setRaw(key, value, days);
        return value;
    };

    api.get = function(key) {
        if (!key) return getAll();
        return getRaw(key);
    };

    api.getJSON = function(key) {
        const val = getRaw(key);
        if (val === null) return undefined;
        try {
            return JSON.parse(val);
        } catch {
            return val;
        }
    };

    api.remove = function(key) {
        removeRaw(key);
    };

    api.defaults = {};

    api.withConverter = function() {
        return api;
    };

    api.noConflict = function() {
        return api;
    };

    win.Cookies = api;

    function restoreNick() {
        const nick = document.getElementById('nick');
        if (!nick) {
            requestAnimationFrame(restoreNick);
            return;
        }
        const saved = getRaw('username');
        if (saved) nick.value = saved;
        nick.addEventListener('input', () => {
            if (nick.value) setRaw('username', nick.value, EXPIRE_DAYS);
        });
    }

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

})();