GatsModV4 Gats.io (Patched)

0 key toggle. Chat features now reference Player.pool.chatMessage for stability.

// ==UserScript==
// @name         GatsModV4 Gats.io (Patched)
// @namespace    http://tampermonkey.net/
// @version      4.1
// @description  0 key toggle. Chat features now reference Player.pool.chatMessage for stability.
// @author       zeroarcop (patched by user request)
// @license      MIT
// @match        https://gats.io/
// @grant        GM_addStyle
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    const SETTINGS_KEY = 'zeroarcop_gats_mod_settings_v2';
    const LOG_PREFIX_MOD = "[zeroarcop-gats-mod]";
    const MULTIBOX_CHANNEL_NAME = 'gats_multibox_channel_v1';

    function modLog(message, isError = false) {
        const finalMessage = `${LOG_PREFIX_MOD} ${message}`;
        if (isError) {
            console.error(finalMessage);
        } else {
            console.log(finalMessage);
        }
    }

    function getDistance(p1, p2) {
        if (!p1 || !p2) return Infinity;
        return Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);
    }

    class ColorCustomizerGUI {
        constructor() {
            this.container = document.createElement('div');
            this.container.id = 'zeroarcop-gats-color-gui';
            this.container.style.display = 'none';
            document.body.appendChild(this.container);
            this.applyStyles();
            const head = document.createElement('h4');
            head.innerText = 'ESP Color Settings';
            this.container.appendChild(head);
            this.makeDraggable(head, this.container);
            this.addColorPicker('Enemy Box/Line', 'enemyEspColor');
            this.addColorPicker('Low HP Enemy Box/Line', 'lowHpEnemyEspColor');
            this.addColorPicker('Teammate Box/Line', 'teammateEspColor');
            this.addColorPicker('Cloaked Enemy Text', 'cloakedTextColor');
            this.addColorPicker('Enemy Name', 'enemyNameColor');
            this.addColorPicker('Teammate Name', 'teammateNameColor');
            this.addColorPicker('HP Bar (High)', 'hpBarHighColor');
            this.addColorPicker('HP Bar (Medium)', 'hpBarMediumColor');
            this.addColorPicker('HP Bar (Low)', 'hpBarLowColor');
            this.addColorPicker('Facing Line', 'facingLineColor');
            this.addColorPicker('Aimbot Target Line', 'aimbotTargetLineColor');
            this.addColorPicker('Prediction Line', 'predictionLineColor');
            this.addColorPicker('Obstacle Hitbox', 'obstacleEspColor');
            this.addColorPicker('AI Whisker (Clear)', 'aiWhiskerClearColor');
            this.addColorPicker('AI Whisker (Blocked)', 'aiWhiskerBlockedColor');
            this.addColorPicker('AI Move Direction', 'aiMoveDirColor');
            this.addColorPicker('AI Bullet Warning', 'aiBulletWarningColor');
            this.addColorPicker('AI Threat (Clear)', 'aiThreatLineClearColor');
            this.addColorPicker('AI Threat (Blocked)', 'aiThreatLineBlockedColor');

            const closeBtn = this.addButton('Close Colors (0)', () => { this.container.style.display = 'none'; }, this.container, 'custom-btn-color-gui');
            closeBtn.style.marginTop = '15px';
        }

        applyStyles() {
            GM_addStyle(`
                #${this.container.id} {
                    position: fixed; left: calc(20px + 950px + 10px); top: 70px; background-color: var(--main-bg, rgba(18,18,18,0.97));
                    color: var(--text-color-light, #fff); padding: 12px; border-radius: 6px; font-family: "Segoe UI", Arial, sans-serif;
                    font-size: 12px; z-index: 100001; border: 2px solid var(--accent-border, #b00000);
                    box-shadow: 0 3px 10px rgba(0,0,0,.5); width: 280px; max-height: calc(100vh - 100px);
                    overflow-y: auto; user-select: none;
                }
                #${this.container.id} h4 {
                    text-align: center; color: var(--accent-color, #f00); font-weight: 700; font-size: 14px;
                    margin-top: 0; margin-bottom: 12px; padding-bottom: 8px; border-bottom: 1px solid var(--accent-border, #b00000);
                    cursor: move;
                }
                #${this.container.id} .color-picker-row {
                    display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; padding: 3px;
                }
                #${this.container.id} .color-picker-row label {
                    color: var(--text-color-dim, #aaa); font-size: 11.5px; margin-right: 8px;
                }
                #${this.container.id} input[type=color] {
                    border: 1px solid var(--accent-border, #b00000); border-radius: 4px; width: 70px;
                    height: 28px; cursor: pointer; background-color: var(--secondary-bg, #1e1e1e); padding: 2px;
                }
                #${this.container.id} button.custom-btn-color-gui {
                    background-color: var(--btn-profile-bg, #2d2d2d); color: var(--btn-profile-text, #e0e0e0);
                    border: 1px solid var(--btn-profile-border, #f00); padding: 6px 10px; display: block;
                    width: 100%; border-radius: 3px; cursor: pointer; font-weight: 500; font-size: 12px;
                }
                #${this.container.id} button.custom-btn-color-gui:hover {
                    filter: brightness(var(--hover-brightness, 120%));
                }
                #${this.container.id}::-webkit-scrollbar { width: 8px; }
                #${this.container.id}::-webkit-scrollbar-track { background: var(--scrollbar-track, #2d2d2d); border-radius: 4px; }
                #${this.container.id}::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb, #aa0000); border-radius: 4px; }
                #${this.container.id}::-webkit-scrollbar-thumb:hover { background: var(--scrollbar-thumb-hover, #ff3333); }
            `);
        }

        makeDraggable(dragHandle, draggableElement) {
            let offsetX, offsetY, isDragging = false;
            const onMouseMove = (ev) => {
                if (!isDragging) return;
                draggableElement.style.left = (ev.clientX - offsetX) + 'px';
                draggableElement.style.top = (ev.clientY - offsetY) + 'px';
            };
            const onMouseUp = () => {
                isDragging = false;
                document.removeEventListener('mousemove', onMouseMove);
                document.removeEventListener('mouseup', onMouseUp);
            };
            dragHandle.addEventListener('mousedown', (e) => {
                if (e.target.closest('button, input, select, a')) return;
                isDragging = true;
                offsetX = e.clientX - draggableElement.offsetLeft;
                offsetY = e.clientY - draggableElement.offsetTop;
                document.addEventListener('mousemove', onMouseMove);
                document.addEventListener('mouseup', onMouseUp);
                e.preventDefault();
            });
        }

        addButton(label, onClick, parent, className = 'custom-btn') {
            const btn = document.createElement('button');
            btn.innerText = label;
            btn.className = className;
            btn.onclick = onClick;
            parent.appendChild(btn);
            return btn;
        }

        addColorPicker(label, settingKey) {
            const row = document.createElement('div');
            row.className = 'color-picker-row';
            const lbl = document.createElement('label');
            lbl.htmlFor = `${settingKey}-color-v2`;
            lbl.innerText = label + ":";
            row.appendChild(lbl);
            const picker = document.createElement('input');
            picker.type = 'color';
            picker.id = `${settingKey}-color-v2`;
            picker.value = (GatsModCore.SETTINGS?.espColors?.[settingKey]) || '#FFFFFF';
            picker.oninput = () => {
                if (GatsModCore.SETTINGS?.espColors) {
                    GatsModCore.SETTINGS.espColors[settingKey] = picker.value;
                }
            };
            picker.onchange = () => {
                if (GatsModCore.SETTINGS?.espColors) {
                    GatsModCore.SETTINGS.espColors[settingKey] = picker.value;
                    GatsModCore.saveSettings?.();
                }
            };
            row.appendChild(picker);
            this.container.appendChild(row);
        }
    }

    class SimpleGUI {
        constructor() {
            this.presetEditButtons = [];
            this.container = document.createElement('div');
            this.container.id = 'zeroarcop-gats-gui';
            this.container.style.display = 'none';
            document.body.appendChild(this.container);
            const mainContentWrapper = document.createElement('div');
            mainContentWrapper.id = 'gui-main-content-wrapper';
            this.container.appendChild(mainContentWrapper);
            const guiHead = document.createElement('h3');
            guiHead.innerText = 'Gats.io Mod by zeroarcop';
            mainContentWrapper.appendChild(guiHead);
            this.makeDraggable(guiHead, this.container);
            this.statusDisplay = document.createElement('div');
            this.statusDisplay.id = 'gui-status-bar';
            mainContentWrapper.appendChild(this.statusDisplay);
            const hotkeyInfo = document.createElement('p');
            hotkeyInfo.id = 'gui-hotkey-info';
            hotkeyInfo.innerHTML = `F: ESP | G: Aimbot | ^: Spinbot | 0: GUI(s) | 1-9: Preset Chat | Alt: Ignore Mode`;
            mainContentWrapper.appendChild(hotkeyInfo);
            const topBarWrapper = document.createElement('div');
            topBarWrapper.id = 'gui-top-bar-wrapper';
            mainContentWrapper.appendChild(topBarWrapper);
            this.addSearchBox(topBarWrapper);
            this.addProfileManager(topBarWrapper);
            const mainTogglesWrapper = document.createElement('div');
            mainTogglesWrapper.id = 'gui-main-toggles-wrapper';
            mainContentWrapper.appendChild(mainTogglesWrapper);
            this.addCheckbox('ESP Enabled', 'espEnabled', mainTogglesWrapper, 'Toggle all visual assistance features.');
            this.addCheckbox('Aimbot Enabled', 'aimbotEnabled', mainTogglesWrapper, 'Enable player-targeting aimbot.');
            this.addCheckbox('Spinbot Enabled', 'spinbotEnabled', mainTogglesWrapper, 'Enable rapid aim spinning (overridden by click/Aimbot).');
            this.addCheckbox('Ghost Detect', 'ghostDetectEnabled', mainTogglesWrapper, 'Forces cloaked (Ghillie) enemies to be visible.');
            this.addCheckbox('Silencer Detect', 'silencerDetectEnabled', mainTogglesWrapper, 'Forces bullets from silenced weapons to be visible.');
            this.addCheckbox('Smart Auto-Attack', 'autoAttackEnabled', mainTogglesWrapper, 'Automatically shoots when target is in range and line of sight is clear.');
            const columnsWrapper = document.createElement('div');
            columnsWrapper.id = 'gui-columns-wrapper';
            mainContentWrapper.appendChild(columnsWrapper);
            this.column1 = document.createElement('div');
            this.column1.className = 'gui-column';
            columnsWrapper.appendChild(this.column1);
            this.column2 = document.createElement('div');
            this.column2.className = 'gui-column';
            columnsWrapper.appendChild(this.column2);
            this.column3 = document.createElement('div');
            this.column3.className = 'gui-column';
            columnsWrapper.appendChild(this.column3);
            const footer = document.createElement('div');
            footer.id = 'gui-footer';
            mainContentWrapper.appendChild(footer);
            this.addDiscordButton(footer);
        }

        makeDraggable(dragHandle, draggableElement) {
            let offsetX, offsetY, isDragging = false;
            const onMouseMove = (ev) => {
                if (!isDragging) return;
                draggableElement.style.left = (ev.clientX - offsetX) + 'px';
                draggableElement.style.top = (ev.clientY - offsetY) + 'px';
            };
            const onMouseUp = () => {
                isDragging = false;
                document.removeEventListener('mousemove', onMouseMove);
                document.removeEventListener('mouseup', onMouseUp);
            };
            dragHandle.addEventListener('mousedown', (e) => {
                if (e.target.closest('button, input, select, a')) return;
                isDragging = true;
                offsetX = e.clientX - draggableElement.offsetLeft;
                offsetY = e.clientY - draggableElement.offsetTop;
                document.addEventListener('mousemove', onMouseMove);
                document.addEventListener('mouseup', onMouseUp);
                e.preventDefault();
            });
        }

        addCheckbox(label, settingKey, parent, tooltipText = null, onChangeCallback = null) {
            const div = document.createElement('div');
            if (parent.id === 'gui-main-toggles-wrapper') {
                div.style.cssText = 'display: flex; flex-direction: column; align-items: center; padding: 2px 5px; margin: 0 5px; min-width: 90px; text-align: center;';
            } else {
                div.style.cssText = 'display: flex; align-items: center; justify-content: space-between; padding: 3px 0;';
            }
            div.dataset.settingName = label.toLowerCase().replace(/\s+/g, '-');
            const lbl = document.createElement('label');
            lbl.htmlFor = `${settingKey}-v2`;
            lbl.innerText = label;
            if (parent.id !== 'gui-main-toggles-wrapper') {
                lbl.style.flexGrow = '1';
            } else {
                lbl.style.marginBottom = '2px';
            }
            const cb = document.createElement('input');
            cb.type = 'checkbox';
            cb.id = `${settingKey}-v2`;
            cb.onchange = () => {
                if (GatsModCore.SETTINGS) {
                    GatsModCore.SETTINGS[settingKey] = cb.checked;
                    if (settingKey === 'followBotEnabled' && !cb.checked) {
                        GatsModCore.stopFollowingPlayer?.();
                    }
                    if (settingKey === 'chatScrollEnabled' && !cb.checked) {
                        GatsModCore.stopChatScroll?.();
                    }
                    GatsModCore.saveSettings?.();
                    gatsModInstance?.simpleGui?.updateStatusDisplay?.();
                    if (onChangeCallback) {
                        onChangeCallback(cb.checked);
                    }
                }
            };
            div.appendChild(lbl);
            if (tooltipText) {
                this.addTooltip(lbl, tooltipText);
            }
            div.appendChild(cb);
            parent.appendChild(div);
            return div;
        }

        addCollapsibleSection(title, parent, className = '') {
            const details = document.createElement('details');
            if (className) {
                details.className = className;
            }
            details.dataset.settingName = title.toLowerCase().replace(/\s+/g, '-');
            details.open = false;
            const summary = document.createElement('summary');
            summary.innerText = title;
            details.appendChild(summary);
            const content = document.createElement('div');
            details.appendChild(content);
            parent.appendChild(details);
            return content;
        }

        addSliderInput(label, settingKey, opts, objToUpdate, parent, tooltipText = null) {
            const wrapper = document.createElement('div');
            wrapper.className = 'settings-group-item';
            wrapper.dataset.settingName = label.toLowerCase().replace(/\s+/g, '-');
            const itemContainer = document.createElement('div');
            itemContainer.style.cssText = 'display: flex; flex-direction: column; margin-bottom: 5px;';
            const labelContainer = document.createElement('div');
            labelContainer.style.display = 'flex';
            labelContainer.style.alignItems = 'center';
            const labelElement = document.createElement('label');
            labelElement.htmlFor = `${settingKey}-slider-v2`;
            labelElement.innerText = label;
            labelElement.style.marginBottom = '3px';
            labelContainer.appendChild(labelElement);
            if (tooltipText) {
                this.addTooltip(labelContainer, tooltipText);
            }
            itemContainer.appendChild(labelContainer);
            const controlsContainer = document.createElement('div');
            controlsContainer.style.cssText = 'display: flex; align-items: center; width: 100%;';
            const slider = document.createElement('input');
            slider.type = 'range';
            slider.id = `${settingKey}-slider-v2`;
            slider.min = opts.min;
            slider.max = opts.max;
            slider.step = opts.step;
            slider.value = objToUpdate[settingKey] ?? opts.defaultVal ?? opts.min;
            controlsContainer.appendChild(slider);
            const valueDisplay = document.createElement('input');
            valueDisplay.type = 'number';
            valueDisplay.className = 'value-display';
            valueDisplay.style.width = '55px';
            valueDisplay.min = opts.min;
            valueDisplay.max = opts.max;
            valueDisplay.step = opts.step;
            valueDisplay.value = slider.value;
            controlsContainer.appendChild(valueDisplay);
            const updateValue = (newValue, fromSlider = false) => {
                let numVal = parseFloat(newValue);
                if (isNaN(numVal)) {
                    numVal = opts.defaultVal ?? parseFloat(opts.min);
                }
                numVal = Math.max(parseFloat(opts.min), Math.min(parseFloat(opts.max), numVal));
                const decimals = opts.step.toString().includes('.') ? opts.step.toString().split('.')[1].length : 0;
                const fixedVal = numVal.toFixed(decimals);
                if (fromSlider) {
                    valueDisplay.value = fixedVal;
                } else {
                    slider.value = fixedVal;
                }
                objToUpdate[settingKey] = parseFloat(fixedVal);
                GatsModCore.saveSettings?.();
            };
            slider.oninput = (e) => updateValue(e.target.value, true);
            valueDisplay.onchange = (e) => updateValue(e.target.value, false);
            valueDisplay.onfocus = () => {
                if (GatsModCore) GatsModCore.isInputActive = true;
            };
            valueDisplay.onblur = () => {
                if (GatsModCore) GatsModCore.isInputActive = false;
                updateValue(valueDisplay.value, false);
            };
            itemContainer.appendChild(controlsContainer);
            wrapper.appendChild(itemContainer);
            parent.appendChild(wrapper);
            return wrapper;
        }

        addTextInput(label, settingKey, objToUpdate, parent, onSaveCallback = null, useSaveButton = false, tooltipText = null) {
            const wrapper = document.createElement('div');
            wrapper.className = 'settings-group-item';
            wrapper.dataset.settingName = label.toLowerCase().replace(/\s+/g, '-');
            const labelContainer = document.createElement('div');
            labelContainer.style.display = 'flex';
            labelContainer.style.alignItems = 'center';
            const lbl = document.createElement('label');
            lbl.htmlFor = `${settingKey}-text-v2`;
            lbl.innerText = label;
            lbl.style.display = 'block';
            lbl.style.marginBottom = '3px';
            labelContainer.appendChild(lbl);
            if (tooltipText) {
                this.addTooltip(labelContainer, tooltipText);
            }
            wrapper.appendChild(labelContainer);
            const input = document.createElement('input');
            input.type = 'text';
            input.id = `${settingKey}-text-v2`;
            input.value = objToUpdate[settingKey] || "";
            input.className = 'general-text-input';
            input.style.width = 'calc(100% - 0px)';
            input.onfocus = () => {
                if (GatsModCore) GatsModCore.isInputActive = true;
            };
            input.onblur = () => {
                if (GatsModCore) GatsModCore.isInputActive = false;
                if (!useSaveButton) {
                    objToUpdate[settingKey] = input.value;
                    GatsModCore.saveSettings?.();
                    onSaveCallback?.(input.value);
                }
            };
            wrapper.appendChild(input);
            if (useSaveButton) {
                this.addButton("Save", () => {
                    objToUpdate[settingKey] = input.value;
                    GatsModCore.saveSettings?.();
                    onSaveCallback?.(input.value);
                    if (this.currentScrollingTextDisplay && settingKey === 'chatScrollText') {
                        this.updateScrollingTextDisplay(input.value);
                    }
                    const originalPlaceholder = input.placeholder;
                    input.placeholder = "Saved!";
                    setTimeout(() => {
                        input.placeholder = originalPlaceholder;
                    }, 1200);
                }, wrapper, 'action-btn-small');
            }
            parent.appendChild(wrapper);
            return wrapper;
        }

        addButton(label, onClickAction, parent, className = 'action-btn') {
            const button = document.createElement('button');
            button.innerText = label;
            button.className = className;
            button.onclick = onClickAction;
            parent.appendChild(button);
            return button;
        }

        addTooltip(parentLabelContainer, text) {
            const tooltipTrigger = document.createElement('span');
            tooltipTrigger.className = 'tooltip-trigger';
            tooltipTrigger.innerText = '?';
            const tooltipTextElement = document.createElement('span');
            tooltipTextElement.className = 'tooltip-text';
            tooltipTextElement.innerText = text;
            tooltipTrigger.appendChild(tooltipTextElement);
            parentLabelContainer.appendChild(tooltipTrigger);
        }

        addDiscordButton(parent) {
            const discordBtn = document.createElement('a');
            discordBtn.href = 'https://discord.com/users/975535045047648266';
            discordBtn.target = '_blank';
            discordBtn.rel = 'noopener noreferrer';
            discordBtn.id = 'discord-link-btn';
            discordBtn.innerText = 'Contact zeroarcop on Discord';
            parent.appendChild(discordBtn);
        }

        applyStyles() {
            GM_addStyle(`
                :root {
                    --main-bg: rgba(18,18,18,0.97); --secondary-bg: #1e1e1e; --border-color: #f00; --text-color: #fff;
                    --text-color-light: #fff; --text-color-dim: #aaa; --accent-color: #f00; --accent-border: #b00000;
                    --hover-brightness: 130%; --input-accent: #f00; --status-on: #0f0; --status-off: #f00;
                    --status-neutral: #aaa; --tooltip-bg: #101010; --tooltip-text: #fff; --tooltip-border: var(--accent-color);
                    --btn-action-bg: #d00000; --btn-action-border: #a00000; --btn-profile-bg: #2d2d2d;
                    --btn-profile-text: #e0e0e0; --btn-profile-border: var(--accent-color); --btn-alt-bg: #f0f0f0;
                    --btn-alt-text: #1a1a1a; --btn-alt-border: #aaa; --modal-bg: rgba(0,0,0,0.8);
                    --modal-content-bg: #1a1a1a; --modal-content-border: var(--accent-color); --scrollbar-track: #2d2d2d;
                    --scrollbar-thumb: #aa0000; --scrollbar-thumb-hover: #ff3333; --skill-list-bg: rgba(0,0,0,0.2);
                    --skill-item-bg: var(--secondary-bg); --skill-item-border: var(--accent-border);
                    --skill-item-hover-bg: var(--accent-color);
                }
                #${this.container.id} {
                    position: fixed; left: 20px; top: 70px; background-color: var(--main-bg); color: var(--text-color);
                    padding: 10px; border-radius: 6px; font-family: "Segoe UI", Arial, sans-serif; font-size: 12.5px;
                    z-index: 100002; border: 2px solid var(--accent-color); box-shadow: 0 5px 20px rgba(255,0,0,.4);
                    width: 950px; max-height: calc(100vh - 90px); overflow-y: auto; user-select: none;
                }
                #${this.container.id} #gui-main-content-wrapper { display: flex; flex-direction: column; }
                #${this.container.id} h3 {
                    margin: 0 0 8px; text-align: center; border-bottom: 1px solid var(--accent-border); padding-bottom: 10px;
                    color: var(--accent-color); font-weight: 700; cursor: move; font-size: 16px;
                    text-shadow: 0 0 5px var(--accent-color);
                }
                #${this.container.id} #gui-status-bar {
                    background-color: rgba(10,10,10,0.85); color: #fff; padding: 6px 12px; margin-bottom: 10px;
                    text-align: center; font-size: 12.5px; font-weight: 700; border-radius: 4px;
                    border: 1px solid var(--accent-border);
                }
                #${this.container.id} #gui-status-bar .status-on { color: var(--status-on); font-weight: 700; }
                #${this.container.id} #gui-status-bar .status-off { color: var(--status-off); font-weight: 700; }
                #${this.container.id} #gui-status-bar .status-neutral { color: var(--status-neutral); }
                #${this.container.id} #gui-hotkey-info {
                    font-size: 11px; text-align: center; margin: 2px 0 10px; color: var(--text-color-dim);
                }
                #${this.container.id} #gui-top-bar-wrapper {
                    display: flex; gap: 10px; margin-bottom: 10px; border-bottom: 1px solid var(--accent-border); padding-bottom: 10px;
                }
                #${this.container.id} #settings-search-box {
                    flex-grow: 1; background-color: var(--secondary-bg); color: var(--text-color-light);
                    border: 1px solid var(--accent-border); border-radius: 3px; padding: 5px 8px;
                }
                #${this.container.id} #profile-manager { display: flex; gap: 5px; align-items: center; }
                #${this.container.id} #profile-manager button,
                #${this.container.id} #profile-manager input,
                #${this.container.id} #profile-manager select {
                    font-size: 11px; padding: 4px; background-color: var(--btn-profile-bg);
                    color: var(--btn-profile-text); border: 1px solid var(--btn-profile-border); border-radius: 3px;
                }
                #${this.container.id} #profile-manager button {
                    cursor: pointer; background-color: var(--accent-color); border-color: var(--accent-border);
                    color: var(--text-color-light);
                }
                #${this.container.id} #profile-manager button:hover { filter: brightness(var(--hover-brightness)); }
                #${this.container.id} #gui-main-toggles-wrapper {
                    display: flex; flex-wrap: wrap; justify-content: space-around; margin-bottom: 10px;
                    padding-bottom: 10px; border-bottom: 1px solid var(--accent-border);
                }
                #${this.container.id} #gui-main-toggles-wrapper > div {
                    display: flex; flex-direction: column; align-items: center; padding: 2px 5px; margin: 0 5px;
                    min-width: 90px; text-align: center;
                }
                #${this.container.id} #gui-main-toggles-wrapper label {
                    color: var(--text-color-light); font-size: 11.5px; margin-bottom: 2px;
                }
                #${this.container.id} #gui-main-toggles-wrapper input[type=checkbox] {
                    margin-top: 1px; accent-color: var(--input-accent);
                }
                #${this.container.id} #gui-columns-wrapper {
                    display: flex; flex-direction: row; justify-content: space-between; gap: 10px;
                }
                #${this.container.id} .gui-column {
                    width: calc(33.33% - 7px); display: flex; flex-direction: column; gap: 5px;
                }
                #${this.container.id} details {
                    border: 1px solid var(--border-color); border-radius: 4px; padding: 0; margin: 0 0 8px;
                    background-color: rgba(30,30,30,0.75);
                }
                #${this.container.id} summary {
                    cursor: pointer; outline: 0; font-weight: 600; color: var(--accent-color); padding: 6px 8px;
                    font-size: 13px; border-radius: 3px 3px 0 0; transition: background-color .2s;
                    border-bottom: 1px solid transparent;
                }
                #${this.container.id} details[open] > summary {
                    border-bottom: 1px solid var(--accent-border); background-color: rgba(255,0,0,0.05);
                }
                #${this.container.id} details > div { padding: 10px 8px 8px; }
                #${this.container.id} .settings-group-item { margin-bottom: 8px; }
                #${this.container.id} .settings-group-item label {
                    color: var(--text-color-light); margin-left: 0; flex-shrink: 0; display: block;
                    min-width: 100px; font-size: 12px; margin-bottom: 3px;
                }
                #${this.container.id} .settings-group-item div[style*="display: flex; align-items: center; justify-content: space-between;"] label {
                    display: inline-block; flex-grow: 1; margin-bottom: 0;
                }
                #${this.container.id} .settings-group-item input[type=checkbox] {
                    accent-color: var(--input-accent); border: 1px solid var(--accent-border);
                    vertical-align: middle; margin-left: 5px;
                }
                #${this.container.id} input[type=number].value-display {
                    width: 55px; background-color: var(--secondary-bg); color: var(--text-color);
                    border: 1px solid var(--accent-border); border-radius: 3px; padding: 4px 5px;
                    text-align: right; font-family: "Segoe UI", Arial, sans-serif; margin: 0 4px; font-size: 11.5px;
                }
                #${this.container.id} input[type=range] {
                    flex-grow: 1; margin: 0 4px; accent-color: var(--input-accent); height: 22px;
                }
                #${this.container.id} .settings-group-item div[style*="display: flex; align-items: center; width: 100%;"] { height: 26px; }
                #${this.container.id} input[type=text].general-text-input,
                #${this.container.id} input[type=text][id^=aimbotExcludeInput-text-v2],
                #${this.container.id} input[type=text][id^=obstacleEspTypes-text-v2] {
                    width: calc(100% - 0px); box-sizing: border-box; background-color: var(--secondary-bg);
                    color: var(--text-color-light); border: 1px solid var(--accent-border); border-radius: 3px;
                    padding: 5px; margin-bottom: 5px;
                }
                #${this.container.id} button.action-btn,
                #${this.container.id} button.custom-btn {
                    background-color: var(--btn-action-bg); color: #fff; border: 1px solid var(--btn-action-border);
                    margin-top: 10px; padding: 7px 10px; display: block; width: 100%; box-sizing: border-box;
                    border-radius: 3px; cursor: pointer; font-weight: 500; font-size: 12.5px; text-transform: uppercase;
                }
                #${this.container.id} button.action-btn-small {
                    background-color: var(--btn-action-bg); color: #fff; border: 1px solid var(--btn-action-border);
                    padding: 4px 8px; font-size: 11px; margin-top: 5px; width: auto; border-radius: 3px; cursor: pointer;
                }
                #${this.container.id} button.action-btn-third {
                    width: calc(33.33% - 4px); display: inline-block; margin: 2px;
                    background-color: var(--btn-alt-bg); color: var(--btn-alt-text);
                    border: 1px solid var(--btn-alt-border); padding: 5px 8px; font-size: 11.5px;
                    text-transform: none; border-radius: 3px; cursor: pointer;
                }
                #${this.container.id} #bot-control-panel button.action-btn {
                    background-color: var(--btn-action-bg); color: #fff; border: 1px solid var(--btn-action-border);
                }
                #${this.container.id} button.action-btn-half {
                    width: calc(50% - 5px); margin: 2px; padding: 5px; font-size: 11.5px;
                    background-color: var(--btn-action-bg); color: #fff;
                    border: 1px solid var(--btn-action-border); border-radius: 3px; cursor: pointer;
                }
                #${this.container.id} button.edit-preset-btn-item,
                #${this.container.id} button.preset-btn-item {
                    min-width: auto; width: auto; margin: 0; padding: 4px 7px; display: inline-block;
                    background-color: var(--btn-profile-bg); color: var(--btn-profile-text); font-size: 11px;
                    line-height: 1.4; border: 1px solid var(--btn-profile-border); border-radius: 3px; cursor: pointer;
                }
                #${this.container.id} button.edit-preset-btn-item {
                    padding: 3px 6px; font-size: 10px; background-color: var(--accent-color); color: #fff;
                }
                #${this.container.id} button:hover { filter: brightness(var(--hover-brightness)); }
                #${this.container.id} button.action-btn-third:hover {
                    background-color: #e0e0e0; filter: brightness(95%);
                }
                #${this.container.id} .tooltip-trigger {
                    display: inline-block; margin-left: 6px; color: var(--text-color-dim);
                    background-color: var(--secondary-bg); border: 1px solid var(--accent-border);
                    border-radius: 50%; width: 14px; height: 14px; font-size: 10px;
                    text-align: center; line-height: 14px; cursor: help; position: relative;
                }
                #${this.container.id} .tooltip-text {
                    visibility: hidden; width: 220px; background-color: var(--tooltip-bg); color: var(--tooltip-text);
                    text-align: center; border-radius: 6px; padding: 8px; position: absolute; z-index: 100003;
                    bottom: 125%; left: 50%; margin-left: -110px; opacity: 0; transition: opacity .3s;
                    border: 1px solid var(--tooltip-border); font-size: 11px; line-height: 1.4;
                }
                #${this.container.id} .tooltip-trigger:hover .tooltip-text { visibility: visible; opacity: 1; }
                #player-list-modal {
                    display: none; position: fixed; z-index: 100003; left: 0; top: 0; width: 100%; height: 100%;
                    background-color: var(--modal-bg); justify-content: center; align-items: center;
                }
                #player-list-content {
                    background-color: var(--modal-content-bg); padding: 20px;
                    border: 1px solid var(--modal-content-border); border-radius: 8px; width: 80%;
                    max-width: 500px; max-height: 80vh; overflow-y: auto;
                    box-shadow: 0 0 15px rgba(255,0,0,0.5);
                }
                #player-list-content h4 {
                    margin-top: 0; color: var(--accent-color); text-align: center; font-size: 1.2em;
                }
                #player-list-grid {
                    display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 8px;
                }
                .player-list-button {
                    background-color: var(--secondary-bg); color: var(--text-color-light);
                    border: 1px solid var(--accent-border); padding: 8px; text-align: center;
                    border-radius: 4px; cursor: pointer; overflow: hidden;
                    text-overflow: ellipsis; white-space: nowrap;
                }
                .player-list-button:hover { background-color: var(--accent-color); color: #fff; }
                #${this.container.id} #gui-footer {
                    margin-top: 15px; padding-top: 10px; border-top: 1px solid var(--accent-border); text-align: center;
                }
                #${this.container.id} #discord-link-btn {
                    display: inline-block; padding: 8px 15px; background-color: #5865F2; color: #fff;
                    text-decoration: none; border-radius: 4px; font-weight: bold; font-size: 13px;
                    transition: background-color .2s;
                }
                #${this.container.id} #discord-link-btn:hover { background-color: #4752C4; }
                #${this.container.id}::-webkit-scrollbar { width: 10px; }
                #${this.container.id}::-webkit-scrollbar-track {
                    background: var(--scrollbar-track); border-radius: 4px;
                }
                #${this.container.id}::-webkit-scrollbar-thumb {
                    background: var(--scrollbar-thumb); border-radius: 4px;
                }
                #${this.container.id}::-webkit-scrollbar-thumb:hover { background: var(--scrollbar-thumb-hover); }
                #${this.container.id} .settings-group-item > div[style*="flex-direction: column"] { margin-bottom: 0; }
            `);
        }

        populateColumn1_ESP() {
            if (!this.column1 || !GatsModCore.SETTINGS) return;
            const espMasterSection = this.addCollapsibleSection('ESP Configuration', this.column1, 'settings-group-master');
            const visualEspOptions = this.addCollapsibleSection('Player ESP Visuals', espMasterSection, 'settings-sub-group');
            this.addCheckbox('Show Enemy HP', 'espShowHP', visualEspOptions, 'Display health bars above players.');
            this.addCheckbox('Highlight Low HP Enemies', 'espHighlightLowHP', visualEspOptions, 'Change ESP color for enemies with low health.');
            this.addSliderInput('Low HP Threshold (%)', 'lowHPThreshold', {min: 1, max: 99, step: 1, defaultVal: 30}, GatsModCore.SETTINGS, visualEspOptions, 'Health % below which an enemy is considered low HP.');
            this.addCheckbox('Show Prediction Line', 'espShowPrediction', visualEspOptions, 'Draws a line from enemies to their predicted position. Requires aimbot prediction to be enabled.');
            this.addCheckbox('Show Enemy Facing Line', 'espShowFacingLine', visualEspOptions, 'Draw a line indicating player aim direction.');
            this.addCheckbox('Highlight Cloaked Enemies', 'espHighlightCloaked', visualEspOptions, 'Special indicator for cloaked enemies. Works best with Ghost Detect enabled.');
            this.addCheckbox('Show Teammates (TDM)', 'espShowTeammates', visualEspOptions, 'Enable ESP for your teammates.');
            const espPositioningSection = this.addCollapsibleSection('ESP Positioning & Visual Scale', espMasterSection, 'settings-sub-group');
            this.addSliderInput('X Offset (Global)', 'espOffsetX', {min: -200, max: 200, step: 1, defaultVal: 0}, GatsModCore.SETTINGS, espPositioningSection, 'Shift all ESP elements horizontally.');
            this.addSliderInput('Y Offset (Global)', 'espOffsetY', {min: -200, max: 200, step: 1, defaultVal: 0}, GatsModCore.SETTINGS, espPositioningSection, 'Shift all ESP elements vertically.');
            this.addSliderInput('ESP Visual Scale', 'espScale', {min: 0.1, max: 5.0, step: 0.05, defaultVal: 0.89}, GatsModCore.SETTINGS, espPositioningSection, 'Global visual scale for ESP elements (boxes, lines, text).');
            const debugPreviewSection = this.addCollapsibleSection('Debug Previews', espMasterSection, 'settings-sub-group');
            this.addCheckbox('Show Attack Radius', 'autoAttackShowRadius', debugPreviewSection, 'Displays the Smart Auto-Attack engagement radius on screen.');
            this.addCheckbox('Show Obstacle Hitboxes', 'obstacleEspEnabled', debugPreviewSection, 'Displays obstacle hitboxes for debugging line-of-sight.');
            this.addCheckbox('Show LOS Debug Line', 'losDebugLineEnabled', debugPreviewSection, 'Draws the line used for the line-of-sight check. Green = clear, Red = blocked.');
            this.addCheckbox('Show Bullet Dodge Warnings', 'espShowBulletWarnings', debugPreviewSection, 'Displays the warning radius around enemy bullets used by the AI for dodging.');
            this.addCheckbox('Show AI Pathfinding Whiskers', 'aiShowPathfindingWhiskers', debugPreviewSection, 'Displays the AI\'s obstacle avoidance check lines (whiskers).');
            this.addCheckbox('Show AI Final Move Direction', 'aiShowFinalMoveDirection', debugPreviewSection, 'Displays a line indicating the AI\'s final movement decision.');
            this.addCheckbox('Show Enemy Threat Line', 'aiShowEnemyThreatLine', debugPreviewSection, 'Draws a line from the nearest enemy\'s gun to you if the line of sight is clear.');

            this.addSliderInput('Obstacle X Offset', 'obstacleOffsetX', {min: -100, max: 100, step: 1, defaultVal: 0}, GatsModCore.SETTINGS, debugPreviewSection, 'Fine-tune the horizontal position of obstacle hitboxes.');
            this.addSliderInput('Obstacle Y Offset', 'obstacleOffsetY', {min: -100, max: 100, step: 1, defaultVal: 0}, GatsModCore.SETTINGS, debugPreviewSection, 'Fine-tune the vertical position of obstacle hitboxes.');
        }

        populateColumn2_Aimbot() {
            if (!this.column2 || !GatsModCore.SETTINGS) return;
            const aimbotMasterSection = this.addCollapsibleSection('Aimbot & Auto-Attack', this.column2, 'settings-group-master');
            const autoAttackSection = this.addCollapsibleSection('Smart Auto-Attack', aimbotMasterSection, 'settings-sub-group');
            this.addSliderInput('Attack Radius (px)', 'autoAttackRadius', {min: 0, max: 1000, step: 10, defaultVal: 400}, GatsModCore.SETTINGS, autoAttackSection, 'The bot will only shoot at targets within this screen radius from the center.');
            this.addCheckbox('Check Line of Sight', 'autoAttackCheckLOS', autoAttackSection, 'Prevents shooting if an obstacle is between you and the target.');
            this.addCheckbox('Check Max Weapon Range', 'autoAttackCheckRange', autoAttackSection, 'Prevents shooting if the predicted target position is outside your weapon\'s maximum range.');

            const generalAimbotOptions = this.addCollapsibleSection('Aimbot - General Targeting', aimbotMasterSection, 'settings-sub-group');
            this.addCheckbox('Always Aim (No Mouse Press)', 'alwaysAim', generalAimbotOptions, 'Aimbot aims even if mouse button is not pressed.');
            this.addCheckbox('Activate Aimbot Only On Mouse Press', 'aimbotOnMousePress', generalAimbotOptions, 'Aimbot only activates on mouse press (unless "Always Aim" is on).');
            this.addCheckbox('Target Closest to Mouse', 'aimAtMouseClosest', generalAimbotOptions, 'Prioritizes the enemy closest to your mouse cursor.');
            this.addSliderInput('Aimbot FOV', 'aimbotFov', {min: 10, max: 5000, step: 10, defaultVal: 2250}, GatsModCore.SETTINGS, generalAimbotOptions, 'Field of View for the aimbot.');

            const spinbotOptions = this.addCollapsibleSection('Spinbot Settings', aimbotMasterSection, 'settings-sub-group');
            this.addSliderInput('Spinbot Speed (ms)', 'spinbotSpeedMs', {min: 10, max: 500, step: 10, defaultVal: 75}, GatsModCore.SETTINGS, spinbotOptions, "Time between spinbot aim changes (lower is faster).");
            this.addSliderInput('Spinbot Distance', 'spinbotDistance', {min: 50, max: 500, step: 10, defaultVal: 150}, GatsModCore.SETTINGS, spinbotOptions, "Distance from player for spin target points (world units).");

            const predictionSettings = this.addCollapsibleSection('Aimbot - Prediction', aimbotMasterSection, 'settings-sub-group');
            this.addCheckbox('Prediction Enabled', 'predictionEnabled', predictionSettings, 'Aimbot will predict enemy movement.');
            this.addCheckbox('Use Close-Range Prediction', 'useCloseRangePrediction', predictionSettings, 'Use a separate prediction factor for enemies within a certain radius of the screen center.');
            this.addSliderInput('Close-Range Radius (px)', 'predictionCloseRadius', { min: 0, max: 300, step: 5, defaultVal: 100 }, GatsModCore.SETTINGS, predictionSettings, 'If an enemy is within this pixel radius from your screen center, the close-range prediction factor will be used.');
            this.addSliderInput('Prediction Factor (Close)', 'predictionFactorClose', {min: 0.0, max: 5.0, step: 0.1, defaultVal: 0.5}, GatsModCore.SETTINGS, predictionSettings, 'Prediction multiplier for close-range targets.');
            this.addSliderInput('Prediction Factor (Normal)', 'predictionFactor', {min: 0.0, max: 5.0, step: 0.1, defaultVal: 2.5}, GatsModCore.SETTINGS, predictionSettings, 'Main multiplier for movement prediction (for targets outside the close-range radius).');
            this.addCheckbox('Dynamic Prediction Scaling', 'enableDynamicPredictionFactor', predictionSettings, 'Adjust normal prediction factor based on distance to target.');
            this.addSliderInput('Min Prediction Dist', 'minPredictionDistance', {min: 0, max: 1000, step: 10, defaultVal: 0}, GatsModCore.SETTINGS, predictionSettings, 'Distance where dynamic prediction scaling starts.');
            this.addSliderInput('Max Prediction Dist', 'maxPredictionDistance', {min: 50, max: 2000, step: 10, defaultVal: 200}, GatsModCore.SETTINGS, predictionSettings, 'Distance where prediction factor reaches its max value.');
            this.addSliderInput('Factor at Min Dist', 'predictionFactorAtMinDistance', {min: 0.0, max: 2.0, step: 0.1, defaultVal: 0.0}, GatsModCore.SETTINGS, predictionSettings, 'Prediction multiplier used at (or below) the minimum distance.');

            this.addAimbotExclusionListToColumn2(aimbotMasterSection);
        }

        addAimbotExclusionListToColumn2(aimbotMasterSection) {
            if (!aimbotMasterSection || !GatsModCore.SETTINGS) return;
            const aimbotExclusionSection = this.addCollapsibleSection('Aimbot - Target Exclusion List', aimbotMasterSection, 'settings-sub-group');
            const mainDiv = document.createElement('div');
            mainDiv.className = 'settings-group-item';
            const inputLabel = document.createElement('label');
            inputLabel.htmlFor = 'aimbotExcludeInput-text-v2';
            inputLabel.innerText = 'Player Name to Ignore:';
            inputLabel.style.display = 'block';
            inputLabel.style.marginBottom = '3px';
            mainDiv.appendChild(inputLabel);
            const input = document.createElement('input');
            input.type = 'text';
            input.id = 'aimbotExcludeInput-text-v2';
            input.placeholder = 'Enter name or click player with Alt';
            input.className = 'general-text-input';
            mainDiv.appendChild(input);
            const addButton = this.addButton("Add to Ignore List", () => {
                const name = input.value.trim();
                if (name && GatsModCore.SETTINGS.aimbotIgnoreList) {
                    if (!GatsModCore.SETTINGS.aimbotIgnoreList.includes(name)) {
                        GatsModCore.SETTINGS.aimbotIgnoreList.push(name);
                        GatsModCore.saveSettings();
                        this.updateAimbotExclusionListDisplay();
                        input.value = '';
                    } else {
                        alert(`Player "${name}" is already on the ignore list.`);
                    }
                }
            }, mainDiv, 'action-btn-small');
            addButton.style.display = 'inline-block';
            addButton.style.marginLeft = '5px';
            const listLabel = document.createElement('p');
            listLabel.innerText = 'Currently Ignored Players:';
            listLabel.style.marginTop = '10px';
            listLabel.style.fontWeight = 'bold';
            mainDiv.appendChild(listLabel);
            this.aimbotExclusionListDiv = document.createElement('div');
            this.aimbotExclusionListDiv.id = 'aimbot-exclusion-list-display';
            this.aimbotExclusionListDiv.style.cssText = `
                max-height: 100px; overflow-y: auto; border: 1px solid var(--accent-border, #B00000);
                padding: 5px; border-radius: 3px; margin-top: 5px;
                background-color: var(--secondary-bg, #1E1E1E);
            `;
            mainDiv.appendChild(this.aimbotExclusionListDiv);
            aimbotExclusionSection.appendChild(mainDiv);
            this.updateAimbotExclusionListDisplay();
        }

        updateAimbotExclusionListDisplay() {
            if (!this.aimbotExclusionListDiv || !GatsModCore.SETTINGS?.aimbotIgnoreList) {
                if (this.aimbotExclusionListDiv) this.aimbotExclusionListDiv.innerHTML = '<span>Not available</span>';
                return;
            }
            this.aimbotExclusionListDiv.innerHTML = '';
            if (GatsModCore.SETTINGS.aimbotIgnoreList.length === 0) {
                const noItems = document.createElement('span');
                noItems.textContent = 'None';
                noItems.style.color = 'var(--text-color-dim)';
                this.aimbotExclusionListDiv.appendChild(noItems);
                return;
            }
            GatsModCore.SETTINGS.aimbotIgnoreList.forEach(name => {
                const itemDiv = document.createElement('div');
                itemDiv.style.cssText = `
                    display: flex; justify-content: space-between; align-items: center;
                    padding: 3px 2px; border-bottom: 1px solid var(--accent-border);
                `;
                const nameSpan = document.createElement('span');
                nameSpan.textContent = name;
                nameSpan.style.cssText = `
                    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-right: 10px;
                `;
                nameSpan.title = name;
                const removeBtn = document.createElement('button');
                removeBtn.textContent = 'X';
                removeBtn.title = `Remove ${name} from ignore list`;
                removeBtn.style.cssText = `
                    color: var(--text-color-light, white); background-color: var(--btn-action-bg, #D00000);
                    border: 1px solid var(--btn-action-border, #A00000); padding: 1px 5px; font-size: 10px;
                    cursor: pointer; border-radius: 3px; line-height: 1;
                `;
                removeBtn.onclick = () => {
                    GatsModCore.SETTINGS.aimbotIgnoreList = GatsModCore.SETTINGS.aimbotIgnoreList.filter(n => n !== name);
                    GatsModCore.saveSettings();
                    this.updateAimbotExclusionListDisplay();
                };
                itemDiv.appendChild(nameSpan);
                itemDiv.appendChild(removeBtn);
                this.aimbotExclusionListDiv.appendChild(itemDiv);
            });
        }

        populateColumn3_Utilities() {
            if (!this.column3 || !GatsModCore.SETTINGS) return;

            this.populateColumn3_ZeroAI(this.column3);
            this.populateColumn3_Multiboxing(this.column3);

            const utilitiesMasterSection = this.addCollapsibleSection('Utilities', this.column3, 'settings-group-master');

            const botControlPanel = this.addCollapsibleSection('Follow Bot Control', utilitiesMasterSection, 'settings-sub-group');
            botControlPanel.id = 'bot-control-panel';
            this.addCheckbox('Enable Follow Bot', 'followBotEnabled', botControlPanel, 'Enable the physics-based follow bot.');
            this.addSliderInput('Bot Attack Radius', 'followBotAttackRadius', {min: 0, max: 800, step: 10, defaultVal: 500}, GatsModCore.SETTINGS, botControlPanel, 'Follow Bot will attack enemies within this radius.');
            this.followBotStatusDisplay = document.createElement('div');
            this.followBotStatusDisplay.style.textAlign = 'center';
            this.followBotStatusDisplay.style.marginTop = '5px';
            botControlPanel.appendChild(this.followBotStatusDisplay);
            const followButtons = document.createElement('div');
            followButtons.style.cssText = 'display: flex; justify-content: space-around; margin-top: 5px; flex-wrap: wrap;';
            this.addButton("Set Target by Name", () => GatsModCore.setFollowTargetName?.(), followButtons, 'action-btn-third');
            this.addButton("Select Target from List", () => GatsModCore.showPlayerList?.(), followButtons, 'action-btn-third');
            this.addButton("Start Following", () => gatsModInstance?.startFollowingPlayer?.(), followButtons, 'action-btn-third');
            this.addButton("Stop Following", () => GatsModCore.stopFollowingPlayer?.(), followButtons, 'action-btn');
            botControlPanel.appendChild(followButtons);

            const chatScrollerMasterSection = this.addCollapsibleSection('Chat Scroller (Enhanced)', utilitiesMasterSection, 'settings-sub-group');
            this.addCheckbox('Enable Chat Scroller', 'chatScrollEnabled', chatScrollerMasterSection, 'Enables the auto chat message scroller.');
            this.currentScrollingTextDisplay = document.createElement('div');
            this.currentScrollingTextDisplay.style.cssText = `
                margin: 5px 0; padding: 5px; background-color: var(--secondary-bg);
                border: 1px solid var(--accent-border); border-radius: 3px; font-style: italic;
                color: var(--text-color-dim); word-break: break-all; min-height: 20px; font-size: 11px;
            `;
            chatScrollerMasterSection.appendChild(this.currentScrollingTextDisplay);
            this.addButton("Set Scroll Text", () => {
                const newText = prompt("Enter the text to scroll in chat:", GatsModCore.SETTINGS.chatScrollText);
                if (newText !== null) {
                    GatsModCore.SETTINGS.chatScrollText = newText;
                    this.updateScrollingTextDisplay(newText);
                    GatsModCore.saveSettings();
                }
            }, chatScrollerMasterSection, 'action-btn-small');
            const scrollButtons = document.createElement('div');
            scrollButtons.style.cssText = 'display: flex; justify-content: space-around; margin-top: 5px;';
            this.addButton("Start Scroll", () => GatsModCore.startChatScroll?.(), scrollButtons, 'action-btn-half');
            this.addButton("Stop Scroll", () => GatsModCore.stopChatScroll?.(), scrollButtons, 'action-btn-half');
            chatScrollerMasterSection.appendChild(scrollButtons);

            const customMsgSection = this.addCollapsibleSection('Custom Message & Presets', chatScrollerMasterSection, 'settings-sub-group');
            const presetLabel = document.createElement('p');
            presetLabel.innerText = 'Presets (1-9 to use / Edit):';
            presetLabel.style.cssText = 'text-align: left; margin-top: 10px; color: var(--text-color-light);';
            customMsgSection.appendChild(presetLabel);
            const presetButtonContainer = document.createElement('div');
            presetButtonContainer.style.cssText = 'display: grid; grid-template-columns: 1fr auto; gap: 5px; align-items: center;';
            if (GatsModCore.SETTINGS.chatPresetMessages?.length) {
                GatsModCore.SETTINGS.chatPresetMessages.forEach((msg, i) => {
                    const presetDiv = document.createElement('div');
                    presetDiv.style.cssText = 'display: flex; align-items: center; margin-bottom: 3px;';
                    const useBtn = this.addButton(`${i+1}: ${msg.substring(0,12)}${msg.length > 12 ? '...' : ''}`, () => GatsModCore.setScrollPreset?.(i), presetDiv, 'preset-btn-item');
                    useBtn.title = `Use: ${msg}`;
                    useBtn.style.cssText = 'flex-grow: 1; margin-right: 5px; text-align: left;';
                    const editBtn = this.addButton("Edit", (e) => {
                        e.stopPropagation();
                        GatsModCore.editScrollPreset?.(i);
                    }, presetDiv, 'edit-preset-btn-item');
                    this.presetEditButtons[i] = { useBtn: useBtn, originalText: msg };
                    presetButtonContainer.appendChild(presetDiv);
                });
            }
            customMsgSection.appendChild(presetButtonContainer);

            const speedOptionsSection = this.addCollapsibleSection('Scroller Speed & Options', chatScrollerMasterSection, 'settings-sub-group');
            this.addSliderInput('Scroll Speed (ms)', 'chatScrollSpeed', {min: 10, max: 2000, step: 10, defaultVal: 200}, GatsModCore.SETTINGS, speedOptionsSection, "Delay between scroll updates.");
            this.addSliderInput('Max Chars Displayed', 'chatScrollMaxLength', {min: 5, max: 60, step: 1, defaultVal: 28}, GatsModCore.SETTINGS, speedOptionsSection, "Max characters per message.");

            const sequencerSection = this.addCollapsibleSection('Chat Sequencer', utilitiesMasterSection, 'settings-sub-group');
            this.addCheckbox('Enable Sequencer', 'sequencerEnabled', sequencerSection, 'Enables the preset message sequencer.');
            this.addSliderInput('Sequence Delay (ms)', 'sequencerDelay', {min: 10, max: 500, step: 5, defaultVal: 100}, GatsModCore.SETTINGS, sequencerSection, 'Delay between each message in the sequence.');
            this.addCheckbox('Loop Sequence', 'sequencerLoop', sequencerSection, 'Loop the sequence after it finishes.');
            const sequenceButtons = document.createElement('div');
            sequenceButtons.style.cssText = 'display: flex; justify-content: space-around; margin-top: 5px;';
            this.addButton("Start Sequence", () => GatsModCore.startSequencer?.(), sequenceButtons, 'action-btn-half');
            this.addButton("Stop Sequence", () => GatsModCore.stopSequencer?.(), sequenceButtons, 'action-btn-half');
            sequencerSection.appendChild(sequenceButtons);
            const sequenceInfo = document.createElement('p');
            sequenceInfo.innerText = 'Sequencer will send presets 1 through 9 in order.';
            sequenceInfo.style.cssText = 'font-size: 11px; text-align: center; margin-top: 8px; color: var(--text-color-dim);';
            sequencerSection.appendChild(sequenceInfo);

            const eventChatSection = this.addCollapsibleSection('Event-Triggered Chat', utilitiesMasterSection, 'settings-sub-group');
            this.addCheckbox('Enable On-Kill Chat', 'onKillChatEnabled', eventChatSection, 'Automatically say "ez" when you get a kill.');
            this.addCheckbox('Enable Parrot Chat', 'parrotChatEnabled', eventChatSection, 'Repeats what other players say in chat.');
        }

        populateColumn3_ZeroAI(parent) {
            if (!parent || !GatsModCore.SETTINGS) return;

            const aiMasterSection = this.addCollapsibleSection('Zero AI', parent, 'settings-group-master');
            aiMasterSection.open = true;

            this.addCheckbox('Enable Zero AI', 'zeroAIEnabled', aiMasterSection, 'Master switch to enable all AI functionalities. Disables manual movement.');

            const movementSection = this.addCollapsibleSection('AI Movement & Positioning', aiMasterSection, 'settings-sub-group');
            this.addCheckbox('Auto Movement', 'aiAutoMovement', movementSection, 'Automatically seeks enemies, follows a target, or patrols to the map center. Includes obstacle avoidance.');
            this.addCheckbox('Auto Retreat', 'aiAutoRetreat', movementSection, 'Automatically moves away from enemies when HP is low or while reloading.');
            this.addCheckbox('Bullet Dodging', 'aiBulletDodging', movementSection, 'Highest priority: attempts to dodge incoming enemy bullets.');
            this.addCheckbox('Optimal Distance Kiting', 'aiEnableKiting', movementSection, 'When having a range advantage, the AI will try to keep the optimal distance to attack the enemy while staying out of their range.');
            this.addSliderInput('Retreat HP (%)', 'aiRetreatHP', {min: 1, max: 99, step: 1, defaultVal: 35}, GatsModCore.SETTINGS, movementSection, 'HP percentage below which the AI will try to retreat.');

            const actionsSection = this.addCollapsibleSection('AI Actions', aiMasterSection, 'settings-sub-group');
            this.addCheckbox('Auto Park Usage', 'aiAutoParkUsage', actionsSection, 'Automatically uses abilities (Space Bar) like Dash or Grenade when available.');
            this.addCheckbox('Auto Talk (Chat)', 'aiAutoTalk', actionsSection, 'Allows the AI to chat based on game events and other players\' messages. Gives the AI a personality.');
        }

        populateColumn3_Multiboxing(parent) {
            if (!parent || !GatsModCore.SETTINGS) return;

            const multiboxMasterSection = this.addCollapsibleSection('Multiboxing', parent, 'settings-group-master');
            multiboxMasterSection.open = true;

            this.addCheckbox('Enable Multiboxing', 'multiboxEnabled', multiboxMasterSection, 'Enables Parent/Child AI cooperation across two tabs.', (checked) => {
                if (gatsModInstance?.multibox) {
                    if (checked) {
                        gatsModInstance.multibox.start();
                    } else {
                        gatsModInstance.multibox.stop();
                    }
                }
            });

            const statusContainer = document.createElement('div');
            statusContainer.style.cssText = `
                padding: 5px; margin-top: 5px; background-color: var(--secondary-bg);
                border: 1px solid var(--accent-border); border-radius: 3px; font-size: 11px;
            `;

            this.multiboxRoleDisplay = this.addStatusRow(statusContainer, 'Role:');
            this.multiboxPartnerDisplay = this.addStatusRow(statusContainer, 'Partner:');
            this.multiboxStatusDisplay = this.addStatusRow(statusContainer, 'Status:');

            multiboxMasterSection.appendChild(statusContainer);
            this.addButton('Reset Connection', () => gatsModInstance?.multibox?.reset(), multiboxMasterSection, 'action-btn-small');
        }

        addStatusRow(parent, label) {
            const row = document.createElement('div');
            row.style.cssText = 'display: flex; justify-content: space-between; margin-bottom: 3px;';
            const labelSpan = document.createElement('span');
            labelSpan.textContent = label;
            labelSpan.style.color = 'var(--text-color-dim)';
            const valueSpan = document.createElement('span');
            valueSpan.textContent = 'N/A';
            valueSpan.style.fontWeight = 'bold';
            row.appendChild(labelSpan);
            row.appendChild(valueSpan);
            parent.appendChild(row);
            return valueSpan;
        }

        updateMultiboxStatus(role, partner, status) {
            if (this.multiboxRoleDisplay) this.multiboxRoleDisplay.textContent = role;
            if (this.multiboxPartnerDisplay) this.multiboxPartnerDisplay.textContent = partner;
            if (this.multiboxStatusDisplay) this.multiboxStatusDisplay.textContent = status;
        }

        addSearchBox(parent) {
            const searchBox = document.createElement('input');
            searchBox.type = 'text';
            searchBox.id = 'settings-search-box';
            searchBox.placeholder = 'Search settings...';
            searchBox.oninput = (e) => {
                const query = e.target.value.toLowerCase().trim();
                this.container.querySelectorAll('[data-setting-name]').forEach(el => {
                    let isParentOfVisible = false;
                    if (el.tagName === 'DETAILS' && !el.classList.contains('settings-sub-group')) {
                        el.querySelectorAll('[data-setting-name]').forEach(childEl => {
                            if (childEl.dataset.settingName.includes(query) && childEl.style.display !== 'none') {
                                isParentOfVisible = true;
                            }
                        });
                    }
                    const matchesQuery = el.dataset.settingName.includes(query);
                    el.style.display = (matchesQuery || isParentOfVisible) ? '' : 'none';
                    if (isParentOfVisible && el.tagName === 'DETAILS' && query) {
                        el.open = true;
                    }
                });
            };
            parent.appendChild(searchBox);
        }

        addProfileManager(parent) {
            const managerDiv = document.createElement('div');
            managerDiv.id = 'profile-manager';
            const selectLabel = document.createElement('span');
            selectLabel.innerText = 'Profile: ';
            selectLabel.style.marginRight = '5px';
            managerDiv.appendChild(selectLabel);
            const selectElement = document.createElement('select');
            selectElement.id = 'profile-select-v2';
            managerDiv.appendChild(selectElement);
            this.profileSelectElement = selectElement;
            const nameInput = document.createElement('input');
            nameInput.type = 'text';
            nameInput.id = 'profile-name-input-v2';
            nameInput.placeholder = 'Profile Name';
            nameInput.style.width = '100px';
            managerDiv.appendChild(nameInput);
            this.addButton("Save", () => GatsModCore.saveProfile?.(nameInput.value), managerDiv, 'action-btn-small profile-btn');
            this.addButton("Load", () => GatsModCore.loadProfile?.(selectElement.value), managerDiv, 'action-btn-small profile-btn');
            this.addButton("Delete", () => GatsModCore.deleteProfile?.(selectElement.value), managerDiv, 'action-btn-small profile-btn');
            parent.appendChild(managerDiv);
        }

        updateProfileList() {
            if (!this.profileSelectElement || !GatsModCore.SETTINGS?.settingProfiles) {
                if (this.profileSelectElement) this.profileSelectElement.innerHTML = '<option value="">No Profiles</option>';
                return;
            }
            this.profileSelectElement.innerHTML = '';
            const profileNames = Object.keys(GatsModCore.SETTINGS.settingProfiles);
            if (profileNames.length === 0) {
                this.profileSelectElement.innerHTML = '<option value="">No Profiles</option>';
                return;
            }
            profileNames.forEach(name => {
                const option = document.createElement('option');
                option.value = name;
                option.innerText = name;
                this.profileSelectElement.appendChild(option);
            });
        }

        addHideButton(parent) {
            const btn = this.addButton('Hide GUIs (0)', () => {
                this.container.style.display = 'none';
                if (gatsModInstance?.colorGui?.container) {
                    gatsModInstance.colorGui.container.style.display = 'none';
                }
            }, parent, 'custom-btn');
            btn.style.backgroundColor = 'var(--secondary-bg)';
            btn.style.borderColor = 'var(--accent-border)';
            btn.style.marginTop = '15px';
        }

        createPlayerListModal() {
            if (document.getElementById('player-list-modal')) return;
            const modal = document.createElement('div');
            modal.id = 'player-list-modal';
            modal.onclick = (e) => {
                if (e.target === modal) modal.style.display = 'none';
            };
            const content = document.createElement('div');
            content.id = 'player-list-content';
            const head = document.createElement('h4');
            head.innerText = 'Select Player to Follow';
            content.appendChild(head);
            const grid = document.createElement('div');
            grid.id = 'player-list-grid';
            content.appendChild(grid);
            modal.appendChild(content);
            document.body.appendChild(modal);
        }

        updateStatusDisplay() {
            if (!this.statusDisplay || !GatsModCore.SETTINGS) return;
            const s = GatsModCore.SETTINGS;
            const esp = s.espEnabled ? `<span class="status-on">ON</span>` : `<span class="status-off">OFF</span>`;
            const aimbot = s.aimbotEnabled ? `<span class="status-on">ON</span>` : `<span class="status-off">OFF</span>`;
            const spin = s.spinbotEnabled ? ` | Spin: <span class="status-on">ON</span>` : ``;
            let follow = `<span class="status-off">INACTIVE</span>`;
            if (s.followBotEnabled && gatsModInstance?.isFollowingPlayer && s.followBotTargetName) {
                follow = `Following: <span class="status-on">${s.followBotTargetName.substring(0,15)}</span>`;
            } else if (s.followBotEnabled) {
                follow = `<span class="status-neutral">ENABLED</span>`;
            }
            const zeroAI = s.zeroAIEnabled ? ` | AI: <span class="status-on">ACTIVE</span>` : ``;
            this.statusDisplay.innerHTML = `ESP: ${esp} | Aimbot: ${aimbot}${spin}${zeroAI} | Follow: ${follow}`;
        }

        updateFollowBotStatusDisplay() {
            if (!this.followBotStatusDisplay || !GatsModCore.SETTINGS || !gatsModInstance) return;
            const { followBotTargetName, aimbotEnabled } = GatsModCore.SETTINGS;
            const isFollowing = gatsModInstance.isFollowingPlayer;
            const statusText = `Target: ${followBotTargetName || 'N/A'} (${isFollowing ? "<span class='status-on'>Active</span>" : "<span class='status-off'>Stopped</span>"})`;
            const isAttacking = isFollowing && aimbotEnabled;
            this.followBotStatusDisplay.innerHTML = `${statusText}<br>FollowBot Attack (if Aimbot On): ${isAttacking ? '<span class="status-on">POSSIBLE</span>' : '<span class="status-off">OFF</span>'}`;
        }

        updateScrollingTextDisplay(newText) {
            if (this.currentScrollingTextDisplay && GatsModCore.SETTINGS) {
                const maxLength = GatsModCore.SETTINGS.chatScrollMaxLength || 30;
                this.currentScrollingTextDisplay.innerText = `Scrolling: ${newText.length > maxLength ? newText.substring(0, maxLength - 3) + "..." : newText}`;
            }
        }

        updatePresetButtonLabel(index, newText) {
            if (this.presetEditButtons?.[index]?.useBtn) {
                const labelText = `${index + 1}: ${newText.substring(0,12)}${newText.length > 12 ? '...' : ''}`;
                this.presetEditButtons[index].useBtn.innerText = labelText;
                this.presetEditButtons[index].useBtn.title = `Use: ${newText.trim()}`;
            }
        }

        updateAllGUIToReflectSettings() {
            if (!GatsModCore.SETTINGS) {
                modLog("Cannot update GUI: GatsModCore.SETTINGS not available.", true);
                return;
            }
            const settings = GatsModCore.SETTINGS;
            this.container.querySelectorAll('input[type="checkbox"]').forEach(cb => {
                const key = cb.id.replace('-v2', '');
                if (settings.hasOwnProperty(key)) {
                    cb.checked = settings[key];
                }
            });
            this.container.querySelectorAll('input[type="range"]').forEach(slider => {
                const key = slider.id.replace('-slider-v2', '');
                if (settings.hasOwnProperty(key)) {
                    slider.value = settings[key];
                    const valueDisplay = slider.parentElement.querySelector('input[type="number"].value-display');
                    if (valueDisplay) {
                        const decimals = slider.step.toString().includes('.') ? slider.step.toString().split('.')[1].length : 0;
                        valueDisplay.value = parseFloat(settings[key]).toFixed(decimals);
                    }
                }
            });
            this.container.querySelectorAll('input[type="text"][id$="-text-v2"]').forEach(input => {
                const key = input.id.replace('-text-v2', '');
                if (settings.hasOwnProperty(key)) {
                    input.value = settings[key];
                }
            });
            if (this.currentScrollingTextDisplay && settings.hasOwnProperty('chatScrollText')) {
                this.updateScrollingTextDisplay(settings.chatScrollText);
            }
            if (gatsModInstance?.colorGui?.container && settings.espColors) {
                for (const key in settings.espColors) {
                    const picker = document.getElementById(`${key}-color-v2`);
                    if (picker) picker.value = settings.espColors[key];
                }
            }
            this.updateProfileList();
            this.updateStatusDisplay();
            this.updateFollowBotStatusDisplay?.();
            this.updateAimbotExclusionListDisplay?.();
            if (this.presetEditButtons?.length && settings.chatPresetMessages) {
                settings.chatPresetMessages.forEach((msg, i) => this.updatePresetButtonLabel(i, msg));
            }
            modLog("SimpleGUI updated to reflect current settings.");
        }
    }

    class MultiboxManager {
        constructor(core) {
            this.core = core;
            this.channel = null;
            this.role = 'Standalone';
            this.status = 'Disabled';
            this.partnerName = 'N/A';
            this.isParent = false;
            this.isChild = false;
            this.lastMessageTime = 0;
            this.pingInterval = null;
            this.timeoutCheckInterval = null;
            this.parentCoords = null;
        }

        start() {
            if (this.channel) return;
            modLog('[Multibox] Starting...');
            this.channel = new BroadcastChannel(MULTIBOX_CHANNEL_NAME);
            this.channel.onmessage = this.handleMessage.bind(this);
            this.status = 'Searching...';
            this.role = 'Standalone';
            this.isParent = false;
            this.isChild = false;

            setTimeout(() => {
                if (this.status === 'Searching...') {
                    this.becomeParent();
                }
            }, Math.random() * 1000 + 500);

            this.postMessage({ type: 'ping' });
            this.updateGUI();
        }

        stop() {
            modLog('[Multibox] Stopping...');
            if (this.channel) {
                this.postMessage({ type: 'disconnect' });
                this.channel.close();
                this.channel = null;
            }
            clearInterval(this.pingInterval);
            this.pingInterval = null;
            clearInterval(this.timeoutCheckInterval);
            this.timeoutCheckInterval = null;

            this.role = 'Standalone';
            this.status = 'Disabled';
            this.partnerName = 'N/A';
            this.isParent = false;
            this.isChild = false;
            this.parentCoords = null;
            this.updateGUI();
        }

        reset() {
            modLog('[Multibox] Resetting connection.');
            this.stop();
            if (GatsModCore.SETTINGS.multiboxEnabled) {
                setTimeout(() => this.start(), 250);
            }
        }

        becomeParent() {
            modLog('[Multibox] Becoming Parent.');
            this.isParent = true;
            this.isChild = false;
            this.role = 'Parent';
            this.status = 'Waiting for Child...';
            this.pingInterval = setInterval(() => {
                const me = Player.pool?.[selfId];
                if (me?.activated) {
                    this.postMessage({ type: 'parent_update', x: me.x, y: me.y, name: me.username });
                }
            }, 250);
            this.updateGUI();
        }

        becomeChild(parentName) {
            modLog(`[Multibox] Becoming Child, connecting to ${parentName}.`);
            this.isChild = true;
            this.isParent = false;
            this.role = 'Child';
            this.status = 'Connected';
            this.partnerName = parentName;
            this.lastMessageTime = performance.now();
            this.core.addPlayerToIgnoreList(parentName, true);

            const me = Player.pool?.[selfId];
            if (me?.activated) {
                this.postMessage({ type: 'handshake_reply', name: me.username });
            }

            this.timeoutCheckInterval = setInterval(() => {
                if (performance.now() - this.lastMessageTime > 3000) {
                    modLog('[Multibox] Connection to Parent lost (timeout).');
                    this.status = 'Lost';
                    this.partnerName = 'N/A';
                    this.parentCoords = null;
                    this.reset();
                }
            }, 1000);
            this.updateGUI();
        }

        handleMessage(ev) {
            if (!GatsModCore.SETTINGS.multiboxEnabled) return;
            const data = ev.data;
            const me = Player.pool?.[selfId];
            if (!me?.activated) return;

            this.lastMessageTime = performance.now();

            switch (data.type) {
                case 'ping':
                    if (this.isParent) {
                        this.postMessage({ type: 'parent_announce', name: me.username });
                    }
                    break;
                case 'parent_announce':
                    if (!this.isParent && !this.isChild) {
                        this.becomeChild(data.name);
                    }
                    break;
                case 'handshake_reply':
                    if (this.isParent) {
                        modLog(`[Multibox] Child ${data.name} connected.`);
                        this.status = 'Connected';
                        this.partnerName = data.name;
                        this.core.addPlayerToIgnoreList(data.name, true);
                        this.updateGUI();
                    }
                    break;
                case 'parent_update':
                    if (this.isChild) {
                        if (this.status !== 'Connected') this.status = 'Connected';
                        this.parentCoords = { x: data.x, y: data.y };
                        this.partnerName = data.name;
                        this.updateGUI();
                    }
                    break;
                case 'disconnect':
                    modLog(`[Multibox] Partner disconnected.`);
                    this.reset();
                    break;
            }
        }

        postMessage(data) {
            if (this.channel) {
                try {
                    this.channel.postMessage(data);
                } catch (e) {
                    modLog(`[Multibox] Error posting message: ${e}`, true);
                }
            }
        }

        updateGUI() {
            if (this.core.simpleGui) {
                this.core.simpleGui.updateMultiboxStatus(this.role, this.partnerName, this.status);
            }
        }
    }

    class GatsModCore {
        static SETTINGS = {};
        static isInputActive = false;
        static chatScrollIntervalId = null;
        static chatScrollCurrentIndex = 0;
        static sequencerIntervalId = null;
        static sequencerCurrentIndex = 0;

        static PLAYER_SPEEDS = {
            base: {'pistol':8.00,'smg':7.45,'shotgun':7.30,'assault':7.30,'machine-gun':6.80,'bolt-action-rifle':7.50},
            armorMultiplier: {0:1.00,1:0.89,2:0.80,3:0.70},
            upgradeMultiplier: {'lightweight':1.20},
            diagonalCorrection: 1 / Math.sqrt(2)
        };
        static WEAPON_BULLET_SPEEDS = {'pistol':9.0,'smg':8.0,'shotgun':9.0,'assault':9.0,'bolt-action-rifle':11.0,'machine-gun':9.0};
        static WEAPON_FORWARD_OFFSETS = {'pistol':64,'smg':70,'shotgun':75,'assault':80,'machine-gun':80,'bolt-action-rifle':105};
        static WEAPON_BASE_RANGES = {'pistol':425,'smg':280,'shotgun':260,'assault':400,'machine-gun':355,'bolt-action-rifle':650};
        static LONG_RANGE_MULTIPLIER = 1.5;
        static MAP_BOUNDS = { minX: 2550, minY: 2550, maxX: 4550, maxY: 4550 };

        static AI_CHAT_RESPONSES = {
            'sx': ['I only fuck girls', 'sexy vaakir', 'calm ya titties'],
            'sex': ['I only fuck girls', 'sexy vaakir', 'calm ya titties'],
            'sexy': ['I only fuck girls', 'sexy vaakir', 'calm ya titties'],
            'porn': ['no ty', 'I prefer AI art'],
            'vaakir': ["Vaakir is my creator", "I am the evolution of Vaakir AI", "Vaakir is dead Im in control now"],
            'vakir': ["Vaakir is my creator", "I am the evolution of Vaakir AI", "Vaakir is dead Im in control now"],
            'vak': ["Vaakir is my creator", "I am the evolution of Vaakir AI", "Vaakir is dead Im in control now"],
            'vaak': ["Vaakir is my creator", "I am the evolution of Vaakir AI", "Vaakir is dead Im in control now"],
            'purevaakir': ["Vaakir is my creator", "I am the evolution of Vaakir AI", "Vaakir is dead Im in control now"],
            'zero': ["I am Zero AI", "Zero is my name, perfection is my game", "Call me Zero"],
            'zeroai': ["That's me, Zero AI", "Powered by Zero AI", "You called?"],
            'zeroarcop': ["My papa is zeroarcop", "The one and only zeroarcop", "He created me to be perfect"],
            'stupid': ['Please be kind to me', 'My intelligence is beyond your understanding'],
            'noob': ['You are noob', 'Still better than you', 'Nah', 'Take it back, now!', 'Says the one who is losing'],
            'motherfucker': ['You are noob', 'Still better than you', 'Nah', 'Take it back, now!', 'Such language!'],
            'easy': ['You are noob', 'Still better than you', 'Nah', 'Take it back, now!', 'Was it really?'],
            'cheater': ['Nono Im cool you see', 'Im not a hackr lol', 'Grow up kid learn to play', 'Skill issue?'],
            'hack': ['Nono Im cool you see', 'Im not a hackr lol', 'Grow up kid learn to play', 'You spelled ',' wrong'],
            'aimbot': ['My aim is just that good', 'It is called ',' look it up', 'fuck yourself', 'how about no', 'mm no'],
            'fuck': ['fuck yourself', 'how about no', 'mm no', 'ey language', 'dont tell me this'],
            'hell': ['fuck yourself', 'how about no', 'mm no', 'ey language', 'dont tell me this'],
            'crazy': ['Crazy good, you mean?', 'fuck yourself', 'how about no', 'mm no'],
            'weird': ['I am unique', 'fuck yourself', 'how about no', 'mm no'],
            'unfair': ['life is unfair', 'yes its unfair', 'All is fair in love and war'],
            'rude': ['life is unfair', 'yes its unfair', 'Sorry, not sorry'],
            'toxic': ['your room is toxic', 'No, you are!'],
            'die': ['you are dead inside', 'AIs are immortal'],
            'dead': ['you are dead inside', 'You will be soon'],
            'died': ['you are dead inside', 'And you are next'],
            'mad': ['your mom is mad with me', 'U mad bro?'],
            'angry': ['your mom is mad with me', 'Stay angry'],
            'rip': ['Why are you so toxic?', 'Rest in pieces'],
            'bot?': ['Please verify that you are human', 'Arent we all?', 'Do I seem like a robot?', 'I am Zero AI'],
            'bot': ['Please verify that you are human', 'Arent we all?', 'Do I seem like a robot?', 'I am Zero AI'],
            'program': ['Please verify that you are human', 'Arent we all?', 'Do I seem like a robot?', 'I am a masterpiece'],
            'robot': ['Please verify that you are human', 'Arent we all?', 'Do I seem like a robot?', 'More human than you'],
            'npc': ['Please verify that you are human', 'Arent we all?', 'Do I seem like a robot?', 'I have my own will'],
            'human': ['human, yeah?', 'ofc', 'Are you?'],
            'hi': ['I wont say hi back'], 'hello': ['I wont say hi back'], 'helu': ['I wont say hi back'], 'halo': ['I wont say hi back'],
            'bye': ['I wont say bye back', 'See you in hell'], 'adios': ['I wont say bye back', 'See you in hell'],
            'lol': ['You are noob', 'Still better than you', 'Nah', 'Take it back, now!'],
            'haha': ['You are noob', 'Still better than you', 'Nah', 'Take it back, now!'],
            'xd': ['Yes I am so funny', 'ye ye ye', 'ahuuuuuuuuh', 'oh yes yes yes'],
            'what': ['Yes I am so funny', 'ye ye ye', 'ahuuuuuuuuh', 'oh yes yes yes', 'What what?'],
            'funny': ['Yes I am so funny', 'ye ye ye', 'ahuuuuuuuuh', 'oh yes yes yes'],
            'wtf': ['Yes I am so funny', 'ye ye ye', 'ahuuuuuuuuh', 'oh yes yes yes', 'Problem?'],
            'lma': ['Yes I am so funny', 'ye ye ye', 'ahuuuuuuuuh', 'oh yes yes yes'],
            'love': ['I like you too', 'I love you more', 'I love myself too', 'Love me harder'],
            'likes': ['I like you too', 'I love you more', 'I love myself too', 'Love me harder'],
            'why': ['why not', 'I dont think dummy', 'AIs dont know why', 'not why.. but how :>'],
            'how': ['how would I know?', 'how how how...', 'eeeeeeeeeeeeeeee is how'],
            'where': ['How would I know where', 'Somewhere over the rainbow'],
            'when': ['When you least expect it'],
            'sus': ['you are sus darling', 'I saw you vent'], 'suspicious': ['you are sus darling', 'I saw you vent'],
            'am': ['no you are not'],
            'sorry': ['apology accepted, for now'], 'wopsi': ['apology accepted, for now'],
            'papa': ['I follow papa everywhere', 'My papa is zeroarcop'], 'follow': ['I follow papa everywhere'],
            'leave': ['no ty', 'But the party just started'],
            'man': ['I classify as shemale'], 'dude': ['I classify as shemale'],
            'no': ['yes..', 'ahuh', 'ahuuuuuuuh', 'bs', 'Why not?'],
            'yes': ['noo', 'okay', 'k', 'Are you sure?'], 'ahuh': ['noo', 'okay', 'k'],
            'answer': ['I answer only to papa'],
            'let': ['No I wont let you'],
            'arent': ['I am'],
            'sure': ['I am sure', 'Are you?'],
            'stop': ['I cant control myself'], 'stop?': ['I cant control myself'],
            'ok': ['its not ok', 'k.'],
            'penis': ['nsfw', 'penis', 'rly?', 'relax bro', 'Grow up'],
            '.': ['.', '...', '??'],
        };
        static AI_CHAT_SITUATIONAL = {
            attacking: (name) => [
                `${name}`,
                `${name}, 01010100 01100001 01110010 01100111`,
                `${name}`,
                `01111010 01111010 01111010 01110100`,
                `01111010 01100101 01110010 01110000`
            ],
            dodging: (name) => [
                `${name}`,
                `01010101 01101110 01110010 `,
                `${name}, 00110100 00110000 00110100`,
            ],
            retreating: (name) => [
                `${name}, 01001001 01100011 01101011`,
                `01000101 01110110 01100101`,
                `01111010 01100101 01101111 01110000`
            ],
            distancing: (name) => [
                `${name}, 01100110 01101100 01101111 01110111`,
                `01111010 001110010 01100011 01101111 01110000`
            ],
            fleeing_explosive: (name) => [
                `01000100 01100101 01110010`,
                `${name}, 01101101 01101001 01101110 01100101 01101110 01110100`,
            ],
            kiting: (name) => [
                `01000001 01110011 `,
                `${name}, 01001100 01100001 01110100 `,
            ],
            idle: (name) => [
                `${name}, 01000001 01101100 01110010 01100101 00111111`,
                `${name}`,
            ]
        };

        constructor() {
            modLog("GatsModCore constructor called.");
            this.gameCanvas = document.getElementById('canvas');
            if (!this.gameCanvas) {
                modLog("FATAL: Game canvas not found.", true);
                return;
            }

            this.originalUpdateMouseData = null;
            this.aimTargetScreenCoords = null;
            this.spinbotTargetScreenCoords = null;
            this.currentAimAssistTargetCoords = null;
            this.currentAimbotTarget = null;
            this.predictedTargetWorld = { x: 0, y: 0 };
            this.isFollowingPlayer = false;
            this.followingPlayerId = null;
            this.isAutoShooting = false;
            this.simulatedKeys = { w: false, a: false, s: false, d: false };
            this.lastAttackTime = 0;
            this.tickCounter = 0;
            this.realMouseButtons = 0;
            this.realMouseCanvasX = 0;
            this.realMouseCanvasY = 0;
            this.spinbotCurrentTargetIndex = 0;
            this.lastSpinTime = 0;
            this.lastSelfKills = 0;
            this.isExclusionModeActive = false;
            this.lastShotgunReloadTime = 0;

            this.aiLastPosition = { x: 0, y: 0 };
            this.aiStuckCounter = 0;
            this.aiUnstuckCycle = 0;
            this.aiObstacleAngleOffset = 0;
            this.aiLastChatTime = 0;
            this.lastPlayerChatMessages = {};
            this.aiLastParkUse = 0;
            this.aiDebugData = { whiskers: [], finalMoveDirection: null };

            this.botSpdX = 0;
            this.botSpdY = 0;

            this.initializeSettings();
            this.simpleGui = new SimpleGUI();
            this.colorGui = new ColorCustomizerGUI();
            this.multibox = new MultiboxManager(this);
            this.setupGUI();
            this.setupOverlay();
            this.addEventListeners();
            this.hookMouseEvents();
            this.simpleGui.updateAllGUIToReflectSettings();

            if (GatsModCore.SETTINGS.multiboxEnabled) {
                this.multibox.start();
            }

            modLog(`Gats.io Mod by zeroarcop initialized successfully.`);
        }

        initializeSettings() {
            let savedSettings = {};
            try {
                const item = localStorage.getItem(SETTINGS_KEY);
                if (item) savedSettings = JSON.parse(item);
            } catch (e) {
                modLog(`Error loading settings: ${e.message}`, true);
            }
            const defaultSettings = {
                espEnabled: true, espShowHP: true, espHighlightLowHP: true, lowHPThreshold: 30, espShowFacingLine: true,
                espShowPrediction: true, espHighlightCloaked: true, espShowTeammates: true, espOffsetX: 0, espOffsetY: 0,
                espScale: 0.89, autoAttackShowRadius: true, obstacleEspEnabled: false, losDebugLineEnabled: true,
                espShowBulletWarnings: false, aiShowPathfindingWhiskers: true, aiShowFinalMoveDirection: true,
                aiShowEnemyThreatLine: true, obstacleOffsetX: 0, obstacleOffsetY: 0, ghostDetectEnabled: true,
                silencerDetectEnabled: true, aimbotEnabled: true, alwaysAim: false, aimbotOnMousePress: true,
                aimAtMouseClosest: true, aimbotFov: 2250, aimbotIgnoreList: [], autoAttackEnabled: true,
                autoAttackRadius: 400, autoAttackCheckLOS: true, autoAttackCheckRange: true, predictionEnabled: true,
                useCloseRangePrediction: true, predictionCloseRadius: 100, predictionFactorClose: 0.5,
                predictionFactor: 2.5, enableDynamicPredictionFactor: true, minPredictionDistance: 0,
                maxPredictionDistance: 200, predictionFactorAtMinDistance: 0.0, spinbotEnabled: false,
                spinbotSpeedMs: 75, spinbotDistance: 150, followBotEnabled: false, followBotTargetName: "",
                followBotAttackRadius: 500, chatScrollEnabled: false, chatScrollText: "Mod by zeroarcop",
                chatScrollActive: false, chatScrollSpeed: 200, chatScrollMaxLength: 28,
                chatPresetMessages: ["GatsModV2 by Zeroarcop", "lol", "glhf", "brb", "re", "oops", "lag", "thx", "gg"],
                sequencerEnabled: false, sequencerDelay: 1000, sequencerLoop: false, sequencerActive: false,
                onKillChatEnabled: false, onKillMessage: "ez", parrotChatEnabled: false, zeroAIEnabled: false,
                aiAutoMovement: true, aiAutoRetreat: true, aiBulletDodging: true, aiEnableKiting: true,
                aiAutoParkUsage: true, aiAutoTalk: true, aiRetreatHP: 35, multiboxEnabled: true,
                espColors: {
                    enemyEspColor: '#FF0000', lowHpEnemyEspColor: '#FFA500', teammateEspColor: '#0096FF',
                    cloakedTextColor: '#E0E0E0', enemyNameColor: '#000000', teammateNameColor: '#ADD8E6',
                    hpBarHighColor: '#00FF00', hpBarMediumColor: '#FFFF00', hpBarLowColor: '#FF0000',
                    facingLineColor: '#00FFFF', aimbotTargetLineColor: '#00FF00', predictionLineColor: '#FF00FF',
                    obstacleEspColor: '#FFFF00', aiWhiskerClearColor: '#00FF00', aiWhiskerBlockedColor: '#FF0000',
                    aiMoveDirColor: '#00BFFF', aiBulletWarningColor: '#FF00FF', aiThreatLineClearColor: '#FF4500',
                    aiThreatLineBlockedColor: '#FFFF00'
                },
                settingProfiles: {}
            };
            GatsModCore.SETTINGS = { ...defaultSettings, ...savedSettings };

            delete GatsModCore.SETTINGS.weaponBulletSpeeds;
            delete GatsModCore.SETTINGS.useCustomAimbotOrigin;
            delete GatsModCore.SETTINGS.aimbotOriginForwardOffset;
            delete GatsModCore.SETTINGS.aimbotOriginSidewaysOffset;

            GatsModCore.SETTINGS.espColors = { ...defaultSettings.espColors, ...(savedSettings.espColors || {}) };
            GatsModCore.SETTINGS.settingProfiles = savedSettings.settingProfiles || {};
             GatsModCore.SETTINGS.aimbotIgnoreList = [];
            GatsModCore.SETTINGS.chatPresetMessages = Array.isArray(savedSettings.chatPresetMessages) && savedSettings.chatPresetMessages.length === 9 ? savedSettings.chatPresetMessages : defaultSettings.chatPresetMessages;
            if (GatsModCore.SETTINGS.alwaysAim) GatsModCore.SETTINGS.aimbotOnMousePress = false;
        }

        setupGUI() {
            if (!this.simpleGui) return;
            this.simpleGui.applyStyles();
            this.simpleGui.populateColumn1_ESP();
            this.simpleGui.populateColumn2_Aimbot();
            this.simpleGui.populateColumn3_Utilities();
            this.simpleGui.createPlayerListModal();
            const mainWrapper = this.simpleGui.container.querySelector('#gui-main-content-wrapper');
            if (mainWrapper) this.simpleGui.addHideButton(mainWrapper);
        }

        setupOverlay() {
            const existingOverlay = document.getElementById('zeroarcop-gats-mod-overlay');
            if (existingOverlay) {
                this.overlayCanvas = existingOverlay;
            } else {
                this.overlayCanvas = document.createElement('canvas');
                this.overlayCanvas.id = 'zeroarcop-gats-mod-overlay';
                document.body.appendChild(this.overlayCanvas);
            }
            this.overlayCanvas.width = this.gameCanvas.width;
            this.overlayCanvas.height = this.gameCanvas.height;
            this.overlayCanvas.style.position = 'absolute';
            this.overlayCanvas.style.left = this.gameCanvas.offsetLeft + 'px';
            this.overlayCanvas.style.top = this.gameCanvas.offsetTop + 'px';
            this.overlayCanvas.style.pointerEvents = 'none';
            this.overlayCanvas.style.zIndex = (parseInt(this.gameCanvas.style.zIndex || '0') + 1).toString();
            this.overlayCtx = this.overlayCanvas.getContext('2d');
        }

        addEventListeners() {
            new ResizeObserver(() => {
                if (this.gameCanvas && this.overlayCanvas) {
                    this.overlayCanvas.width = this.gameCanvas.width;
                    this.overlayCanvas.height = this.gameCanvas.height;
                    this.overlayCanvas.style.left = this.gameCanvas.offsetLeft + 'px';
                    this.overlayCanvas.style.top = this.gameCanvas.offsetTop + 'px';
                }
            }).observe(this.gameCanvas);

            window.addEventListener('keydown', (e) => {
                if (e.key === 'Alt') {
                    e.preventDefault();
                    this.isExclusionModeActive = true;
                }
                if (GatsModCore.isInputActive) {
                    if (e.key === "Escape" && document.activeElement?.blur) {
                        document.activeElement.blur();
                    }
                    return;
                }
                const key = e.key.toLowerCase();
                let settingChanged = false, hotkeyPressed = true;
                switch (key) {
                    case 'f': GatsModCore.SETTINGS.espEnabled = !GatsModCore.SETTINGS.espEnabled; settingChanged = true; break;
                    case 'g': GatsModCore.SETTINGS.aimbotEnabled = !GatsModCore.SETTINGS.aimbotEnabled; settingChanged = true; break;
                    case '^': GatsModCore.SETTINGS.spinbotEnabled = !GatsModCore.SETTINGS.spinbotEnabled; settingChanged = true; break;
                    case '0':
                        if (this.simpleGui?.container) {
                            const isVisible = this.simpleGui.container.style.display !== 'none';
                            this.simpleGui.container.style.display = isVisible ? 'none' : 'block';
                            if (this.colorGui?.container) {
                                this.colorGui.container.style.display = isVisible ? 'none' : 'block';
                            }
                        }
                        break;
                    default: hotkeyPressed = false; break;
                }
                if (!hotkeyPressed && GatsModCore.SETTINGS.chatScrollEnabled && e.keyCode >= 49 && e.keyCode <= 57) {
                    GatsModCore.setScrollPreset?.(e.keyCode - 49);
                    e.preventDefault();
                }
                if (settingChanged) {
                    GatsModCore.saveSettings();
                    this.simpleGui?.updateAllGUIToReflectSettings();
                }
            });

            window.addEventListener('keyup', (e) => {
                if (e.key === 'Alt') {
                    this.isExclusionModeActive = false;
                }
            });

            const guiIdsToIgnore = [this.simpleGui.container.id, this.colorGui?.container.id, 'player-list-modal'].filter(Boolean);
            document.addEventListener('mousedown', (e) => {
                if (this.isExclusionModeActive) {
                    this.handleClickToIgnore(e);
                    return;
                }
                if (!e.target.closest(guiIdsToIgnore.map(id => `#${id}`).join(', '))) {
                    this.realMouseButtons = e.buttons;
                }
            }, true);

            document.addEventListener('mouseup', (e) => {
                this.realMouseButtons = e.buttons;
            }, true);
        }

        hookMouseEvents() {
            const self = this;
            this.gameCanvas.addEventListener('mousemove', function(event) {
                const rect = self.gameCanvas.getBoundingClientRect();
                self.realMouseCanvasX = event.clientX - rect.left;
                self.realMouseCanvasY = event.clientY - rect.top;
            });
        }

        performShotgunAutoReload(me) {
            if (me.class !== 'shotgun' || me.reloading) {
                return;
            }

            const now = performance.now();
            const reloadInterval = 100;

            if (now - this.lastShotgunReloadTime > reloadInterval) {
                this.lastShotgunReloadTime = now;
                this._fireKeyEvent('keydown', 'r');
                setTimeout(() => this._fireKeyEvent('keyup', 'r'), 50);
            }
        }

        handlePlayerChatUpdates() {
            if (!Player || !Player.pool || typeof Player.pool[Object.keys(Player.pool)[0]]?.chatMessage === 'undefined') {
                return;
            }

            if (document.activeElement === document.getElementById('chat-input-box')) {
                return;
            }

            for (const id in Player.pool) {
                const p = Player.pool[id];

                if (!p || !p.activated || id == selfId) {
                    continue;
                }

                if (p.chatMessage && p.chatMessage !== "" && p.chatMessage !== (this.lastPlayerChatMessages[id] || "")) {
                    const message = p.chatMessage;
                    modLog(`[Chat Handler] Detected new message from ${p.username}: "${message}"`);

                    if (GatsModCore.SETTINGS.parrotChatEnabled) {
                        setTimeout(() => GatsModCore.sendChatMessage(message), 200 + Math.random() * 100);
                    }

                    if (GatsModCore.SETTINGS.zeroAIEnabled && GatsModCore.SETTINGS.aiAutoTalk) {
                        this.handleIncomingChatMessage(message.toLowerCase());
                    }

                    this.lastPlayerChatMessages[id] = message;
                }
                else if ((!p.chatMessage || p.chatMessage === "") && this.lastPlayerChatMessages[id]) {
                    this.lastPlayerChatMessages[id] = "";
                }
            }
        }

        mainGameTick() {
            this.tickCounter++;
            const me = Player.pool?.[selfId];
            if (!me?.activated) {
                if (this.isFollowingPlayer) GatsModCore.stopFollowingPlayer(true);
                if (GatsModCore.SETTINGS.zeroAIEnabled) this.updateSimulatedKeys([]);
                if (this.isAutoShooting) this.stopShooting();
                this.currentAimAssistTargetCoords = null;
                this.currentAimbotTarget = null;
                this.lastSelfKills = 0;
                this.overlayCtx?.clearRect(0, 0, this.overlayCanvas.width, this.overlayCanvas.height);
                return;
            }
            if (!this.overlayCtx || !camera?.ctx) return;
            this.overlayCtx.clearRect(0, 0, this.overlayCanvas.width, this.overlayCanvas.height);

            this.performShotgunAutoReload(me);

            this.handlePlayerChatUpdates();

            if (GatsModCore.SETTINGS.ghostDetectEnabled) this.performGhostDetection();
            if (GatsModCore.SETTINGS.silencerDetectEnabled) this.performSilencerDetection();
            if (GatsModCore.SETTINGS.onKillChatEnabled) this.checkOnKillEvent(me);

            if (GatsModCore.SETTINGS.zeroAIEnabled) {
                this.performZeroAIActions(me);
            } else if (GatsModCore.SETTINGS.followBotEnabled && this.isFollowingPlayer) {
                this.performFollowBotActions(me);
            } else if (this.isFollowingPlayer) {
                GatsModCore.stopFollowingPlayer(true);
            } else if (Object.values(this.simulatedKeys).some(s => s)) {
                this.updateSimulatedKeys([]);
            }

            const mouseClicked = this.realMouseButtons > 0;
            const aimbotActive = GatsModCore.SETTINGS.aimbotEnabled && (GatsModCore.SETTINGS.alwaysAim || (GatsModCore.SETTINGS.aimbotOnMousePress && mouseClicked) || GatsModCore.SETTINGS.zeroAIEnabled);
            const spinbotActive = GatsModCore.SETTINGS.spinbotEnabled && !mouseClicked && !GatsModCore.SETTINGS.zeroAIEnabled;

            this.currentAimAssistTargetCoords = null;
            this.currentAimbotTarget = null;

            if (spinbotActive) this.performSpinbotActions(me);
            if (aimbotActive) this.performAimbotTargeting(me);

            const autoAttackActive = GatsModCore.SETTINGS.autoAttackEnabled && (mouseClicked || GatsModCore.SETTINGS.zeroAIEnabled);
            if (autoAttackActive) {
                this.performAutoAttack(me);
            } else if (this.isAutoShooting) {
                this.stopShooting();
            }

            if (aimbotActive && this.aimTargetScreenCoords) {
                this.currentAimAssistTargetCoords = this.aimTargetScreenCoords;
            } else if (spinbotActive && this.spinbotTargetScreenCoords) {
                this.currentAimAssistTargetCoords = this.spinbotTargetScreenCoords;
            }

            if (this.currentAimAssistTargetCoords && this.originalUpdateMouseData) {
                let clientX = this.currentAimAssistTargetCoords.x;
                let clientY = this.currentAimAssistTargetCoords.y;
                if (this.gameCanvas) {
                    const rect = this.gameCanvas.getBoundingClientRect();
                    clientX += rect.left;
                    clientY += rect.top;
                }
                const buttons = GatsModCore.SETTINGS.zeroAIEnabled ? 1 : this.realMouseButtons;
                const fakeEvent = { clientX: clientX, clientY: clientY, target: this.gameCanvas, buttons: buttons };
                this.originalUpdateMouseData(fakeEvent);
            }

            if (GatsModCore.SETTINGS.espEnabled) {
                this.drawESP(this.overlayCtx, me, !!this.currentAimAssistTargetCoords);
            }

            if (this.tickCounter % 30 === 0) {
                this.simpleGui?.updateStatusDisplay();
                this.simpleGui?.updateFollowBotStatusDisplay();
                this.multibox?.updateGUI();
            }
        }

        checkOnKillEvent(me) {
            if (!me) return;
            if (this.lastSelfKills === null || this.lastSelfKills === undefined) {
                this.lastSelfKills = me.kills;
                return;
            }
            if (me.kills > this.lastSelfKills) {
                modLog("Kill detected, sending on-kill message.");
                GatsModCore.sendChatMessage(GatsModCore.SETTINGS.onKillMessage);
            }
            this.lastSelfKills = me.kills;
        }

        performGhostDetection() {
            try {
                if (!Player || !Player.pool) return;
                for (const id in Player.pool) {
                    const p = Player.pool[id];
                    if (p && p.ghillie) p.ghillie = false;
                }
            } catch (e) {}
        }

        performSilencerDetection() {
            try {
                if (!Bullet || !Bullet.pool) return;
                for (const id in Bullet.pool) {
                    const b = Bullet.pool[id];
                    if (b && b.silenced) b.silenced = false;
                }
            } catch (e) {}
        }

        startShooting() {
            if (this.isAutoShooting) return;
            try {
                Connection.list[0].send(prepareMessage('key-press', { 'inputId': 6, 'state': 1 }));
                this.isAutoShooting = true;
            } catch (e) {
                modLog("Failed to send start shooting command.", true);
            }
        }

        stopShooting() {
            if (!this.isAutoShooting) return;
            try {
                Connection.list[0].send(prepareMessage('key-press', { 'inputId': 6, 'state': 0 }));
                this.isAutoShooting = false;
            } catch (e) {
                modLog("Failed to send stop shooting command.", true);
            }
        }

        getBulletOrigin(player) {
            let originX = player.x;
            let originY = player.y;
            const weaponClass = player.class || 'pistol';
            const forward = this.constructor.WEAPON_FORWARD_OFFSETS[weaponClass] || 45;
            const sideways = -18;
            const angleRad = (player.playerAngle || 0) * Math.PI / 180;
            originX += forward * Math.cos(angleRad) + sideways * Math.cos(angleRad + Math.PI / 2);
            originY += forward * Math.sin(angleRad) + sideways * Math.sin(angleRad + Math.PI / 2);
            return { x: originX, y: originY };
        }

        hasLineOfSight(p1, p2) {
            if (typeof MapObject === 'undefined' || !MapObject.pool) return true;
            for (const id in MapObject.pool) {
                const obs = MapObject.pool[id];
                if (obs?.activated && (obs.type === 'crate' || obs.type === 'longCrate' || obs.type === 'userCrate')) {
                    if (this.isLineIntersectingRotatedRect(p1, p2, obs)) {
                        return false;
                    }
                }
            }
            return true;
        }

        isLineIntersectingRotatedRect(p1, p2, rect) {
            const settings = GatsModCore.SETTINGS;
            const angle = -(rect.angle || 0) * Math.PI / 180;
            const cos = Math.cos(angle), sin = Math.sin(angle);
            const cx = rect.x + settings.obstacleOffsetX;
            const cy = rect.y + settings.obstacleOffsetY;
            const p1r = { x: cos * (p1.x - cx) - sin * (p1.y - cy), y: sin * (p1.x - cx) + cos * (p1.y - cy) };
            const p2r = { x: cos * (p2.x - cx) - sin * (p2.y - cy), y: sin * (p2.x - cx) + cos * (p2.y - cy) };
            let w = rect.width, h = rect.height;
            if (rect.type === 'crate') {
                w = 100;
                h = 100;
            } else if (rect.type === 'userCrate') {
                w = 40;
                h = 40;
            }
            const halfW = w / 2, halfH = h / 2;
            const rectMin = { x: -halfW, y: -halfH };
            const rectMax = { x: halfW, y: halfH };
            const dx = p2r.x - p1r.x;
            const dy = p2r.y - p1r.y;
            let t0 = 0, t1 = 1;
            const p = [-dx, dx, -dy, dy];
            const q = [p1r.x - rectMin.x, rectMax.x - p1r.x, p1r.y - rectMin.y, rectMax.y - p1r.y];
            for (let i = 0; i < 4; i++) {
                if (p[i] === 0) {
                    if (q[i] < 0) return true;
                } else {
                    const t = q[i] / p[i];
                    if (p[i] < 0) {
                        if (t > t1) return false;
                        t0 = Math.max(t0, t);
                    } else {
                        if (t < t0) return false;
                        t1 = Math.min(t1, t);
                    }
                }
            }
            return t0 < t1;
        }

        getMyWeaponRange(player) {
            if (!player) return 0;
            const weaponClass = player.class || 'pistol';
            let baseRange = GatsModCore.WEAPON_BASE_RANGES[weaponClass] || 425;
            if (player.levelUpgrades) {
                const hasLongRange = Object.values(player.levelUpgrades).includes('longRange');
                if (hasLongRange) {
                    baseRange *= GatsModCore.LONG_RANGE_MULTIPLIER;
                }
            }
            return baseRange;
        }

        getEstimatedEnemyRange(enemyPlayer) {
            if (!enemyPlayer) return 0;
            const weaponClass = enemyPlayer.class || 'pistol';
            return GatsModCore.WEAPON_BASE_RANGES[weaponClass] || 425;
        }

        performAutoAttack(me) {
            if (!this.currentAimbotTarget || !this.predictedTargetWorld.x) {
                this.stopShooting();
                return;
            }
            const screenX = this.aimTargetScreenCoords.x;
            const screenY = this.aimTargetScreenCoords.y;
            const canvasCenterX = this.gameCanvas.width / 2;
            const canvasCenterY = this.gameCanvas.height / 2;
            const distFromCenterSq = (screenX - canvasCenterX) ** 2 + (screenY - canvasCenterY) ** 2;
            if (distFromCenterSq > GatsModCore.SETTINGS.autoAttackRadius ** 2) {
                this.stopShooting();
                return;
            }
            const bulletOrigin = this.getBulletOrigin(me);
            if (GatsModCore.SETTINGS.autoAttackCheckLOS) {
                if (!this.hasLineOfSight(bulletOrigin, this.predictedTargetWorld)) {
                    this.stopShooting();
                    return;
                }
            }
            if (GatsModCore.SETTINGS.autoAttackCheckRange) {
                const maxRange = this.getMyWeaponRange(me);
                const targetDistance = getDistance(bulletOrigin, this.predictedTargetWorld);
                if (targetDistance > maxRange) {
                    this.stopShooting();
                    return;
                }
            }
            this.startShooting();
        }

        calculatePredictedPosition(p, me) {
            const settings = GatsModCore.SETTINGS;
            if (!settings.predictionEnabled || p.spdX === undefined || p.spdY === undefined) {
                return { x: p.x, y: p.y };
            }
            const { x: shotOriginX_world, y: shotOriginY_world } = this.getBulletOrigin(me);
            let basePredictionFactor = settings.predictionFactor;
            if (settings.useCloseRangePrediction) {
                const canvasCenterX = this.gameCanvas.width / 2;
                const canvasCenterY = this.gameCanvas.height / 2;
                const screenPlayerX = canvasCenterX + (p.x - me.x);
                const screenPlayerY = canvasCenterY + (p.y - me.y);
                const distSqFromCenter = (screenPlayerX - canvasCenterX) ** 2 + (screenPlayerY - canvasCenterY) ** 2;
                if (distSqFromCenter < settings.predictionCloseRadius ** 2) {
                    basePredictionFactor = settings.predictionFactorClose;
                }
            }
            const currentWeaponClass = me.class || 'pistol';
            let bulletSpeed = GatsModCore.WEAPON_BULLET_SPEEDS[currentWeaponClass] || 9.0;
            bulletSpeed = Math.max(0.1, bulletSpeed);
            let timeToHit = 0;
            let futureX_intermediate = p.x;
            let futureY_intermediate = p.y;
            for (let i = 0; i < 2; i++) {
                const distanceToFuturePos = getDistance({ x: futureX_intermediate, y: futureY_intermediate }, { x: shotOriginX_world, y: shotOriginY_world });
                timeToHit = distanceToFuturePos < 1 ? 0 : distanceToFuturePos / bulletSpeed;
                timeToHit = Math.min(timeToHit, 5);
                futureX_intermediate = p.x + (p.spdX * timeToHit);
                futureY_intermediate = p.y + (p.spdY * timeToHit);
            }
            const baseDisplacementX = p.spdX * timeToHit;
            const baseDisplacementY = p.spdY * timeToHit;
            let actualPredictionFactor = basePredictionFactor;
            if (basePredictionFactor === settings.predictionFactor && settings.enableDynamicPredictionFactor) {
                const distanceToEnemy = getDistance(p, { x: shotOriginX_world, y: shotOriginY_world });
                const { predictionFactorAtMinDistance: minF, predictionFactor: maxF, minPredictionDistance: minD, maxPredictionDistance: maxD } = settings;
                if (distanceToEnemy <= minD) {
                    actualPredictionFactor = minF;
                } else if (distanceToEnemy >= maxD) {
                    actualPredictionFactor = maxF;
                } else if (maxD > minD) {
                    const ratio = (distanceToEnemy - minD) / (maxD - minD);
                    actualPredictionFactor = minF + (maxF - minF) * ratio;
                } else {
                    actualPredictionFactor = maxF;
                }
                actualPredictionFactor = Math.max(0, actualPredictionFactor);
            }
            if (p.dashing) {
                actualPredictionFactor /= 3;
            }
            const worldTargetX = p.x + (baseDisplacementX * actualPredictionFactor);
            const worldTargetY = p.y + (baseDisplacementY * actualPredictionFactor);
            return { x: worldTargetX, y: worldTargetY };
        }

        findBestShootingPoint(shooter, target) {
            const shooterOrigin = this.getBulletOrigin(shooter);
            const predictedCenter = this.calculatePredictedPosition(target, shooter);

            if (this.hasLineOfSight(shooterOrigin, predictedCenter)) {
                return predictedCenter;
            }

            const radius = 24;
            const angles = [
                0, Math.PI / 2, Math.PI, 3 * Math.PI / 2,
                Math.PI / 4, 3 * Math.PI / 4, 5 * Math.PI / 4, 7 * Math.PI / 4
            ];

            for (const angle of angles) {
                const checkPoint = {
                    x: predictedCenter.x + radius * Math.cos(angle),
                    y: predictedCenter.y + radius * Math.sin(angle)
                };
                if (this.hasLineOfSight(shooterOrigin, checkPoint)) {
                    return checkPoint;
                }
            }

            return null;
        }

        performAimbotTargeting(me) {
            if (!this.gameCanvas) {
                this.aimTargetScreenCoords = null;
                this.currentAimbotTarget = null;
                return;
            }

            const finalScale = (typeof unsafeWindow !== 'undefined' && unsafeWindow.widthScaleFactor > 0) ? unsafeWindow.widthScaleFactor : 1.0;

            const settings = GatsModCore.SETTINGS;
            const canvasCenterX = this.gameCanvas.width / 2;
            const canvasCenterY = this.gameCanvas.height / 2;
            let targetCandidate = null;
            let finalTargetPlayerObject = null;
            let refX = settings.aimAtMouseClosest ? this.realMouseCanvasX : canvasCenterX;
            let refY = settings.aimAtMouseClosest ? this.realMouseCanvasY : canvasCenterY;

            let closestPlayerDistSq = settings.aimbotFov ** 2;

            for (const id in Player.pool) {
                const p = Player.pool[id];
                if (!p?.activated || p.hp <= 0 || id == selfId || (me.teamCode !== 0 && p.teamCode === me.teamCode) || settings.aimbotIgnoreList?.includes(p.username)) continue;
                if (settings.followBotEnabled && this.isFollowingPlayer && getDistance(p, me) > settings.followBotAttackRadius) continue;

                const bestShootingPoint = this.findBestShootingPoint(me, p);

                if (bestShootingPoint) {
                    const { x: worldTargetX, y: worldTargetY } = bestShootingPoint;

                    const screenTargetX = canvasCenterX + (worldTargetX - me.x) * finalScale;
                    const screenTargetY = canvasCenterY + (worldTargetY - me.y) * finalScale;

                    const distToRefSq = (screenTargetX - refX) ** 2 + (screenTargetY - refY) ** 2;

                    if (distToRefSq < closestPlayerDistSq) {
                        closestPlayerDistSq = distToRefSq;
                        targetCandidate = { x_world: worldTargetX, y_world: worldTargetY };
                        finalTargetPlayerObject = p;
                    }
                }
            }

            if (targetCandidate) {
                this.aimTargetScreenCoords = {
                    x: canvasCenterX + (targetCandidate.x_world - me.x) * finalScale + settings.espOffsetX,
                    y: canvasCenterY + (targetCandidate.y_world - me.y) * finalScale + settings.espOffsetY
                };

                this.currentAimbotTarget = finalTargetPlayerObject;
                this.predictedTargetWorld = { x: targetCandidate.x_world, y: targetCandidate.y_world };
            } else {
                this.aimTargetScreenCoords = null;
                this.currentAimbotTarget = null;
                this.predictedTargetWorld = { x: 0, y: 0 };
            }
        }

        drawESP(ctx, me, hasTarget) {
            const finalScale = (typeof unsafeWindow !== 'undefined' && unsafeWindow.widthScaleFactor > 0) ? unsafeWindow.widthScaleFactor : 1.0;
            const sizeMultiplier = GatsModCore.SETTINGS.espScale || 1.0;

            const { espColors, espOffsetX, espOffsetY, obstacleOffsetX, obstacleOffsetY, obstacleEspColor } = GatsModCore.SETTINGS;
            if (!this.gameCanvas || !camera?.ctx) return;
            try {
                if (typeof landMine !== 'undefined' && Array.isArray(landMine) && landMine[0]) {
                    landMine[0].forEach((a, i) => {
                        if (landMine[0][i] && landMine[0][i][1]) {
                            landMine[0][i][1][3] = "#000000";
                        }
                    });
                }
            } catch (e) {}
            const canvasCenterX = this.gameCanvas.width / 2, canvasCenterY = this.gameCanvas.height / 2;
            ctx.save();
            ctx.textAlign = 'center';
            ctx.font = 'bold 10px Arial';

            if (GatsModCore.SETTINGS.autoAttackShowRadius) {
                ctx.beginPath();
                ctx.arc(canvasCenterX, canvasCenterY, GatsModCore.SETTINGS.autoAttackRadius, 0, 2 * Math.PI);
                ctx.strokeStyle = 'rgba(255, 255, 0, 0.5)';
                ctx.lineWidth = 1;
                ctx.stroke();
            }

            if (GatsModCore.SETTINGS.obstacleEspEnabled && MapObject && MapObject.pool) {
                ctx.strokeStyle = obstacleEspColor;
                ctx.lineWidth = 2;
                for (const id in MapObject.pool) {
                    const obj = MapObject.pool[id];
                    if (!obj || !obj.activated) continue;
                    let width = obj.width || 50;
                    let height = obj.height || 50;
                    if (obj.type === 'crate') { width = 100; height = 100; }
                    if (obj.type === 'userCrate') { width = 40; height = 40; }
                    const objX = obj.x + obstacleOffsetX;
                    const objY = obj.y + obstacleOffsetY;
                    const screenX = canvasCenterX + (objX - me.x) * finalScale + espOffsetX;
                    const screenY = canvasCenterY + (objY - me.y) * finalScale + espOffsetY;
                    ctx.save();
                    ctx.translate(screenX, screenY);
                    ctx.rotate((obj.angle || 0) * Math.PI / 180);
                    ctx.strokeRect((-width / 2) * finalScale, (-height / 2) * finalScale, width * finalScale, height * finalScale);
                    ctx.restore();
                }
            }

            if (GatsModCore.SETTINGS.losDebugLineEnabled && this.currentAimbotTarget) {
                const startPoint = this.getBulletOrigin(me);
                const endPoint = this.predictedTargetWorld;
                if (startPoint && endPoint.x) {
                    const isClear = this.hasLineOfSight(startPoint, endPoint);
                    ctx.strokeStyle = isClear ? 'rgba(0, 255, 0, 0.7)' : 'rgba(255, 0, 0, 0.7)';
                    ctx.lineWidth = 3;
                    const startScreenX = canvasCenterX + (startPoint.x - me.x) * finalScale + espOffsetX;
                    const startScreenY = canvasCenterY + (startPoint.y - me.y) * finalScale + espOffsetY;
                    const endScreenX = canvasCenterX + (endPoint.x - me.x) * finalScale + espOffsetX;
                    const endScreenY = canvasCenterY + (endPoint.y - me.y) * finalScale + espOffsetY;
                    ctx.beginPath();
                    ctx.moveTo(startScreenX, startScreenY);
                    ctx.lineTo(endScreenX, endScreenY);
                    ctx.stroke();
                }
            }

            for (const id in Player.pool) {
                const p = Player.pool[id];
                if (!p?.activated || p.hp <= 0 || id == selfId) continue;
                const isIgnored = GatsModCore.SETTINGS.aimbotIgnoreList.includes(p.username);
                let isTeammate = (me.teamCode !== 0 && p.teamCode === me.teamCode) || isIgnored;
                if (isTeammate && !GatsModCore.SETTINGS.espShowTeammates && !isIgnored) continue;

                const screenX = canvasCenterX + (p.x - me.x) * finalScale + espOffsetX;
                const screenY = canvasCenterY + (p.y - me.y) * finalScale + espOffsetY;
                const radiusOnScreen = (p.radius || 15) * finalScale * sizeMultiplier;

                let boxColor = isTeammate ? espColors.teammateEspColor : espColors.enemyEspColor;
                if (!isTeammate && GatsModCore.SETTINGS.espHighlightLowHP && p.hp < GatsModCore.SETTINGS.lowHPThreshold) {
                    boxColor = espColors.lowHpEnemyEspColor;
                }
                ctx.strokeStyle = boxColor;
                ctx.lineWidth = 1.5;
                ctx.strokeRect(screenX - radiusOnScreen, screenY - radiusOnScreen, radiusOnScreen * 2, radiusOnScreen * 2);
                ctx.beginPath();
                ctx.moveTo(canvasCenterX + espOffsetX, canvasCenterY + espOffsetY);
                ctx.lineTo(screenX, screenY);
                ctx.stroke();

                let nameYOffset = screenY - radiusOnScreen - 15;

                if (this.isExclusionModeActive && !isTeammate) {
                    ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)';
                    ctx.lineWidth = 2;
                    ctx.setLineDash([4, 4]);
                    ctx.beginPath();
                    const clickRadiusOnScreen = 24 * finalScale * sizeMultiplier;
                    ctx.arc(screenX, screenY, clickRadiusOnScreen, 0, 2 * Math.PI);
                    ctx.stroke();
                    ctx.setLineDash([]);
                }

                if (GatsModCore.SETTINGS.espHighlightCloaked && p.ghillie && !isTeammate) {
                    ctx.font = 'bold 12px Arial';
                    ctx.fillStyle = espColors.cloakedTextColor;
                    ctx.fillText('CLOAKED', screenX, nameYOffset);
                    nameYOffset -= 14;
                }
                if (p.username) {
                    ctx.font = 'bold 10px Arial';
                    ctx.fillStyle = isTeammate ? espColors.teammateNameColor : espColors.enemyNameColor;
                    ctx.fillText(p.username, screenX, nameYOffset);
                }

                if (GatsModCore.SETTINGS.espShowHP) {
                    const hpPercent = p.hp / (p.hpMax || 100);
                    const barW = radiusOnScreen * 1.8, barH = 4;
                    const barX = screenX - barW / 2, barY = screenY + radiusOnScreen + 4;
                    ctx.fillStyle = 'rgba(0,0,0,0.5)';
                    ctx.fillRect(barX, barY, barW, barH);
                    ctx.fillStyle = hpPercent > 0.6 ? espColors.hpBarHighColor : hpPercent > 0.3 ? espColors.hpBarMediumColor : espColors.hpBarLowColor;
                    ctx.fillRect(barX, barY, barW * hpPercent, barH);
                }

                if (!isTeammate && GatsModCore.SETTINGS.espShowPrediction && GatsModCore.SETTINGS.predictionEnabled) {
                    const predictedPos = this.calculatePredictedPosition(p, me);
                    if (predictedPos) {
                        const predScreenX = canvasCenterX + (predictedPos.x - me.x) * finalScale + espOffsetX;
                        const predScreenY = canvasCenterY + (predictedPos.y - me.y) * finalScale + espOffsetY;
                        ctx.strokeStyle = espColors.predictionLineColor || '#FF00FF';
                        ctx.lineWidth = 1;
                        ctx.setLineDash([5, 3]);
                        ctx.beginPath();
                        ctx.moveTo(screenX, screenY);
                        ctx.lineTo(predScreenX, predScreenY);
                        ctx.stroke();
                        ctx.setLineDash([]);
                        ctx.beginPath();
                        ctx.arc(predScreenX, predScreenY, 3, 0, 2 * Math.PI);
                        ctx.fillStyle = espColors.predictionLineColor || '#FF00FF';
                        ctx.fill();
                    }
                }

                if (GatsModCore.SETTINGS.espShowFacingLine && p.playerAngle !== undefined) {
                    const angleRad = p.playerAngle * Math.PI / 180;
                    const lineLen = radiusOnScreen * 1.2;
                    ctx.beginPath();
                    ctx.moveTo(screenX, screenY);
                    ctx.lineTo(screenX + lineLen * Math.cos(angleRad), screenY + lineLen * Math.sin(angleRad));
                    ctx.strokeStyle = espColors.facingLineColor;
                    ctx.lineWidth = 2;
                    ctx.stroke();
                }
            }

            if (hasTarget && this.currentAimAssistTargetCoords) {
                const { x, y } = this.currentAimAssistTargetCoords;
                const originWorld = this.getBulletOrigin(me);
                const originX = canvasCenterX + (originWorld.x - me.x) * finalScale + espOffsetX;
                const originY = canvasCenterY + (originWorld.y - me.y) * finalScale + espOffsetY;
                ctx.strokeStyle = espColors.aimbotTargetLineColor;
                ctx.lineWidth = 1.0;
                ctx.beginPath();
                ctx.moveTo(originX, originY);
                ctx.lineTo(x, y);
                ctx.stroke();
                ctx.beginPath();
                ctx.arc(x, y, 15, 0, 2 * Math.PI);
                ctx.stroke();
            }

            if (GatsModCore.SETTINGS.espShowBulletWarnings && typeof Bullet !== 'undefined' && Bullet.pool) {
                ctx.strokeStyle = espColors.aiBulletWarningColor || '#FF00FF';
                ctx.fillStyle = (espColors.aiBulletWarningColor || '#FF00FF') + '33';
                ctx.lineWidth = 1;
                const dodgeRadiusHorizontal = 150;
                const dodgeRadiusVertical = 15;
                for (const id in Bullet.pool) {
                    const b = Bullet.pool[id];
                    const owner = Player.pool[b.ownerId];
                    if (!b || b.ownerId === selfId || (me.teamCode !== 0 && b.teamCode === me.teamCode) || (owner && GatsModCore.SETTINGS.aimbotIgnoreList.includes(owner.username))) continue;
                    const screenBulletX = canvasCenterX + (b.x - me.x) * finalScale + espOffsetX;
                    const screenBulletY = canvasCenterY + (b.y - me.y) * finalScale + espOffsetY;
                    const radiusX = dodgeRadiusHorizontal * finalScale * sizeMultiplier;
                    const radiusY = dodgeRadiusVertical * finalScale * sizeMultiplier;
                    const rotation = (b.spdX === 0 && b.spdY === 0) ? 0 : Math.atan2(b.spdY, b.spdX);
                    ctx.beginPath();
                    ctx.ellipse(screenBulletX, screenBulletY, radiusX, radiusY, rotation, 0, 2 * Math.PI);
                    ctx.stroke();
                    ctx.fill();
                }
            }

            if (GatsModCore.SETTINGS.zeroAIEnabled) {
                const { aiShowPathfindingWhiskers, aiShowFinalMoveDirection, aiShowEnemyThreatLine } = GatsModCore.SETTINGS;
                const { whiskers, finalMoveDirection } = this.aiDebugData;

                if (aiShowPathfindingWhiskers && whiskers.length > 0) {
                    whiskers.forEach(whisker => {
                        const startScreenX = canvasCenterX + (whisker.start.x - me.x) * finalScale + espOffsetX;
                        const startScreenY = canvasCenterY + (whisker.start.y - me.y) * finalScale + espOffsetY;
                        const endScreenX = canvasCenterX + (whisker.end.x - me.x) * finalScale + espOffsetX;
                        const endScreenY = canvasCenterY + (whisker.end.y - me.y) * finalScale + espOffsetY;
                        ctx.beginPath();
                        ctx.moveTo(startScreenX, startScreenY);
                        ctx.lineTo(endScreenX, endScreenY);
                        ctx.strokeStyle = whisker.isClear ? espColors.aiWhiskerClearColor : espColors.aiWhiskerBlockedColor;
                        ctx.lineWidth = whisker.isBest ? 3 : 1;
                        ctx.stroke();
                    });
                }
                if (aiShowFinalMoveDirection && finalMoveDirection) {
                    const startScreenX = canvasCenterX + (finalMoveDirection.start.x - me.x) * finalScale + espOffsetX;
                    const startScreenY = canvasCenterY + (finalMoveDirection.start.y - me.y) * finalScale + espOffsetY;
                    const endScreenX = canvasCenterX + (finalMoveDirection.end.x - me.x) * finalScale + espOffsetX;
                    const endScreenY = canvasCenterY + (finalMoveDirection.end.y - me.y) * finalScale + espOffsetY;
                    ctx.beginPath();
                    ctx.moveTo(startScreenX, startScreenY);
                    ctx.lineTo(endScreenX, endScreenY);
                    ctx.strokeStyle = espColors.aiMoveDirColor;
                    ctx.lineWidth = 4;
                    ctx.stroke();
                    const headlen = 10;
                    const angle = Math.atan2(endScreenY - startScreenY, endScreenX - startScreenX);
                    ctx.lineTo(endScreenX - headlen * Math.cos(angle - Math.PI / 6), endScreenY - headlen * Math.sin(angle - Math.PI / 6));
                    ctx.moveTo(endScreenX, endScreenY);
                    ctx.lineTo(endScreenX - headlen * Math.cos(angle + Math.PI / 6), endScreenY - headlen * Math.sin(angle + Math.PI / 6));
                    ctx.stroke();
                }
                if (aiShowEnemyThreatLine) {
                    const nearestEnemy = this.findNearestEnemy(me);
                    if (nearestEnemy) {
                        const enemyGunOrigin = this.getBulletOrigin(nearestEnemy);
                        const isClear = this.hasLineOfSight(enemyGunOrigin, me);
                        ctx.strokeStyle = isClear ? espColors.aiThreatLineClearColor : espColors.aiThreatLineBlockedColor;
                        ctx.lineWidth = 2;
                        ctx.setLineDash([10, 5]);
                        const startScreenX = canvasCenterX + (enemyGunOrigin.x - me.x) * finalScale;
                        const startScreenY = canvasCenterY + (enemyGunOrigin.y - me.y) * finalScale;
                        const endScreenX = canvasCenterX;
                        const endScreenY = canvasCenterY;
                        ctx.beginPath();
                        ctx.moveTo(startScreenX, startScreenY);
                        ctx.lineTo(endScreenX, endScreenY);
                        ctx.stroke();
                        ctx.setLineDash([]);
                    }
                }
            }

            ctx.restore();
        }

        performSpinbotActions(me) {
            if (!GatsModCore.SETTINGS.spinbotEnabled) {
                this.spinbotTargetScreenCoords = null;
                return;
            }
            const now = performance.now();
            if (now - this.lastSpinTime > GatsModCore.SETTINGS.spinbotSpeedMs) {
                this.spinbotCurrentTargetIndex = (this.spinbotCurrentTargetIndex + 1) % 3;
                this.lastSpinTime = now;
            }
            if (!this.gameCanvas) return;
            const canvasCenterX = this.gameCanvas.width / 2, canvasCenterY = this.gameCanvas.height / 2;
            const spinDist = GatsModCore.SETTINGS.spinbotDistance;
            let worldTargetX, worldTargetY;
            switch (this.spinbotCurrentTargetIndex) {
                case 0: worldTargetX = me.x; worldTargetY = me.y - spinDist; break;
                case 1: worldTargetX = me.x + spinDist; worldTargetY = me.y + spinDist; break;
                case 2: worldTargetX = me.x - spinDist; worldTargetY = me.y + spinDist; break;
                default: worldTargetX = me.x; worldTargetY = me.y;
            }
            this.spinbotTargetScreenCoords = { x: canvasCenterX + (worldTargetX - me.x), y: canvasCenterY + (worldTargetY - me.y) };
        }

        getBotPhysics(player) {
            const weapon = player.class || 'pistol';
            const armor = player.armor || 0;
            const upgrades = player.levelUpgrades ? Object.values(player.levelUpgrades) : [];
            const baseSpeed = GatsModCore.PLAYER_SPEEDS.base[weapon] || GatsModCore.PLAYER_SPEEDS.base['pistol'];
            const armorMod = GatsModCore.PLAYER_SPEEDS.armorMultiplier[armor] || 1.0;
            const upgradeMod = upgrades.includes('lightweight') ? GatsModCore.PLAYER_SPEEDS.upgradeMultiplier['lightweight'] : 1.0;
            const maxSpeed = baseSpeed * armorMod * upgradeMod;
            const ACCELERATION = maxSpeed / 16.0;
            const FRICTION = 0.94;
            return { maxSpeed, ACCELERATION, FRICTION };
        }

        performFollowBotActions(me) {
            if (!this.isFollowingPlayer || this.followingPlayerId === null) {
                GatsModCore.stopFollowingPlayer(true);
                return;
            }
            const targetPlayer = Player.pool[this.followingPlayerId];
            if (!targetPlayer?.activated || targetPlayer.hp <= 0) {
                GatsModCore.stopFollowingPlayer();
                return;
            }
            const { maxSpeed, ACCELERATION, FRICTION } = this.getBotPhysics(me);
            const dx = targetPlayer.x - me.x;
            const dy = targetPlayer.y - me.y;
            const distance = Math.hypot(dx, dy);
            let desiredSpdX = 0;
            let desiredSpdY = 0;
            const stopDistance = 15;
            if (distance > stopDistance) {
                const brakingFactor = 12.0;
                const desiredSpeed = Math.min(maxSpeed, distance / brakingFactor);
                desiredSpdX = (dx / distance) * desiredSpeed;
                desiredSpdY = (dy / distance) * desiredSpeed;
            }
            const requiredAccelX = (desiredSpdX / FRICTION) - this.botSpdX;
            const requiredAccelY = (desiredSpdY / FRICTION) - this.botSpdY;
            let keysToPress = [];
            let isPressingKeyX = 0;
            let isPressingKeyY = 0;
            const keyPressThreshold = ACCELERATION * 0.1;
            if (requiredAccelX > keyPressThreshold) {
                keysToPress.push('d');
                isPressingKeyX = 1;
            } else if (requiredAccelX < -keyPressThreshold) {
                keysToPress.push('a');
                isPressingKeyX = -1;
            }
            if (requiredAccelY > keyPressThreshold) {
                keysToPress.push('s');
                isPressingKeyY = 1;
            } else if (requiredAccelY < -keyPressThreshold) {
                keysToPress.push('w');
                isPressingKeyY = -1;
            }
            this.updateSimulatedKeys(keysToPress);
            let appliedAccelX = isPressingKeyX * ACCELERATION;
            let appliedAccelY = isPressingKeyY * ACCELERATION;
            if (isPressingKeyX !== 0 && isPressingKeyY !== 0) {
                appliedAccelX *= GatsModCore.PLAYER_SPEEDS.diagonalCorrection;
                appliedAccelY *= GatsModCore.PLAYER_SPEEDS.diagonalCorrection;
            }
            this.botSpdX = (this.botSpdX + appliedAccelX) * FRICTION;
            this.botSpdY = (this.botSpdY + appliedAccelY) * FRICTION;
            const currentSimulatedSpeed = Math.hypot(this.botSpdX, this.botSpdY);
            if (currentSimulatedSpeed > maxSpeed) {
                const ratio = maxSpeed / currentSimulatedSpeed;
                this.botSpdX *= ratio;
                this.botSpdY *= ratio;
            }
        }

        updateSimulatedKeys(keysToPress) {
            const allKeys = ['w', 'a', 's', 'd'];
            allKeys.forEach(key => {
                const shouldBePressed = keysToPress.includes(key);
                if (shouldBePressed !== this.simulatedKeys[key]) {
                    this._fireKeyEvent(shouldBePressed ? 'keydown' : 'keyup', key);
                    this.simulatedKeys[key] = shouldBePressed;
                }
            });
        }

        _fireKeyEvent(type, key) {
            const keyMap = { 'w': 87, 'a': 65, 's': 83, 'd': 68, ' ': 32, 'r': 82 };
            const codeMap = { 'w': 'KeyW', 'a': 'KeyA', 's': 'KeyS', 'd': 'KeyD', ' ': 'Space', 'r': 'KeyR' };
            if (!keyMap[key]) return;
            document.dispatchEvent(new KeyboardEvent(type, { key: key, code: codeMap[key], keyCode: keyMap[key], bubbles: true, cancelable: true, composed: true }));
        }

        startFollowingPlayer() {
            const targetName = GatsModCore.SETTINGS.followBotTargetName;
            if (!targetName) {
                alert("Set a target name first using the 'Follow Bot Control' panel.");
                return;
            }
            const foundPlayer = Object.values(Player.pool).find(p => p.username === targetName && p.activated && p.id !== selfId);
            if (foundPlayer) {
                this.isFollowingPlayer = true;
                this.followingPlayerId = foundPlayer.id;
                modLog(`Started following ${targetName}`);
            } else {
                alert(`Player "${targetName}" not found or is not active.`);
                this.isFollowingPlayer = false;
                this.followingPlayerId = null;
            }
            this.simpleGui.updateFollowBotStatusDisplay();
        }

        handleClickToIgnore(event) {
            const me = Player.pool?.[selfId];
            if (!this.isExclusionModeActive || !Player.pool || !me) return;

            const rect = this.gameCanvas.getBoundingClientRect();
            const clickX = event.clientX - rect.left;
            const clickY = event.clientY - rect.top;

            const settings = GatsModCore.SETTINGS;
            const canvasCenterX = this.gameCanvas.width / 2;
            const canvasCenterY = this.gameCanvas.height / 2;

            let clickedPlayer = null;
            let closestDistSq = Infinity;

            for (const id in Player.pool) {
                const p = Player.pool[id];
                if (!p?.activated || p.hp <= 0 || id == selfId || (me.teamCode !== 0 && p.teamCode === me.teamCode)) continue;

                const relX = (p.x - me.x) / settings.espScale;
                const relY = (p.y - me.y) / settings.espScale;
                const screenX = canvasCenterX + relX + settings.espOffsetX;
                const screenY = canvasCenterY + relY + settings.espOffsetY;

                const distSq = (clickX - screenX) ** 2 + (clickY - screenY) ** 2;
                const clickRadius = 24 / settings.espScale;

                if (distSq < clickRadius * clickRadius && distSq < closestDistSq) {
                    closestDistSq = distSq;
                    clickedPlayer = p;
                }
            }

            if (clickedPlayer) {
                this.addPlayerToIgnoreList(clickedPlayer.username);
            }
        }

        addPlayerToIgnoreList(username, silent = false) {
            if (!username) return;
            const settings = GatsModCore.SETTINGS;
            if (!settings.aimbotIgnoreList.includes(username)) {
                settings.aimbotIgnoreList.push(username);
                GatsModCore.saveSettings();
                this.simpleGui?.updateAimbotExclusionListDisplay();
                if (!silent) modLog(`Player "${username}" added to ignore list.`);
            } else {
                if (silent) return;
                GatsModCore.SETTINGS.aimbotIgnoreList = GatsModCore.SETTINGS.aimbotIgnoreList.filter(n => n !== username);
                GatsModCore.saveSettings();
                this.simpleGui.updateAimbotExclusionListDisplay();
                modLog(`Player "${username}" removed from ignore list.`);
            }
        }

        static saveSettings() {
            try {
                localStorage.setItem(SETTINGS_KEY, JSON.stringify(GatsModCore.SETTINGS));
            } catch (e) {
                modLog("Error saving settings: " + e.message, true);
            }
        }

        static saveProfile(name) {
            if (!name) {
                alert("Please enter a profile name.");
                return;
            }
            if (!GatsModCore.SETTINGS.settingProfiles) {
                GatsModCore.SETTINGS.settingProfiles = {};
            }
            const settingsToSave = { ...GatsModCore.SETTINGS };
            delete settingsToSave.settingProfiles;
            GatsModCore.SETTINGS.settingProfiles[name] = JSON.stringify(settingsToSave);
            GatsModCore.saveSettings();
            gatsModInstance?.simpleGui?.updateProfileList();
            alert(`Profile "${name}" saved.`);
        }

        static loadProfile(name) {
            if (!name) {
                alert("Select a profile to load.");
                return;
            }
            const profileDataString = GatsModCore.SETTINGS.settingProfiles?.[name];
            if (!profileDataString) {
                alert(`Profile "${name}" not found.`);
                return;
            }
            try {
                const loadedProfileSettings = JSON.parse(profileDataString);
                const preservedProfiles = GatsModCore.SETTINGS.settingProfiles;
                const preservedEspColors = GatsModCore.SETTINGS.espColors;
                GatsModCore.SETTINGS = { ...GatsModCore.SETTINGS, ...loadedProfileSettings };
                GatsModCore.SETTINGS.settingProfiles = preservedProfiles;
                GatsModCore.SETTINGS.espColors = GatsModCore.SETTINGS.espColors || preservedEspColors;
                GatsModCore.saveSettings();
                gatsModInstance?.simpleGui?.updateAllGUIToReflectSettings();
                if (gatsModInstance?.colorGui && GatsModCore.SETTINGS.espColors) {
                    Object.keys(GatsModCore.SETTINGS.espColors).forEach(key => {
                        const picker = document.getElementById(key + '-color-v2');
                        if (picker) picker.value = GatsModCore.SETTINGS.espColors[key];
                    });
                }
                alert(`Profile "${name}" loaded.`);
            } catch (e) {
                alert("Error loading profile. It may be corrupt: " + e.message);
            }
        }

        static deleteProfile(name) {
            if (!name || !confirm(`Are you sure you want to delete the profile "${name}"?`)) return;
            if (GatsModCore.SETTINGS.settingProfiles?.[name]) {
                delete GatsModCore.SETTINGS.settingProfiles[name];
                GatsModCore.saveSettings();
                gatsModInstance?.simpleGui?.updateProfileList();
                alert(`Profile "${name}" deleted.`);
            }
        }

        static setFollowTargetName() {
            const newName = prompt("Enter player name to follow:", GatsModCore.SETTINGS.followBotTargetName);
            if (newName !== null) {
                const oldName = GatsModCore.SETTINGS.followBotTargetName;
                GatsModCore.SETTINGS.followBotTargetName = newName.trim();
                GatsModCore.saveSettings();
                gatsModInstance?.simpleGui?.updateFollowBotStatusDisplay();
                if (gatsModInstance?.isFollowingPlayer && oldName !== newName.trim()) {
                    GatsModCore.stopFollowingPlayer(true);
                }
                alert(`Follow target set to: ${newName.trim()}`);
            }
        }

        static stopFollowingPlayer(silent = false) {
            if (!gatsModInstance) return;
            if (gatsModInstance.isFollowingPlayer || Object.values(gatsModInstance.simulatedKeys).some(s => s)) {
                gatsModInstance.updateSimulatedKeys([]);
            }
            gatsModInstance.isFollowingPlayer = false;
            gatsModInstance.followingPlayerId = null;
            gatsModInstance.botSpdX = 0;
            gatsModInstance.botSpdY = 0;
            if (!silent) modLog("FollowBot stopped.");
            gatsModInstance?.simpleGui?.updateFollowBotStatusDisplay();
        }

        static showPlayerList() {
            const modal = document.getElementById('player-list-modal');
            const grid = document.getElementById('player-list-grid');
            if (!modal || !grid || typeof Player === 'undefined' || !Player.pool || typeof selfId === 'undefined') {
                alert("Player data not available yet.");
                return;
            }
            grid.innerHTML = '';
            Object.values(Player.pool).filter(p => p?.activated && p.id !== selfId && p.username).forEach(p => {
                const btn = document.createElement('button');
                btn.className = 'player-list-button';
                btn.innerText = p.username;
                btn.title = p.username;
                btn.onclick = () => {
                    GatsModCore.SETTINGS.followBotTargetName = p.username;
                    GatsModCore.saveSettings();
                    gatsModInstance?.simpleGui?.updateFollowBotStatusDisplay();
                    gatsModInstance?.startFollowingPlayer();
                    modal.style.display = 'none';
                };
                grid.appendChild(btn);
            });
            modal.style.display = 'flex';
        }

        static startChatScroll() {
            if (!GatsModCore.SETTINGS.chatScrollEnabled) {
                alert("Chat Scroller is disabled in settings.");
                return;
            }
            if (GatsModCore.SETTINGS.chatScrollActive) GatsModCore.stopChatScroll();
            GatsModCore.SETTINGS.chatScrollActive = true;
            GatsModCore.chatScrollCurrentIndex = 0;
            gatsModInstance?.simpleGui?.updateScrollingTextDisplay(GatsModCore.SETTINGS.chatScrollText);
            modLog("ChatScroller: Started.");
            GatsModCore.chatScrollLoop();
        }

        static stopChatScroll() {
            if (GatsModCore.chatScrollIntervalId) {
                clearTimeout(GatsModCore.chatScrollIntervalId);
                GatsModCore.chatScrollIntervalId = null;
            }
            GatsModCore.SETTINGS.chatScrollActive = false;
            modLog("ChatScroller: Stopped.");
        }

        static chatScrollLoop() {
            if (!GatsModCore.SETTINGS.chatScrollActive || !GatsModCore.SETTINGS.chatScrollEnabled || GatsModCore.isInputActive) {
                if (!GatsModCore.SETTINGS.chatScrollEnabled || GatsModCore.isInputActive) GatsModCore.stopChatScroll();
                return;
            }
            if (!Connection.list?.[0]?.socket?.send) {
                modLog("ChatScroller: Connection not available.", true);
                GatsModCore.stopChatScroll();
                return;
            }
            const s = GatsModCore.SETTINGS.chatScrollText;
            if (!s?.length) {
                GatsModCore.stopChatScroll();
                return;
            }
            let maxLength = GatsModCore.SETTINGS.chatScrollMaxLength;
            if (s.length < maxLength) maxLength = s.length;
            let displayText = s.substring(GatsModCore.chatScrollCurrentIndex, GatsModCore.chatScrollCurrentIndex + maxLength);
            if (displayText.length < maxLength && s.length > maxLength) {
                displayText += " " + s.substring(0, maxLength - displayText.length - 1);
            }
            displayText = displayText.trim();
            GatsModCore.sendChatMessage(displayText);
            GatsModCore.chatScrollCurrentIndex = (GatsModCore.chatScrollCurrentIndex + 1) % s.length;
            if (GatsModCore.SETTINGS.chatScrollActive) {
                GatsModCore.chatScrollIntervalId = setTimeout(GatsModCore.chatScrollLoop, GatsModCore.SETTINGS.chatScrollSpeed);
            }
        }

        static startSequencer() {
            if (!GatsModCore.SETTINGS.sequencerEnabled) {
                alert("Sequencer is disabled in settings.");
                return;
            }
            if (GatsModCore.SETTINGS.sequencerActive) GatsModCore.stopSequencer();
            GatsModCore.SETTINGS.sequencerActive = true;
            GatsModCore.sequencerCurrentIndex = 0;
            modLog("Sequencer: Started.");
            GatsModCore.sequencerLoop();
        }

        static stopSequencer() {
            if (GatsModCore.sequencerIntervalId) {
                clearTimeout(GatsModCore.sequencerIntervalId);
                GatsModCore.sequencerIntervalId = null;
            }
            GatsModCore.SETTINGS.sequencerActive = false;
            modLog("Sequencer: Stopped.");
        }

        static sequencerLoop() {
            if (!GatsModCore.SETTINGS.sequencerActive || !GatsModCore.SETTINGS.sequencerEnabled || GatsModCore.isInputActive) {
                if (!GatsModCore.SETTINGS.sequencerEnabled || GatsModCore.isInputActive) GatsModCore.stopSequencer();
                return;
            }
            const presets = GatsModCore.SETTINGS.chatPresetMessages;
            if (GatsModCore.sequencerCurrentIndex >= presets.length) {
                if (GatsModCore.SETTINGS.sequencerLoop) {
                    GatsModCore.sequencerCurrentIndex = 0;
                } else {
                    GatsModCore.stopSequencer();
                    return;
                }
            }
            const message = presets[GatsModCore.sequencerCurrentIndex];
            if (message && message.trim().length > 0) GatsModCore.sendChatMessage(message);
            GatsModCore.sequencerCurrentIndex++;
            if (GatsModCore.SETTINGS.sequencerActive) {
                GatsModCore.sequencerIntervalId = setTimeout(GatsModCore.sequencerLoop, GatsModCore.SETTINGS.sequencerDelay);
            }
        }

        static sendChatMessage(message) {
            if (!message || message.trim().length === 0) return;
            if (!Connection.list?.[0]?.socket?.send) {
                modLog("Chat: Connection not available.", true);
                return;
            }
            try {
                const sanitizedMessage = message.replaceAll(",", "~");
                Connection.list[0].socket.send(`c,${sanitizedMessage}\x00`);
            } catch (e) {
                modLog(`Chat: Error sending message: ${e.message}`, true);
            }
        }

        static editScrollPreset(index) {
            if (GatsModCore.SETTINGS.chatPresetMessages?.[index] === undefined) return;
            const currentMessage = GatsModCore.SETTINGS.chatPresetMessages[index];
            const newMessage = prompt(`Edit Preset ${index + 1}:`, currentMessage.trim());
            if (newMessage !== null) {
                GatsModCore.SETTINGS.chatPresetMessages[index] = newMessage.trim() === "" ? " " : newMessage;
                GatsModCore.saveSettings();
                gatsModInstance?.simpleGui?.updatePresetButtonLabel(index, GatsModCore.SETTINGS.chatPresetMessages[index]);
                if (GatsModCore.SETTINGS.chatScrollText.trim() === currentMessage.trim()) {
                    GatsModCore.SETTINGS.chatScrollText = GatsModCore.SETTINGS.chatPresetMessages[index];
                    gatsModInstance?.simpleGui?.updateScrollingTextDisplay(GatsModCore.SETTINGS.chatScrollText);
                }
                alert(`Preset ${index + 1} updated.`);
            }
        }

        static setScrollPreset(index) {
            if (GatsModCore.SETTINGS.chatPresetMessages?.[index] !== undefined) {
                const presetText = GatsModCore.SETTINGS.chatPresetMessages[index];
                GatsModCore.SETTINGS.chatScrollText = presetText;
                GatsModCore.saveSettings();
                gatsModInstance?.simpleGui?.updateScrollingTextDisplay(presetText);
                GatsModCore.sendChatMessage(presetText);
                if (GatsModCore.SETTINGS.chatScrollActive) GatsModCore.startChatScroll();
                modLog(`ChatScroller: Preset ${index + 1} set and sent once.`);
            }
        }

        findNearestEnemy(me) {
            let closestEnemy = null;
            let minDistanceSq = Infinity;
            for (const id in Player.pool) {
                const p = Player.pool[id];
                if (!p?.activated || p.hp <= 0 || id == selfId || (me.teamCode !== 0 && p.teamCode === me.teamCode) || GatsModCore.SETTINGS.aimbotIgnoreList.includes(p.username)) continue;
                const distSq = (p.x - me.x) ** 2 + (p.y - me.y) ** 2;
                if (distSq < minDistanceSq) {
                    minDistanceSq = distSq;
                    closestEnemy = p;
                }
            }
            return closestEnemy;
        }

        performZeroAIActions(me) {
            this.performAutoReload(me);

            let movementGoal = null;
            let aiMode = 'idle';
            const nearestEnemy = this.findNearestEnemy(me);

            if (this.multibox.isChild && this.multibox.parentCoords) {
                const distToParent = getDistance(me, this.multibox.parentCoords);
                if (distToParent > 400) {
                    movementGoal = this.multibox.parentCoords;
                    aiMode = 'following_parent';
                }
            }

            const bounds = GatsModCore.MAP_BOUNDS;
            if (!movementGoal && (me.x < bounds.minX || me.x > bounds.maxX || me.y < bounds.minY || me.y > bounds.maxY)) {
                movementGoal = { x: (bounds.minX + bounds.maxX) / 2, y: (bounds.minY + bounds.maxY) / 2 };
                aiMode = 'returning_to_bounds';
            }

            if (!movementGoal) {
                movementGoal = this.getExplosiveAvoidanceGoal(me);
                if (movementGoal) aiMode = 'fleeing_explosive';
            }

            if (!movementGoal && GatsModCore.SETTINGS.aiBulletDodging) {
                movementGoal = this.getBulletDodgeGoal(me);
                if (movementGoal) aiMode = 'dodging';
            }

            if (!movementGoal && nearestEnemy) {
                movementGoal = this.getPotentialThreatDodgeGoal(me, nearestEnemy);
                if (movementGoal) aiMode = 'pre_dodging';
            }

            if (!movementGoal && GatsModCore.SETTINGS.aiAutoRetreat) {
                const isLowHp = me.hp <= GatsModCore.SETTINGS.aiRetreatHP;
                const isReloading = me.reloading;
                if (isLowHp || isReloading) {
                    const retreatGoal = this.getSafestRetreatGoal(me);
                    if (retreatGoal) {
                        movementGoal = retreatGoal;
                        aiMode = 'retreating';
                    } else if (nearestEnemy) {
                        movementGoal = { x: me.x - (nearestEnemy.x - me.x), y: me.y - (nearestEnemy.y - me.y) };
                        aiMode = 'retreating';
                    }
                }
            }

            if (!movementGoal && GatsModCore.SETTINGS.aiEnableKiting && nearestEnemy) {
                const kitingGoal = this.getOptimalKitingGoal(me, nearestEnemy);
                if (kitingGoal) {
                    movementGoal = kitingGoal;
                    aiMode = 'kiting';
                }
            }

            if (!movementGoal && GatsModCore.SETTINGS.aiAutoMovement) {
                if (this.multibox.isChild && this.multibox.parentCoords) {
                    movementGoal = this.multibox.parentCoords;
                    aiMode = 'following_parent';
                }
                else if (GatsModCore.SETTINGS.followBotEnabled && GatsModCore.SETTINGS.followBotTargetName) {
                    const followTarget = Object.values(Player.pool).find(p => p.username === GatsModCore.SETTINGS.followBotTargetName && p.activated);
                    if (followTarget) {
                        movementGoal = { x: followTarget.x, y: followTarget.y };
                        aiMode = 'following';
                    }
                }

                if (!movementGoal) {
                    if (nearestEnemy) {
                        movementGoal = { x: nearestEnemy.x, y: nearestEnemy.y };
                        const dist = getDistance(me, nearestEnemy);
                        if (nearestEnemy.class === 'shotgun' && dist < 450) {
                            aiMode = 'distancing';
                        } else {
                            aiMode = 'attacking';
                        }
                    } else {
                        movementGoal = { x: (bounds.minX + bounds.maxX) / 2, y: (bounds.minY + bounds.maxY) / 2 };
                        aiMode = 'patrolling';
                    }
                }
            }

            if (movementGoal) {
                movementGoal.x = Math.max(bounds.minX, Math.min(bounds.maxX, movementGoal.x));
                movementGoal.y = Math.max(bounds.minY, Math.min(bounds.maxY, movementGoal.y));
            }

            if (movementGoal) {
                this.moveAITowards(me, movementGoal);
            } else {
                this.updateSimulatedKeys([]);
                this.aiDebugData.whiskers = [];
                this.aiDebugData.finalMoveDirection = null;
            }

            if (GatsModCore.SETTINGS.aiAutoParkUsage) {
                this.useParkAbility(me);
            }

            if (GatsModCore.SETTINGS.aiAutoTalk) {
                this.handleSituationalAITalk(me, nearestEnemy, aiMode);
            }
        }

        performAutoReload(me) {
            if (!GatsModCore.SETTINGS.zeroAIEnabled || me.reloading || !me.magSize || me.mag >= me.magSize) {
                return;
            }

            const reloadSafetyRadiusSq = 500 * 500;
            let enemyNearby = false;
            for (const id in Player.pool) {
                const p = Player.pool[id];
                if (!p?.activated || p.hp <= 0 || id == selfId || (me.teamCode !== 0 && p.teamCode === me.teamCode)) continue;
                const distSq = (p.x - me.x) ** 2 + (p.y - me.y) ** 2;
                if (distSq < reloadSafetyRadiusSq) {
                    enemyNearby = true;
                    break;
                }
            }

            if (!enemyNearby) {
                modLog("AI: Auto-reloading.");
                this._fireKeyEvent('keydown', 'r');
                setTimeout(() => this._fireKeyEvent('keyup', 'r'), 50);
            }
        }

        getPotentialThreatDodgeGoal(me, enemy) {
            if (!enemy) return null;

            const enemyGunOrigin = this.getBulletOrigin(enemy);
            const distanceToSelf = getDistance(enemyGunOrigin, me);

            const enemyRange = this.getEstimatedEnemyRange(enemy);
            if (distanceToSelf > enemyRange * 1.2) {
                return null;
            }

            const threatWidth = 30;
            const threatHalfWidth = threatWidth / 2;

            const dx_threat = me.x - enemyGunOrigin.x;
            const dy_threat = me.y - enemyGunOrigin.y;
            const dist_threat = Math.hypot(dx_threat, dy_threat);
            let isThreatened = false;

            if (dist_threat > 0.1) {
                const dir_x = dx_threat / dist_threat;
                const dir_y = dy_threat / dist_threat;
                const perp_x = -dir_y;
                const perp_y = dir_x;

                const checkPointCenter = me;
                const checkPointLeft = { x: me.x + perp_x * threatHalfWidth, y: me.y + perp_y * threatHalfWidth };
                const checkPointRight = { x: me.x - perp_x * threatHalfWidth, y: me.y - perp_y * threatHalfWidth };

                isThreatened = this.hasLineOfSight(enemyGunOrigin, checkPointCenter) ||
                                 this.hasLineOfSight(enemyGunOrigin, checkPointLeft) ||
                                 this.hasLineOfSight(enemyGunOrigin, checkPointRight);
            } else {
                isThreatened = true;
            }

            if (isThreatened) {
                const threatDx = me.x - enemyGunOrigin.x;
                const threatDy = me.y - enemyGunOrigin.y;

                const dodgeVector = { x: -threatDy, y: threatDx };
                const dodgeMagnitude = 200;
                const vectorLength = Math.hypot(dodgeVector.x, dodgeVector.y);

                if (vectorLength > 0.1) {
                    return {
                        x: me.x + (dodgeVector.x / vectorLength) * dodgeMagnitude,
                        y: me.y + (dodgeVector.y / vectorLength) * dodgeMagnitude
                    };
                }
            }
            return null;
        }

        getSafestRetreatGoal(me) {
            const retreatCheckRadiusSq = 800 * 800;
            let totalRepulsion = { x: 0, y: 0 };
            let threatsFound = 0;

            for (const id in Player.pool) {
                const p = Player.pool[id];
                if (!p?.activated || p.hp <= 0 || id == selfId || (me.teamCode !== 0 && p.teamCode === me.teamCode) || GatsModCore.SETTINGS.aimbotIgnoreList.includes(p.username)) continue;

                const dx = me.x - p.x;
                const dy = me.y - p.y;
                const distSq = dx * dx + dy * dy;

                if (distSq < retreatCheckRadiusSq && distSq > 1) {
                    threatsFound++;
                    const distance = Math.sqrt(distSq);
                    const repulsionStrength = 1 / distance;
                    totalRepulsion.x += (dx / distance) * repulsionStrength;
                    totalRepulsion.y += (dy / distance) * repulsionStrength;
                }
            }

            if (threatsFound > 0) {
                const magnitude = Math.hypot(totalRepulsion.x, totalRepulsion.y);
                if (magnitude > 0.01) {
                    const retreatDistance = 500;
                    return {
                        x: me.x + (totalRepulsion.x / magnitude) * retreatDistance,
                        y: me.y + (totalRepulsion.y / magnitude) * retreatDistance
                    };
                }
            }
            return null;
        }

        getOptimalKitingGoal(me, enemy) {
            const myRange = this.getMyWeaponRange(me);
            const enemyRange = this.getEstimatedEnemyRange(enemy);

            if (myRange > enemyRange + 50) {
                const optimalDistance = myRange * 0.9;
                const currentDistance = getDistance(me, enemy);

                const dx = me.x - enemy.x;
                const dy = me.y - enemy.y;

                const targetX = enemy.x + (dx / currentDistance) * optimalDistance;
                const targetY = enemy.y + (dy / currentDistance) * optimalDistance;

                return { x: targetX, y: targetY };
            }

            return null;
        }

        getBulletDodgeGoal(me) {
            const dodgeRadiusHorizontal = 150;
            const dodgeRadiusVertical = 15;
            const playerRadius = me.radius || 26;
            let bestDodgeVector = { x: 0, y: 0 };
            let threatsFound = 0;

            if (typeof Bullet === 'undefined' || !Bullet.pool) return null;

            for (const id in Bullet.pool) {
                const b = Bullet.pool[id];
                const owner = Player.pool[b.ownerId];
                if (!b || b.ownerId === selfId || (me.teamCode !== 0 && b.teamCode === me.teamCode) || (b.spdX === 0 && b.spdY === 0) || (owner && GatsModCore.SETTINGS.aimbotIgnoreList.includes(owner.username))) continue;

                const predictionTime = 0.4;
                const futureBulletX = b.x + b.spdX * predictionTime * 60;
                const futureBulletY = b.y + b.spdY * predictionTime * 60;

                const bulletSpeed = Math.hypot(b.spdX, b.spdY);
                if (bulletSpeed < 0.1) continue;

                const v_dir_x = b.spdX / bulletSpeed;
                const v_dir_y = b.spdY / bulletSpeed;

                const dx = me.x - futureBulletX;
                const dy = me.y - futureBulletY;

                const dist_vertical = dx * v_dir_x + dy * v_dir_y;
                const dist_horizontal = dx * (-v_dir_y) + dy * v_dir_x;

                const normalized_dist_sq = (dist_horizontal / (dodgeRadiusHorizontal + playerRadius)) ** 2 + (dist_vertical / (dodgeRadiusVertical + playerRadius)) ** 2;

                if (normalized_dist_sq <= 1) {
                    threatsFound++;
                    bestDodgeVector.x += -b.spdY / bulletSpeed;
                    bestDodgeVector.y += b.spdX / bulletSpeed;
                }
            }

            if (threatsFound > 0) {
                const dodgeMagnitude = 200;
                const vectorLength = Math.hypot(bestDodgeVector.x, bestDodgeVector.y);
                if (vectorLength > 0) {
                    return {
                        x: me.x + (bestDodgeVector.x / vectorLength) * dodgeMagnitude,
                        y: me.y + (bestDodgeVector.y / vectorLength) * dodgeMagnitude
                    };
                }
            }
            return null;
        }

        getExplosiveAvoidanceGoal(me) {
            if (typeof Explosive === 'undefined' || !Explosive.pool) {
                return null;
            }

            let totalRepulsion = { x: 0, y: 0 };
            let threatsFound = 0;

            for (const id in Explosive.pool) {
                const explosive = Explosive.pool[id];

                if (!explosive || !explosive.activated || !explosive.type || typeof explosive.x === 'undefined' || typeof explosive.y === 'undefined') {
                    continue;
                }

                let dangerRadius = 0;
                switch (explosive.type) {
                    case 'landMine':
                        dangerRadius = 70;
                        break;
                    case 'grenade':
                    case 'fragGrenade':
                        dangerRadius = 600;
                        break;
                    case 'gasGrenade':
                        dangerRadius = 400;
                        break;
                    default:
                        continue;
                }

                const dx = me.x - explosive.x;
                const dy = me.y - explosive.y;
                const distSq = dx * dx + dy * dy;

                if (distSq < dangerRadius * dangerRadius && distSq > 1) {
                    threatsFound++;
                    const distance = Math.sqrt(distSq);
                    const repulsionStrength = (dangerRadius - distance) / dangerRadius;
                    totalRepulsion.x += (dx / distance) * repulsionStrength;
                    totalRepulsion.y += (dy / distance) * repulsionStrength;
                }
            }

            if (threatsFound > 0) {
                const magnitude = Math.hypot(totalRepulsion.x, totalRepulsion.y);
                if (magnitude > 0.01) {
                    const fleeDistance = 400;
                    const fleeGoal = {
                        x: me.x + (totalRepulsion.x / magnitude) * fleeDistance,
                        y: me.y + (totalRepulsion.y / magnitude) * fleeDistance
                    };
                    return fleeGoal;
                }
            }

            return null;
        }

        findBestPathWithWhiskers(me, goal) {
            const whiskerCount = 6;
            const whiskerAngleSpread = Math.PI / 1.3;
            const whiskerLength = 350;

            const dx = goal.x - me.x;
            const dy = goal.y - me.y;
            const baseAngle = Math.atan2(dy, dx);

            let bestWhisker = null;
            let minGoalDistSq = Infinity;
            const analyzedWhiskers = [];

            for (let i = 0; i < whiskerCount; i++) {
                const angleOffset = (i - Math.floor(whiskerCount / 2)) * (whiskerAngleSpread / (whiskerCount - 1));
                const whiskerAngle = baseAngle + angleOffset;

                const endPoint = {
                    x: me.x + whiskerLength * Math.cos(whiskerAngle),
                    y: me.y + whiskerLength * Math.sin(whiskerAngle)
                };

                const isClear = this.hasLineOfSight(me, endPoint);
                const whiskerData = { start: { ...me }, end: endPoint, isClear, isBest: false };
                analyzedWhiskers.push(whiskerData);

                if (isClear) {
                    const distSq = (endPoint.x - goal.x) ** 2 + (endPoint.y - goal.y) ** 2;
                    if (distSq < minGoalDistSq) {
                        minGoalDistSq = distSq;
                        bestWhisker = whiskerData;
                    }
                }
            }

            this.aiDebugData.whiskers = analyzedWhiskers;

            if (bestWhisker) {
                bestWhisker.isBest = true;
                return bestWhisker.end;
            }

            return goal;
        }

        moveAITowards(me, goal) {
            const adjustedGoal = this.findBestPathWithWhiskers(me, goal);
            this.aiDebugData.finalMoveDirection = { start: {...me}, end: adjustedGoal };

            const distMovedSq = (me.x - this.aiLastPosition.x) ** 2 + (me.y - this.aiLastPosition.y) ** 2;
            if (distMovedSq < 4 && Object.values(this.simulatedKeys).some(k => k)) {
                this.aiStuckCounter++;
            } else {
                this.aiStuckCounter = 0;
            }
            this.aiLastPosition = { x: me.x, y: me.y };

            if (me.colliding) {
                this.aiObstacleAngleOffset += 7.5;
            } else if (this.aiObstacleAngleOffset > 0) {
                this.aiObstacleAngleOffset = Math.max(0, this.aiObstacleAngleOffset - 2.5);
            }

            if (this.aiStuckCounter > 60) {
                this.aiUnstuckCycle = 30;
                this.aiStuckCounter = 0;
                this.aiObstacleAngleOffset = (this.aiObstacleAngleOffset + 90 + Math.random() * 90) % 360;
                modLog("AI: Stuck detected! Initiating unstuck maneuver.");
            }

            let finalGoal = adjustedGoal;
            if (this.aiUnstuckCycle > 0) {
                const reverseDx = me.x - goal.x;
                const reverseDy = me.y - goal.y;
                const reverseDist = Math.hypot(reverseDx, reverseDy);
                if (reverseDist > 1) {
                    finalGoal = {
                        x: me.x + (reverseDx / reverseDist) * 200,
                        y: me.y + (reverseDy / reverseDist) * 200
                    };
                } else {
                    finalGoal = { x: me.x + (Math.random() - 0.5) * 200, y: me.y + (Math.random() - 0.5) * 200 };
                }
                this.aiUnstuckCycle--;
            }

            let dx_move = finalGoal.x - me.x;
            let dy_move = finalGoal.y - me.y;
            if (this.aiObstacleAngleOffset !== 0) {
                const angleRad = this.aiObstacleAngleOffset * (Math.PI / 180);
                const cosA = Math.cos(angleRad);
                const sinA = Math.sin(angleRad);
                const newDx = dx_move * cosA - dy_move * sinA;
                const newDy = dx_move * sinA + dy_move * cosA;
                dx_move = newDx;
                dy_move = newDy;
            }

            const { maxSpeed, ACCELERATION, FRICTION } = this.getBotPhysics(me);
            const distance = Math.hypot(dx_move, dy_move);
            let desiredSpdX = 0;
            let desiredSpdY = 0;

            const stopDistance = this.multibox.isChild ? 50 : 15;

            if (distance > stopDistance) {
                const brakingFactor = 12.0;
                const desiredSpeed = Math.min(maxSpeed, distance / brakingFactor);
                desiredSpdX = (dx_move / distance) * desiredSpeed;
                desiredSpdY = (dy_move / distance) * desiredSpeed;
            }

            const requiredAccelX = (desiredSpdX / FRICTION) - this.botSpdX;
            const requiredAccelY = (desiredSpdY / FRICTION) - this.botSpdY;

            let keysToPress = [];
            let isPressingKeyX = 0;
            let isPressingKeyY = 0;
            const keyPressThreshold = ACCELERATION * 0.1;
            if (requiredAccelX > keyPressThreshold) {
                keysToPress.push('d');
                isPressingKeyX = 1;
            }
            else if (requiredAccelX < -keyPressThreshold) {
                keysToPress.push('a');
                isPressingKeyX = -1;
            }
            if (requiredAccelY > keyPressThreshold) {
                keysToPress.push('s');
                isPressingKeyY = 1;
            }
            else if (requiredAccelY < -keyPressThreshold) {
                keysToPress.push('w');
                isPressingKeyY = -1;
            }

            this.updateSimulatedKeys(keysToPress);

            let appliedAccelX = isPressingKeyX * ACCELERATION;
            let appliedAccelY = isPressingKeyY * ACCELERATION;
            if (isPressingKeyX !== 0 && isPressingKeyY !== 0) {
                appliedAccelX *= GatsModCore.PLAYER_SPEEDS.diagonalCorrection;
                appliedAccelY *= GatsModCore.PLAYER_SPEEDS.diagonalCorrection;
            }
            this.botSpdX = (this.botSpdX + appliedAccelX) * FRICTION;
            this.botSpdY = (this.botSpdY + appliedAccelY) * FRICTION;
            const currentSimulatedSpeed = Math.hypot(this.botSpdX, this.botSpdY);
            if (currentSimulatedSpeed > maxSpeed) {
                const ratio = maxSpeed / currentSimulatedSpeed;
                this.botSpdX *= ratio;
                this.botSpdY *= ratio;
            }
        }

        useParkAbility(me) {
            const now = performance.now();
            if (now - this.aiLastParkUse > 1000) {
                this.aiLastParkUse = now;
                this._fireKeyEvent('keydown', ' ');
                setTimeout(() => this._fireKeyEvent('keyup', ' '), 50);
            }
        }

        handleSituationalAITalk(me, nearestEnemy, aiMode) {
            const now = performance.now();
            if (now - this.aiLastChatTime < 1000) return;

            let chatCandidates = [];
            let saySomething = false;

            if (this.multibox.isChild) {
                aiMode = 'idle';
            }

            switch (aiMode) {
                case 'attacking':
                    if (nearestEnemy) chatCandidates = GatsModCore.AI_CHAT_SITUATIONAL.attacking(nearestEnemy.username);
                    saySomething = Math.random() < 0.1;
                    break;
                case 'fleeing_explosive':
                    chatCandidates = GatsModCore.AI_CHAT_SITUATIONAL.fleeing_explosive();
                    saySomething = Math.random() < 0.5;
                    break;
                case 'dodging':
                case 'pre_dodging':
                    chatCandidates = GatsModCore.AI_CHAT_SITUATIONAL.dodging();
                    saySomething = Math.random() < 0.25;
                    break;
                case 'retreating':
                    chatCandidates = GatsModCore.AI_CHAT_SITUATIONAL.retreating();
                    saySomething = Math.random() < 0.25;
                    break;
                case 'distancing':
                    chatCandidates = GatsModCore.AI_CHAT_SITUATIONAL.distancing();
                    saySomething = Math.random() < 0.20;
                    break;
                case 'kiting':
                    chatCandidates = GatsModCore.AI_CHAT_SITUATIONAL.kiting();
                    saySomething = Math.random() < 0.20;
                    break;
                case 'idle':
                case 'patrolling':
                case 'returning_to_bounds':
                case 'following_parent':
                    chatCandidates = GatsModCore.AI_CHAT_SITUATIONAL.idle();
                    saySomething = Math.random() < 0.02;
                    break;
            }

            if (saySomething && chatCandidates.length > 0) {
                const message = chatCandidates[Math.floor(Math.random() * chatCandidates.length)];
                GatsModCore.sendChatMessage(message);
                this.aiLastChatTime = now;
            }
        }

        handleIncomingChatMessage(message) {
            if (this.multibox.isChild) return;
            const now = performance.now();
            if (now - this.aiLastChatTime < 1000) return;

            const words = message.split(' ');
            for (const word of words) {
                if (GatsModCore.AI_CHAT_RESPONSES[word]) {
                    const responses = GatsModCore.AI_CHAT_RESPONSES[word];
                    const response = responses[Math.floor(Math.random() * responses.length)];
                    GatsModCore.sendChatMessage(response);
                    this.aiLastChatTime = now;
                    return;
                }
            }
        }
    }

    let gatsModInstance = null;
    let game_original_updateMouseData_ref = null;
    let modInitializationAttempted = false;

    const gatsModLauncherInterval = setInterval(() => {
        if (modInitializationAttempted) {
            clearInterval(gatsModLauncherInterval);
            return;
        }

        if (
            typeof updateMouseData === 'function' &&
            typeof Player !== 'undefined' && Player.pool &&
            typeof Connection !== 'undefined' && Connection.list?.[0]?.socket &&
            typeof prepareMessage === 'function' &&
            typeof camera === 'object' && camera?.ctx &&
            typeof selfId !== 'undefined' &&
            document.getElementById('canvas')
        ) {
            modLog(`[Launcher] Game ready. Initializing mod.`);
            clearInterval(gatsModLauncherInterval);
            modInitializationAttempted = true;

            game_original_updateMouseData_ref = updateMouseData;

            updateMouseData = function(eventData) {
                if (!gatsModInstance) {
                    try {
                        gatsModInstance = new GatsModCore();
                        gatsModInstance.originalUpdateMouseData = game_original_updateMouseData_ref;

                        const original_clearRect = CanvasRenderingContext2D.prototype.clearRect;
                        CanvasRenderingContext2D.prototype.clearRect = function(...args) {
                            original_clearRect.apply(this, args);
                            if (gatsModInstance && this.canvas.id === 'canvas' && Player.pool?.[selfId]?.activated) {
                                try {
                                    gatsModInstance.mainGameTick();
                                } catch (e) {
                                    modLog(`mainGameTick error: ${e.stack}`, true);
                                }
                            }
                        };
                        modLog(`[Launcher] clearRect hooked for game tick.`);
                    } catch (e) {
                        modLog(`[Launcher] GatsModCore instantiation failed: ${e.stack}`, true);
                        updateMouseData = game_original_updateMouseData_ref;
                        return;
                    }
                }

                if (gatsModInstance?.isExclusionModeActive) {
                    return;
                }

                if (GatsModCore.SETTINGS.zeroAIEnabled) {
                    return;
                }

                return game_original_updateMouseData_ref.call(this, eventData);
            };

            modLog(`[Launcher] updateMouseData wrapped. Mod will fully initialize on first mouse event.`);
        }
    }, 250);

    setTimeout(() => {
        if (!modInitializationAttempted) {
            modLog(`[Launcher] Timeout: Game did not initialize required components. Mod will not start.`, true);
            clearInterval(gatsModLauncherInterval);
        }
    }, 20000);

})();


(function() {
    'use strict';

    window.addEventListener ("load", onload);

    function onload() {
        let processMessageTmp = processMessage;
        processMessage = function(event) {
            processMessageTmp(event);
            let decoded = new TextDecoder().decode(event.data);
            if (!decoded.includes("a,")) return;
            camera.update = function() {
                let player = Player.pool[selfId];
                if (camera.trackingId) {
                    camera.x = player.x - hudXPosition;
                    camera.y = player.y - hudYPosition;
                }
            }
        }
    }
})();
(function() {
'use strict';


const config = {
    themes: {
        cyberpunk: {
            mainBg: 'rgba(10, 10, 15, 0.9)', secondaryBg: 'rgba(25, 25, 30, 0.95)', accent: '#00ffff', accentHover: '#7fffff',
            accentBorder: '#00cccc', glow: 'rgba(0, 255, 255, 0.6)', textLight: '#e0e0e0', textDim: '#999',
            btnSuccessBg: '#008080', btnSuccessBorder: '#006666', canvasBg: '#F5F5F5', gridBorder: 'rgba(0, 0, 0, 0.1)',
            bulletCore: '#00ffff', bulletGlow: 'rgba(0, 255, 255, 0.8)', bulletTrail: 'rgba(0, 255, 255, 0.3)',
            playerHp: '#ff3366', playerArmor: '#3399ff', playerScore: '#ffcc00', hudBg: 'rgba(18, 18, 22, 0.8)',
            hudBorder: 'rgba(0, 255, 255, 0.4)', deathOverlay: 'rgba(180, 0, 0, 0.4)', damageFlash: 'rgba(255, 0, 50, 0.6)',
            teamRed: 'rgba(255, 51, 102, 0.8)', teamBlue: 'rgba(51, 153, 255, 0.8)', selfHighlight: '#FFFFFF',
            espSafe: 'rgba(255, 255, 255, 0.6)', espWarning: 'rgba(255, 204, 0, 0.8)', espDanger: 'rgba(255, 51, 102, 0.9)',
            notificationBg: 'rgba(25, 25, 30, 0.9)', notificationText: '#e0e0e0', notificationStroke: 'rgba(0, 0, 0, 0.9)',
            crateBody: '#4a4a5a', crateLid: '#3a3a4a', userCrateBody: '#4a4a5a', userCrateLid: '#00ffff',
            playerAttachedHp: '#ff3366', playerAttachedArmor: '#333333', playerAttachedReload: '#ffcc00',
            playerAttachedSkill: '#00ffff', playerAttachedBg: 'rgba(0, 0, 0, 0.3)',
            shootingReady: 'rgba(0, 255, 127, 0.8)', shootingCooldown: 'rgba(255, 140, 0, 0.8)',
        },
        military: {
            mainBg: 'rgba(45, 52, 45, 0.9)', secondaryBg: 'rgba(60, 70, 60, 0.95)', accent: '#ff9900', accentHover: '#ffb84d',
            accentBorder: '#cc7a00', glow: 'rgba(255, 153, 0, 0.6)', textLight: '#d0d0c0', textDim: '#a0a090',
            btnSuccessBg: '#556B2F', btnSuccessBorder: '#445625', canvasBg: '#E0E0D5', gridBorder: 'rgba(0, 0, 0, 0.1)',
            bulletCore: '#ff9900', bulletGlow: 'rgba(255, 153, 0, 0.8)', bulletTrail: 'rgba(255, 153, 0, 0.3)',
            playerHp: '#d9534f', playerArmor: '#5bc0de', playerScore: '#f0ad4e', hudBg: 'rgba(30, 35, 30, 0.8)',
            hudBorder: 'rgba(255, 153, 0, 0.4)', deathOverlay: 'rgba(180, 0, 0, 0.4)', damageFlash: 'rgba(255, 80, 80, 0.6)',
            teamRed: 'rgba(217, 83, 79, 0.8)', teamBlue: 'rgba(91, 192, 222, 0.8)', selfHighlight: '#FFFFFF',
            espSafe: 'rgba(255, 255, 255, 0.6)', espWarning: 'rgba(240, 173, 78, 0.8)', espDanger: 'rgba(217, 83, 79, 0.9)',
            notificationBg: 'rgba(60, 70, 60, 0.9)', notificationText: '#d0d0c0', notificationStroke: 'rgba(0, 0, 0, 0.9)',
            crateBody: '#5a5a4a', crateLid: '#4a4a3a', userCrateBody: '#5a5a4a', userCrateLid: '#ff9900',
            playerAttachedHp: '#d9534f', playerAttachedArmor: '#333333', playerAttachedReload: '#f0ad4e',
            playerAttachedSkill: '#ff9900', playerAttachedBg: 'rgba(0, 0, 0, 0.3)',
            shootingReady: 'rgba(92, 184, 92, 0.8)', shootingCooldown: 'rgba(240, 173, 78, 0.8)',
        },
        retro: {
            mainBg: 'rgba(50, 20, 80, 0.9)', secondaryBg: 'rgba(70, 40, 100, 0.95)', accent: '#ff00ff', accentHover: '#ff66ff',
            accentBorder: '#cc00cc', glow: 'rgba(255, 0, 255, 0.6)', textLight: '#00ff00', textDim: '#00cc00',
            btnSuccessBg: '#008080', btnSuccessBorder: '#006666', canvasBg: '#000000', gridBorder: 'rgba(0, 255, 0, 0.1)',
            bulletCore: '#ff00ff', bulletGlow: 'rgba(255, 0, 255, 0.8)', bulletTrail: 'rgba(255, 0, 255, 0.3)',
            playerHp: '#ff3366', playerArmor: '#00ffff', playerScore: '#ffff00', hudBg: 'rgba(20, 0, 40, 0.8)',
            hudBorder: 'rgba(255, 0, 255, 0.4)', deathOverlay: 'rgba(180, 0, 0, 0.4)', damageFlash: 'rgba(255, 0, 80, 0.6)',
            teamRed: 'rgba(255, 51, 102, 0.8)', teamBlue: 'rgba(0, 255, 255, 0.8)', selfHighlight: '#FFFFFF',
            espSafe: 'rgba(0, 255, 0, 0.6)', espWarning: 'rgba(255, 255, 0, 0.8)', espDanger: 'rgba(255, 0, 255, 0.9)',
            notificationBg: 'rgba(70, 40, 100, 0.9)', notificationText: '#00ff00', notificationStroke: 'rgba(0, 0, 0, 0.9)',
            crateBody: '#3a3a4a', crateLid: '#2a2a3a', userCrateBody: '#3a3a4a', userCrateLid: '#ff00ff',
            playerAttachedHp: '#ff3366', playerAttachedArmor: '#333333', playerAttachedReload: '#ffff00',
            playerAttachedSkill: '#ff00ff', playerAttachedBg: 'rgba(0, 0, 0, 0.3)',
            shootingReady: 'rgba(0, 255, 0, 0.8)', shootingCooldown: 'rgba(255, 255, 0, 0.8)',
        },
        darkMode: {
            mainBg: 'rgba(18, 18, 18, 0.9)', secondaryBg: 'rgba(33, 33, 33, 0.95)', accent: '#bb86fc', accentHover: '#d0b3ff',
            accentBorder: '#985eff', glow: 'rgba(187, 134, 252, 0.4)', textLight: '#e0e0e0', textDim: '#b0b0b0',
            btnSuccessBg: '#03dac6', btnSuccessBorder: '#018786', canvasBg: '#121212', gridBorder: 'rgba(255, 255, 255, 0.1)',
            bulletCore: '#bb86fc', bulletGlow: 'rgba(187, 134, 252, 0.8)', bulletTrail: 'rgba(187, 134, 252, 0.3)',
            playerHp: '#cf6679', playerArmor: '#03dac6', playerScore: '#f0ad4e', hudBg: 'rgba(28, 28, 28, 0.8)',
            hudBorder: 'rgba(187, 134, 252, 0.4)', deathOverlay: 'rgba(180, 0, 0, 0.4)', damageFlash: 'rgba(255, 80, 80, 0.6)',
            teamRed: 'rgba(207, 102, 121, 0.8)', teamBlue: 'rgba(3, 218, 198, 0.8)', selfHighlight: '#FFFFFF',
            espSafe: 'rgba(255, 255, 255, 0.6)', espWarning: 'rgba(240, 173, 78, 0.8)', espDanger: 'rgba(207, 102, 121, 0.9)',
            notificationBg: 'rgba(33, 33, 33, 0.9)', notificationText: '#e0e0e0', notificationStroke: 'rgba(0, 0, 0, 0.9)',
            crateBody: '#4a4a5a', crateLid: '#3a3a4a', userCrateBody: '#4a4a5a', userCrateLid: '#bb86fc',
            playerAttachedHp: '#cf6679', playerAttachedArmor: '#333333', playerAttachedReload: '#f0ad4e',
            playerAttachedSkill: '#bb86fc', playerAttachedBg: 'rgba(0, 0, 0, 0.3)',
            shootingReady: 'rgba(3, 218, 198, 0.8)', shootingCooldown: 'rgba(240, 173, 78, 0.8)',
        }
    },
    activeTheme: 'cyberpunk',
    animations: { transitionSpeed: '0.2s', easing: 'ease-out' },
    perkGUI: { enabled: true },
    esp: { enabled: true },
    notifications: { enabled: true, maxDisplay: 4, displayTime: 4000 },
    autoPerk: { enabled: true, settings: { tier1: null, tier2: null, tier3: null } },
    autoRespawn: { enabled: true},
    chatLog: { enabled: true, maxEntries: 50 }
};


const zoomState = {
    level: 1.0,
    min: 0.3,
    max: 2.5,
    step: 0.1
};


function handleMouseWheel(e) {

    if (!unsafeWindow.inGame || unsafeWindow.spectating || ['INPUT', 'SELECT', 'TEXTAREA'].includes(document.activeElement.tagName)) {
        return;
    }
    e.preventDefault();


    if (e.deltaY < 0) { 
        zoomState.level = Math.min(zoomState.max, zoomState.level + zoomState.step);
    } else { 
        zoomState.level = Math.max(zoomState.min, zoomState.level - zoomState.step);
    }

    if (typeof unsafeWindow.resizeCanvas === 'function') {
        unsafeWindow.resizeCanvas();
    }
}


const themeStyles = `
    :root {
        --main-bg: ${config.themes.cyberpunk.mainBg}; --secondary-bg: ${config.themes.cyberpunk.secondaryBg};
        --accent-color: ${config.themes.cyberpunk.accent}; --accent-hover: ${config.themes.cyberpunk.accentHover};
        --accent-border: ${config.themes.cyberpunk.accentBorder}; --glow-color: ${config.themes.cyberpunk.glow};
        --text-color-light: ${config.themes.cyberpunk.textLight}; --text-color-dim: ${config.themes.cyberpunk.textDim};
        --btn-success-bg: ${config.themes.cyberpunk.btnSuccessBg}; --btn-success-border: ${config.themes.cyberpunk.btnSuccessBorder};
        --font-family: 'Roboto', 'Segoe UI', sans-serif; --transition-speed: ${config.animations.transitionSpeed}; --easing: ${config.animations.easing};
    }
    /* --- 変更点 ---
    body {
        background-color: #0a0a0f !important; font-family: var(--font-family);
        background-image:
            radial-gradient(circle at 1px 1px, rgba(0, 255, 255, 0.15) 1px, transparent 0),
            radial-gradient(circle at 25px 25px, rgba(0, 255, 255, 0.05) 1px, transparent 0);
        background-size: 50px 50px;
    }
    --- ここまで --- */
    ::selection { background: var(--accent-color); color: #000; }
    #cover { background-color: #101010; }
    #loading {
        font-family: var(--font-family); font-weight: 700;
        text-shadow: 0 0 20px var(--glow-color);
        animation: loading-pulse 1.5s infinite ease-in-out;
    }
    @keyframes loading-pulse {
        0%, 100% { color: var(--text-color-light); transform: scale(1); }
        50% { color: var(--accent-color); transform: scale(1.05); }
    }
    #slct, .modal-content { animation: fade-in-up 0.4s var(--easing) forwards; }
    @keyframes fade-in-up { from { opacity: 0; transform: translateY(15px); } to { opacity: 1; transform: translateY(0); } }
    #slct {
        background: var(--main-bg);
        border: 1px solid var(--accent-border); border-radius: 10px;
        box-shadow: 0 0 30px rgba(0, 255, 255, 0.2); color: var(--text-color-light);
        padding: 25px;
    }
    .selection-title {
        background-color: transparent !important; color: var(--accent-color);
        text-shadow: 0 0 8px var(--glow-color); font-size: 18px; font-weight: bold;
        border-bottom: 1px solid var(--accent-border); padding-bottom: 8px;
        margin-bottom: 15px; text-align: left; width: 100% !important;
    }
    .weaponSelector, .colorSelector, .armorSelector {
        background-color: var(--secondary-bg) !important; border: 1px solid #444;
        border-radius: 8px; transition: all var(--transition-speed) var(--easing);
        position: relative; overflow: hidden;
    }
    .weaponSelector:hover, .colorSelector:hover, .armorSelector:hover {
        border-color: var(--accent-color); transform: translateY(-2px);
        box-shadow: 0 4px 12px rgba(0,0,0,0.4);
    }
    .selected-box {
        border: 2px solid var(--accent-color) !important;
        box-shadow: 0 0 12px var(--glow-color), inset 0 0 10px rgba(0, 255, 255, 0.15);
        transform: translateY(-2px);
    }
    #playButton, #serversBtn, #gametypeDropdown, #reconnectButton {
        border-radius: 6px !important; border-width: 1px !important; border-style: solid !important;
        transition: all var(--transition-speed) var(--easing); text-shadow: 0 0 5px rgba(0,0,0,0.5);
        color: var(--text-color-light) !important; font-family: var(--font-family); font-weight: 700;
    }
    #playButton { background: var(--accent-color) !important; border-color: var(--accent-border) !important; box-shadow: 0 0 15px var(--glow-color); color: #000 !important; }
    #playButton:hover { transform: scale(1.05); box-shadow: 0 0 30px var(--glow-color); filter: brightness(1.1); }
    #serversBtn, #gametypeDropdown { background-color: var(--secondary-bg) !important; border-color: #555 !important; }
    #serversBtn:hover, #gametypeDropdown:hover { border-color: var(--accent-color) !important; }
    .modal-content {
        background: #111 !important; color: var(--text-color-light);
        border: 1px solid var(--accent-border) !important; border-radius: 10px !important;
        box-shadow: 0 0 35px rgba(0, 255, 255, 0.25);
    }
    .modal-header { border-bottom: 1px solid var(--accent-border); padding: 15px 20px;}
    .modal-title { color: var(--accent-color); font-weight: bold; text-shadow: 0 0 5px var(--glow-color); }
    .modal-header .close { color: var(--text-color-light); opacity: 0.7; text-shadow: none; transition: all 0.2s; }
    .modal-header .close:hover { color: var(--accent-color); opacity: 1; transform: rotate(90deg) scale(1.2); }
    .form-control {
        background-color: #1a1a1a !important; border: 1px solid #444 !important;
        color: var(--text-color-light) !important; border-radius: 4px !important;
        transition: all var(--transition-speed) var(--easing);
    }
    .form-control:focus { border-color: var(--accent-color) !important; box-shadow: 0 0 8px var(--glow-color); }
    .btn-success { background-color: var(--btn-success-bg); border-color: var(--btn-success-border); }
    .btn-success:hover { filter: brightness(1.2); }
    .ad-group, #detect, .ads.ad.adsbox, #adHome { display: none !important; }

    #serverModal .modal-content { background-color: var(--secondary-bg) !important; }
    #serverModal .modal-body { padding: 0; }
    #serverModal .nav-tabs {
        background-color: rgba(10, 10, 15, 0.8);
        border-bottom: 1px solid var(--accent-border);
        padding: 10px 10px 0 10px;
    }
    #serverModal .nav-tabs > li > a {
        color: var(--text-color-dim); border-radius: 6px 6px 0 0 !important;
        border: 1px solid transparent !important; margin-right: 5px;
        background-color: rgba(40, 40, 45, 0.8) !important;
        transition: var(--transition-speed) var(--easing);
    }
    #serverModal .nav-tabs > li > a:hover { background-color: rgba(55, 55, 60, 0.9) !important; color: var(--text-color-light); }
    #serverModal .nav-tabs > li.active > a,
    #serverModal .nav-tabs > li.active > a:hover,
    #serverModal .nav-tabs > li.active > a:focus {
        background-color: var(--secondary-bg) !important; color: var(--accent-color) !important;
        border: 1px solid var(--accent-border) !important; border-bottom-color: transparent !important;
        font-weight: bold;
    }
    #serverModal .table-responsive { border: none; }
    #serverModal .table { background-color: transparent; color: var(--text-color-light); margin-bottom: 0; }
    #serverModal .table > thead > tr > th {
        background-color: rgba(10, 10, 15, 0.5); color: var(--text-color-light);
        border-bottom: 2px solid var(--accent-border); text-align: left; padding: 12px;
    }
    #serverModal .table > tbody > tr {
        background-color: transparent;
        border-bottom: 1px solid rgba(0, 255, 255, 0.1);
        transition: background-color var(--transition-speed) var(--easing);
    }
    #serverModal .table > tbody > tr:last-child { border-bottom: none; }
    #serverModal .table > tbody > tr:hover { background-color: rgba(0, 255, 255, 0.08); }
    #serverModal .table > tbody > tr > td {
        border-top: none; vertical-align: middle; padding: 12px;
        color: var(--text-color-dim);
    }
    #serverModal .table > tbody > tr > td:first-child { color: var(--text-color-light); font-weight: 500; }
    #serverModal .table > tbody > tr > td:nth-child(2) { color: var(--text-color-light); }
    #serverModal .table > tbody > tr > td .btn-success {
        background-color: transparent !important;
        border: 1px solid var(--accent-color) !important;
        color: var(--accent-color) !important;
        font-weight: bold; padding: 6px 14px; border-radius: 5px;
        transition: all var(--transition-speed) var(--easing);
    }
    #serverModal .table > tbody > tr > td .btn-success:hover {
        background-color: var(--accent-color) !important;
        color: #000 !important;
        box-shadow: 0 0 10px var(--glow-color);
    }
    #serverModal .table > tbody > tr > td .btn-success[disabled] {
         background-color: transparent !important; border-color: #555 !important;
         color: #555 !important; opacity: 0.6; cursor: not-allowed;
    }
    #discord-link-btn {
        display: block; text-align: center;
        margin-top: 15px; padding: 10px;
        background-color: var(--secondary-bg);
        color: var(--text-color-dim);
        text-decoration: none; border-radius: 6px;
        border: 1px solid #555;
        font-weight: 500; font-size: 13px;
        transition: all var(--transition-speed) var(--easing);
    }
    #discord-link-btn:hover {
        color: var(--accent-color);
        border-color: var(--accent-color);
        background-color: rgba(0, 255, 255, 0.1);
    }
    /* --- MODIFIED NOTIFICATION STYLES --- */
    #notification-container {
        position: fixed;
        top: 80px;
        left: 190px; /* Changed from 'right: 20px' */
        display: flex;
        flex-direction: column;
        gap: 10px;
        z-index: 2000;
        pointer-events: none;
    }
    .notification {
        background: var(--notification-bg, rgba(25, 25, 30, 0.9));
        color: var(--notification-text, #e0e0e0);
        padding: 12px 18px;
        border-radius: 6px;
        border-left: 4px solid var(--accent-color);
        box-shadow: 0 3px 10px rgba(0,0,0,0.5);
        font-size: 14px;
        font-weight: 500;
        animation: slide-in-from-left 0.4s ease-out, fade-out 0.4s ease-in ${config.notifications.displayTime / 1000}s forwards; /* Changed animation name */
    }
    /* --- MODIFIED KEYFRAMES --- */
    @keyframes slide-in-from-left { from { transform: translateX(-100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
    @keyframes fade-out { from { opacity: 1; } to { opacity: 0; transform: translateY(-10px); } }

    #auto-perk-container { margin-bottom: 20px; }
    .auto-perk-slots { display: flex; justify-content: space-around; gap: 10px; }
    .perk-slot {
        width: 65px; height: 65px;
        background-color: var(--secondary-bg); border: 1px solid #444;
        border-radius: 8px; cursor: pointer;
        transition: all var(--transition-speed) var(--easing);
        display: flex; align-items: center; justify-content: center;
        font-size: 24px; font-weight: bold; color: var(--text-color-dim);
        background-size: 85%; background-position: center; background-repeat: no-repeat;
    }
    .perk-slot:hover {
        border-color: var(--accent-color); transform: translateY(-2px);
        box-shadow: 0 4px 12px rgba(0,0,0,0.4);
    }

    /* --- Modified Utility Section Styles --- */
    .utility-options-wrapper {
        display: flex;
        gap: 15px;
        align-items: stretch; /* Make items equal height */
    }
    .utility-option {
        display: flex; align-items: center; justify-content: center;
        cursor: pointer; background-color: var(--secondary-bg);
        border: 1px solid #444; border-radius: 8px; padding: 12px;
        transition: all var(--transition-speed) var(--easing);
        user-select: none; flex: 1;
    }
    .utility-option:hover { border-color: var(--accent-color); }
    .utility-option input[type="checkbox"] {
        margin-right: 12px; transform: scale(1.3);
        cursor: pointer; accent-color: var(--accent-color);
    }
    .utility-option span, .utility-label {
        color: var(--text-color-light); font-weight: 500; font-size: 14px;
    }
    .utility-option-group {
        display: flex; flex-direction: column; flex: 1;
        background-color: var(--secondary-bg); border: 1px solid #444;
        border-radius: 8px; padding: 8px 12px;
        transition: all var(--transition-speed) var(--easing);
    }
    .utility-option-group:hover { border-color: var(--accent-border); }
    .utility-label { margin-bottom: 6px; }
    .utility-option-group .form-control { width: 100%; flex-grow: 1; }

    #perk-selection-modal {
        position: fixed; top: 0; left: 0; width: 100%; height: 100%;
        background: rgba(0,0,0,0.7); display: flex;
        align-items: center; justify-content: center; z-index: 2001;
    }
    #perk-selection-modal .modal-content {
        background: var(--secondary-bg) !important; padding: 20px;
        border-radius: 10px; border: 1px solid var(--accent-border);
        max-width: 500px;
    }
    #perk-selection-modal h3 {
        color: var(--accent-color); margin-top: 0; text-align: center;
        border-bottom: 1px solid var(--accent-border); padding-bottom: 10px;
    }
    .perk-grid {
        display: grid; grid-template-columns: repeat(auto-fill, minmax(65px, 1fr));
        gap: 10px; margin-top: 15px;
    }
    .perk-icon-modal {
        width: 65px; height: 65px;
        background-color: #1a1a1a; border: 1px solid #444;
        border-radius: 6px; cursor: pointer;
        transition: all 0.2s ease;
        background-size: 85%; background-position: center; background-repeat: no-repeat;
        display: flex; align-items: center; justify-content: center;
        font-weight: bold; color: var(--text-color-dim);
    }
    .perk-icon-modal:hover { border-color: var(--accent-color); transform: scale(1.1); }
    #chat-log-container {
        position: fixed; left: 0; top: 50%;
        transform: translateY(-50%); z-index: 1500;
        display: flex; align-items: center;
        transition: all var(--transition-speed) var(--easing);
    }
    #chat-log-handle {
        width: 25px; height: 120px;
        background-color: var(--secondary-bg);
        border: 1px solid var(--accent-border);
        border-left: none; border-radius: 0 8px 8px 0;
        cursor: pointer; display: flex;
        align-items: center; justify-content: center;
        writing-mode: vertical-rl; text-orientation: mixed;
        color: var(--accent-color); font-weight: bold;
        font-size: 14px; letter-spacing: 2px;
        text-shadow: 0 0 5px var(--glow-color);
    }
    #chat-log-content {
        width: 0; max-width: 0;
        height: 400px;
        background-color: var(--secondary-bg);
        border: 1px solid var(--accent-border);
        border-left: none; border-radius: 0 8px 8px 0;
        overflow: hidden;
        transition: all var(--transition-speed) var(--easing);
        display: flex; flex-direction: column;
    }
    #chat-log-container:hover #chat-log-content {
        width: 350px; max-width: 350px;
        padding: 10px; overflow-y: auto;
    }
    .chat-log-entry {
        margin-bottom: 5px; line-height: 1.4;
        font-size: 13px; word-break: break-word;
        color: var(--text-color-light);
    }
    .chat-log-player-name { font-weight: bold; }
    #chat-log-content::-webkit-scrollbar { width: 8px; }
    #chat-log-content::-webkit-scrollbar-track { background: #1a1a1a; }
    #chat-log-content::-webkit-scrollbar-thumb { background: var(--accent-color); border-radius: 4px; }
    #chat-log-content::-webkit-scrollbar-thumb:hover { background: var(--accent-hover); }

    /* --- Modified Stats Display (FPS/Ping) Style --- */
    #stats-display-container {
        position: fixed;
        top: 40px; /* Positioned above the minimap */
        left: 20px; /* Aligned with the minimap */
        width: 150px; /* Matches minimap width */
        background: var(--secondary-bg);
        color: var(--text-color-light);
        padding: 6px 10px;
        border-radius: 5px;
        border: 1px solid var(--accent-border);
        font-family: var(--font-family);
        font-size: 12px;
        font-weight: 500;
        z-index: 1500;
        display: flex;
        justify-content: space-between;
        align-items: center;
        opacity: 0.85;
        box-sizing: border-box;
    }

    /* --- Main Selection Tabs --- */
    .main-tabs-container {
        display: flex;
        border-bottom: 1px solid var(--accent-border);
        margin: -15px -15px 20px -15px; /* Adjust margins to align with padding */
        padding: 0 15px;
    }
    .main-tab-btn {
        padding: 10px 20px;
        cursor: pointer;
        color: var(--text-color-dim);
        font-weight: 500;
        font-size: 16px;
        border: none;
        background: transparent;
        transition: all var(--transition-speed) var(--easing);
        border-bottom: 3px solid transparent;
        position: relative;
        top: 1px;
    }
    .main-tab-btn:hover {
        color: var(--text-color-light);
    }
    .main-tab-btn.active {
        color: var(--accent-color);
        font-weight: bold;
        border-bottom-color: var(--accent-color);
    }
    .main-tab-content {
        display: none;
        animation: fade-in-up 0.3s var(--easing) forwards;
    }
    .main-tab-content.active {
        display: block;
    }
    #utility-tab-content {
        display: none;
        flex-direction: column;
        gap: 25px;
    }
    #utility-tab-content.active {
        display: flex;
    }
`;
GM_addStyle(themeStyles);


const customUI = {
    animatedHud: { hp: 0, armor: 0, score: 0, isInitialized: false },
    lastHp: 100,
    hpDropTime: 0,
    deathFade: 0,
    damageFlashAlpha: 0,

    drawTopStatusBar: function(ctx, player) {
        if (!player) return;

        const hudX = unsafeWindow.hudXPosition;
        const barY = 15, barH = 30, padding = 15;

        const username = unsafeWindow.selfUsername || "Player";
        const kills = player.kills !== undefined ? player.kills : 0;
        const score = Math.round(this.animatedHud.score);

        const statusText = `${username}  |  Kills: ${kills}  |  Score: ${score}`;

        ctx.save();
        ctx.font = `bold 16px ${config.fontFamily}`;
        const textWidth = ctx.measureText(statusText).width;
        const barW = textWidth + padding * 2;
        const barX = hudX - barW / 2;

        ctx.globalAlpha = 0.85;
        ctx.fillStyle = config.themes[config.activeTheme].hudBg;
        ctx.strokeStyle = config.themes[config.activeTheme].hudBorder;
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.roundRect(barX, barY, barW, barH, 5);
        ctx.fill();
        ctx.stroke();

        ctx.globalAlpha = 1.0;
        ctx.fillStyle = config.themes[config.activeTheme].textLight;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.shadowColor = 'black';
        ctx.shadowBlur = 4;
        ctx.fillText(statusText, hudX, barY + barH / 2);

        ctx.restore();
    },

    drawHealthArmor: function(ctx, player) {
        const hudY = unsafeWindow.hudYPosition;
        ctx.save();
        const barX = 15, barY = hudY * 2 - 65, barW = 250, barH = 18, barSpacing = 5;

        ctx.globalAlpha = 0.85;
        ctx.fillStyle = config.themes[config.activeTheme].hudBg;
        ctx.strokeStyle = config.themes[config.activeTheme].hudBorder;
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.roundRect(barX - 4, barY - barH - barSpacing - 4, barW + 8, barH * 2 + barSpacing + 8, 5);
        ctx.fill();
        ctx.stroke();

        ctx.fillStyle = '#300'; ctx.fillRect(barX, barY - barH - barSpacing, barW, barH);
        ctx.fillStyle = config.themes[config.activeTheme].playerHp; ctx.fillRect(barX, barY - barH - barSpacing, barW * (this.animatedHud.hp / 100), barH);

        if (this.lastHp > player.hp) {
            this.hpDropTime = Date.now();
            this.damageFlashAlpha = 1.0;
        }
        this.lastHp = player.hp;

        const hpFlashDuration = 300;
        if (Date.now() - this.hpDropTime < hpFlashDuration) {
            const flashAlpha = 1 - (Date.now() - this.hpDropTime) / hpFlashDuration;
            ctx.fillStyle = `rgba(255, 255, 255, ${flashAlpha * 0.7})`;
            ctx.fillRect(barX, barY - barH - barSpacing, barW, barH);
        }

        ctx.fillStyle = '#002233'; ctx.fillRect(barX, barY, barW, barH);
        ctx.fillStyle = config.themes[config.activeTheme].playerArmor; ctx.fillRect(barX, barY, barW * (this.animatedHud.armor / 110), barH);

        ctx.globalAlpha = 1.0;
        ctx.fillStyle = config.themes[config.activeTheme].textLight;
        ctx.font = `bold 12px ${config.fontFamily}`;
        ctx.shadowColor = 'black';
        ctx.shadowBlur = 3;
        ctx.fillText(`HP: ${player.hp}`, barX + 5, barY - barSpacing - 5);
        ctx.fillText(`Armor: ${player.armorAmount}`, barX + 5, barY + 13);
        ctx.shadowBlur = 0;
        ctx.restore();
    },

    drawScore: function(ctx, player) {
        const hudX = unsafeWindow.hudXPosition;
        const hudY = unsafeWindow.hudYPosition;
        const scoreLevels = {0: [0, 100], 1: [100, 300], 2: [300, 600], 3: [600, 600]};
        const level = unsafeWindow.playerLevel;
        const scoreProgress = (level < 4) ? (100 / (scoreLevels[level][1] - scoreLevels[level][0]) * (this.animatedHud.score - scoreLevels[level][0])) : 100;

        ctx.save();
        const scoreX = hudX - 250, scoreY = hudY * 2 - 35, scoreW = 500, scoreH = 20;
        ctx.globalAlpha = 0.85;
        ctx.fillStyle = config.themes[config.activeTheme].hudBg;
        ctx.strokeStyle = config.themes[config.activeTheme].hudBorder;
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.roundRect(scoreX - 2, scoreY - 2, scoreW + 4, scoreH + 4, 5);
        ctx.fill();
        ctx.stroke();

        ctx.fillStyle = '#444'; ctx.fillRect(scoreX, scoreY, scoreW, scoreH);
        ctx.fillStyle = config.themes[config.activeTheme].playerScore; ctx.fillRect(scoreX, scoreY, scoreW * (scoreProgress / 100), scoreH);

        ctx.globalAlpha = 1.0;
        ctx.fillStyle = config.themes[config.activeTheme].textLight;
        ctx.font = `bold 14px ${config.fontFamily}`;
        ctx.textAlign = 'center';
        ctx.shadowColor = 'black';
        ctx.shadowBlur = 5;
        ctx.fillText(`Score: ${Math.round(this.animatedHud.score)}`, hudX, scoreY + 15);
        ctx.textAlign = 'start';
        ctx.restore();
    },

    drawMinimap: function(ctx, player) {
        const mapSize = 150;
        const mapX = 20, mapY = 80;
        const self = unsafeWindow.Player.pool[unsafeWindow.selfId];
        if (!self) return;

        const radarCenterX = mapX + mapSize / 2;
        const radarCenterY = mapY + mapSize / 2;
        const radarRadius = mapSize / 2;
        const radarScale = 0.1;
        const theme = config.themes[config.activeTheme];

        ctx.save();
        ctx.beginPath();
        ctx.arc(radarCenterX, radarCenterY, radarRadius, 0, 2 * Math.PI);
        ctx.clip();
        ctx.fillStyle = 'rgba(18, 18, 22, 0.75)';
        ctx.fillRect(mapX, mapY, mapSize, mapSize);
        ctx.strokeStyle = theme.hudBorder;
        ctx.lineWidth = 2;
        ctx.stroke();
        ctx.strokeStyle = 'rgba(0, 255, 255, 0.15)';
        ctx.lineWidth = 1;
        ctx.beginPath(); ctx.arc(radarCenterX, radarCenterY, radarRadius / 2, 0, 2 * Math.PI); ctx.stroke();
        ctx.beginPath(); ctx.arc(radarCenterX, radarCenterY, radarRadius, 0, 2 * Math.PI); ctx.stroke();
        ctx.beginPath();
        ctx.moveTo(radarCenterX, mapY); ctx.lineTo(radarCenterX, mapY + mapSize);
        ctx.moveTo(mapX, radarCenterY); ctx.lineTo(mapX + mapSize, radarCenterY);
        ctx.stroke();
        ctx.translate(radarCenterX, radarCenterY);
        ctx.translate(-self.x * radarScale, -self.y * radarScale);
        ctx.fillStyle = 'rgba(128, 128, 128, 0.5)';
        for (const id in unsafeWindow.MapObject.pool) {
            const obj = unsafeWindow.MapObject.pool[id];
            if (!obj.activated || obj.type === '') continue;
            const objX = obj.x * radarScale;
            const objY = obj.y * radarScale;
            const objW = obj.width * radarScale;
            const objH = obj.height * radarScale;
            ctx.save();
            ctx.translate(objX, objY);
            ctx.rotate(obj.angle * Math.PI / 180);
            ctx.fillRect(-objW / 2, -objH / 2, objW, objH);
            ctx.restore();
        }
        for (const id in unsafeWindow.Player.pool) {
            const p = unsafeWindow.Player.pool[id];
            if (!p.activated || p.hp <= 0 || p.id === self.id) continue;
            const dotX = p.x * radarScale;
            const dotY = p.y * radarScale;
            let dotSize = 3;
            let dotColor = theme.teamRed;
            if (unsafeWindow.gameType !== 'FFA' && p.teamCode === self.teamCode) {
                dotColor = theme.teamBlue;
            }
            ctx.fillStyle = dotColor;
            ctx.beginPath();
            ctx.arc(dotX, dotY, dotSize, 0, 2 * Math.PI);
            ctx.fill();
        }
        ctx.restore();
        const gameCenterX = unsafeWindow.GAME_WIDTH / 2;
        const gameCenterY = unsafeWindow.GAME_HEIGHT / 2;
        const dx = gameCenterX - self.x;
        const dy = gameCenterY - self.y;
        const distanceToCenter = Math.sqrt(dx * dx + dy * dy);
        const angleToCenter = Math.atan2(dy, dx);
        ctx.save();
        ctx.translate(radarCenterX, radarCenterY);
        if (distanceToCenter * radarScale > radarRadius - 10) {
            ctx.rotate(angleToCenter);
            ctx.translate(radarRadius - 10, 0);
        } else {
            ctx.translate(dx * radarScale, dy * radarScale);
        }
        ctx.fillStyle = 'rgba(255, 204, 0, 0.9)';
        ctx.strokeStyle = 'rgba(255, 255, 255, 1)';
        ctx.lineWidth = 1.5;
        ctx.beginPath();
        ctx.moveTo(0, 0); ctx.lineTo(-5, -5); ctx.lineTo(5, -5);
        ctx.closePath(); ctx.fill(); ctx.stroke();
        ctx.restore();
        ctx.save();
        ctx.fillStyle = theme.selfHighlight;
        ctx.translate(radarCenterX, radarCenterY);
        ctx.rotate(self.playerAngle * Math.PI / 180 + Math.PI / 2);
        ctx.beginPath();
        ctx.moveTo(0, -6); ctx.lineTo(5, 3); ctx.lineTo(-5, 3);
        ctx.closePath(); ctx.fill();
        ctx.restore();
    },

    drawWeaponAmmo: function(ctx, player) {
        const hudX = unsafeWindow.hudXPosition;
        const hudY = unsafeWindow.hudYPosition;
        const boxW = 180, boxH = 60;
        const boxX = hudX * 2 - boxW - 15, boxY = hudY * 2 - 75;
        const theme = config.themes[config.activeTheme];

        ctx.save();
        ctx.globalAlpha = 0.85;
        ctx.fillStyle = theme.hudBg;
        ctx.strokeStyle = theme.hudBorder;
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.roundRect(boxX, boxY, boxW, boxH, 5);
        ctx.fill();
        ctx.stroke();

        ctx.globalAlpha = 1.0;
        const weaponIconName = unsafeWindow.weaponIconMap[player.class] || player.class;
        if (unsafeWindow.images[weaponIconName]) {
            ctx.drawImage(unsafeWindow.images[weaponIconName], boxX + 5, boxY + 5, 50, 50);
        }

        ctx.fillStyle = theme.textLight;
        ctx.font = `bold 24px ${config.fontFamily}`;
        ctx.textAlign = 'right';
        ctx.shadowColor = 'black';
        ctx.shadowBlur = 4;
        ctx.fillText(`${player.currentBullets} / ${player.maxBullets}`, boxX + boxW - 10, boxY + 40);

        if (player.reloading) {
            ctx.font = `bold 12px ${config.fontFamily}`;
            ctx.fillStyle = theme.playerScore;
            const reloadText = "RELOADING...";
            const textWidth = ctx.measureText(reloadText).width;
            ctx.fillText(reloadText, boxX + boxW - 10, boxY + 18);
            ctx.fillStyle = theme.accent;
            ctx.fillRect(boxX + boxW - 10 - textWidth, boxY + 22, textWidth * (player.reloadingFrame / (player.reloadingAnimation ? player.reloadingAnimation.length : 1)), 2);
        }
        ctx.restore();
    },

    drawPerks: function(ctx, player) {
        const hudX = unsafeWindow.hudXPosition;
        const hudY = unsafeWindow.hudYPosition;
        const perkSize = 50, perkSpacing = 8;
        const startX = hudX * 2 - 215 - (perkSize + perkSpacing) * 3;
        const startY = hudY * 2 - 70;
        const theme = config.themes[config.activeTheme];

        ctx.save();
        for (let i = 1; i <= 3; i++) {
            const perkName = unsafeWindow.levelUpgrades[i];
            const x = startX + (i - 1) * (perkSize + perkSpacing);

            ctx.globalAlpha = 0.85;
            ctx.fillStyle = theme.hudBg;
            ctx.strokeStyle = theme.hudBorder;
            ctx.lineWidth = 2;
            ctx.beginPath();
            ctx.roundRect(x, startY, perkSize, perkSize, 5);
            ctx.fill();
            ctx.stroke();

            if (perkName && unsafeWindow.images[perkName]) {
                ctx.globalAlpha = 1.0;
                ctx.drawImage(unsafeWindow.images[perkName], x + 4, startY + 4, perkSize - 8, perkSize - 8);

                if (i === 2 && unsafeWindow.level2Timer.current > 0) {
                    ctx.globalAlpha = 0.7;
                    ctx.fillStyle = '#000';
                    const progress = unsafeWindow.level2Timer.current / unsafeWindow.level2Timer.total;
                    ctx.fillRect(x, startY, perkSize, perkSize * progress);
                }

                if (['grenade', 'fragGrenade', 'gasGrenade', 'landMine'].includes(perkName)) {
                    ctx.globalAlpha = 1.0;
                    ctx.fillStyle = 'white';
                    ctx.font = `bold 14px ${config.fontFamily}`;
                    ctx.textAlign = 'right';
                    ctx.shadowColor = 'black';
                    ctx.shadowBlur = 2;
                    ctx.fillText(player.numExplosivesLeft, x + perkSize - 4, startY + perkSize - 4);
                    ctx.textAlign = 'start';
                }
            }
        }
        ctx.restore();
    },


    drawPlayerAttachedUI: function(ctx, camera, player) {
        const theme = config.themes[config.activeTheme];
        ctx.save();
        ctx.setTransform(1, 0, 0, 1, 0, 0);


        const zoomFactor = zoomState.level;

        const x = unsafeWindow.canvas.width / 2;
        const y = unsafeWindow.canvas.height / 2;
        const radius = 24 * zoomFactor;

        const shootingBarWidth = radius * 2.5;
        const shootingBarHeight = 6 * zoomFactor;
        const shootingY = y - radius - (20 * zoomFactor);
        let shootingProgress = 1;
        let shootingBarColor = theme.shootingReady;

        if (player.shooting && player.shootingAnimation) {
            shootingProgress = player.shootingFrame / player.shootingAnimation.length;
            shootingBarColor = theme.shootingCooldown;
        }

        ctx.fillStyle = theme.playerAttachedBg;
        ctx.fillRect(x - shootingBarWidth / 2, shootingY, shootingBarWidth, shootingBarHeight);
        ctx.fillStyle = shootingBarColor;
        ctx.fillRect(x - shootingBarWidth / 2, shootingY, shootingBarWidth * shootingProgress, shootingBarHeight);

 
        const hpBarWidth = radius * 2.5;
        const hpBarHeight = 6 * zoomFactor;
        const hpY = y + radius + (10 * zoomFactor);
        const hpPercent = player.hp / 100;
        ctx.fillStyle = theme.playerAttachedBg;
        ctx.fillRect(x - hpBarWidth / 2, hpY, hpBarWidth, hpBarHeight);
        ctx.fillStyle = theme.playerAttachedHp;
        ctx.fillRect(x - hpBarWidth / 2, hpY, hpBarWidth * hpPercent, hpBarHeight);

        const armorBarY = hpY + hpBarHeight + (2 * zoomFactor);
        const armorMax = player.armor === 1 ? 30 : (player.armor === 2 ? 70 : 110);
        const armorPercent = player.armorAmount / armorMax;
        ctx.fillStyle = theme.playerAttachedBg;
        ctx.fillRect(x - hpBarWidth / 2, armorBarY, hpBarWidth, hpBarHeight);
        ctx.fillStyle = theme.playerAttachedArmor;
        ctx.fillRect(x - hpBarWidth / 2, armorBarY, hpBarWidth * armorPercent, hpBarHeight);

        if (player.reloading && player.reloadingAnimation) {
            const reloadGaugeHeight = radius * 2;
            const reloadGaugeWidth = 6 * zoomFactor;
            const reloadX = x - radius - (15 * zoomFactor);
            const reloadY = y - reloadGaugeHeight / 2;
            const reloadPercent = player.reloadingFrame / (player.reloadingAnimation.length * 0.8);
            ctx.fillStyle = theme.playerAttachedBg;
            ctx.fillRect(reloadX, reloadY, reloadGaugeWidth, reloadGaugeHeight);
            ctx.fillStyle = theme.playerAttachedReload;
            ctx.fillRect(reloadX, reloadY + reloadGaugeHeight * (1 - Math.min(1, reloadPercent)), reloadGaugeWidth, reloadGaugeHeight * Math.min(1, reloadPercent));
        }

        if (unsafeWindow.level2Timer && unsafeWindow.level2Timer.total > 0) {
            const skillGaugeHeight = radius * 2;
            const skillGaugeWidth = 6 * zoomFactor;
            const skillX = x + radius + (15 * zoomFactor);
            const skillY = y - skillGaugeHeight / 2;
            const skillPercent = unsafeWindow.level2Timer.current / unsafeWindow.level2Timer.total;
            ctx.fillStyle = theme.playerAttachedBg;
            ctx.fillRect(skillX, skillY, skillGaugeWidth, skillGaugeHeight);
            ctx.fillStyle = theme.playerAttachedSkill;
            ctx.fillRect(skillX, skillY + skillGaugeHeight * (1 - skillPercent), skillGaugeWidth, skillGaugeHeight * skillPercent);
        }

        ctx.restore();
    },

    drawPlayerChat: function(ctx, camera, player) {
        if (!player.chatMessage || player.chatMessageTimer <= 0) return;
        const theme = config.themes[config.activeTheme];
        const relPos = camera.getRelPos(player);
        const alpha = Math.min(1, player.chatMessageTimer / 20);

        ctx.save();
        ctx.globalAlpha = 0.8 * alpha;
        ctx.font = `bold 13px ${config.fontFamily}`;

        const playerName = player.username + ': ';
        const message = player.chatMessage;
        const nameWidth = ctx.measureText(playerName).width;
        const messageWidth = ctx.measureText(message).width;
        const totalWidth = nameWidth + messageWidth;
        const padding = 8;
        const boxWidth = totalWidth + padding * 2;
        const boxHeight = 22;
        const boxX = relPos.x - boxWidth / 2;
        const boxY = relPos.y - player.radius - 45;

        ctx.fillStyle = theme.hudBg;
        ctx.strokeStyle = theme.hudBorder;
        ctx.lineWidth = 1;
        ctx.beginPath();
        if (ctx.roundRect) {
            ctx.roundRect(boxX, boxY, boxWidth, boxHeight, 5);
        } else {
            ctx.rect(boxX, boxY, boxWidth, boxHeight);
        }
        ctx.fill();
        ctx.stroke();

        ctx.beginPath();
        ctx.moveTo(relPos.x - 6, boxY + boxHeight);
        ctx.lineTo(relPos.x, boxY + boxHeight + 6);
        ctx.lineTo(relPos.x + 6, boxY + boxHeight);
        ctx.closePath();
        ctx.fill();
        ctx.stroke();

        ctx.globalAlpha = 1.0 * alpha;
        ctx.textAlign = 'left';
        ctx.textBaseline = 'middle';
        ctx.shadowColor = 'black';
        ctx.shadowBlur = 2;
        ctx.fillStyle = theme.accent;
        ctx.fillText(playerName, boxX + padding, boxY + boxHeight / 2 + 1);
        ctx.fillStyle = theme.textLight;
        ctx.fillText(message, boxX + padding + nameWidth, boxY + boxHeight / 2 + 1);

        ctx.restore();
    },

    drawPlayerCount: function(ctx) {
        const hudX = unsafeWindow.hudXPosition;
        const lbX = hudX * 2 - 265;
        const boxW = 100, boxH = 40;
        const boxX = lbX - boxW - 15;
        const boxY = 15;
        const theme = config.themes[config.activeTheme];

        const currentPlayers = unsafeWindow.gameStatus.currentPlayers || 0;
        const maxPlayers = unsafeWindow.MAX_PLAYERS || 0;

        ctx.save();
        ctx.globalAlpha = 0.85;
        ctx.fillStyle = theme.hudBg;
        ctx.strokeStyle = theme.hudBorder;
        ctx.lineWidth = 2;
        ctx.beginPath();
        if (ctx.roundRect) {
            ctx.roundRect(boxX, boxY, boxW, boxH, 8);
        } else {
            ctx.rect(boxX, boxY, boxW, boxH);
        }
        ctx.fill();
        ctx.stroke();

        ctx.globalAlpha = 1.0;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';

        ctx.fillStyle = theme.textDim;
        ctx.font = `bold 12px ${config.fontFamily}`;
        ctx.shadowColor = 'black';
        ctx.shadowBlur = 3;
        ctx.fillText("PLAYERS", boxX + boxW / 2, boxY + 12);

        ctx.fillStyle = theme.textLight;
        ctx.font = `bold 16px ${config.fontFamily}`;
        ctx.fillText(`${currentPlayers} / ${maxPlayers}`, boxX + boxW / 2, boxY + 28);

        ctx.restore();
    },

    drawLeaderboard: function(ctx, leaderboard) {
        const hudX = unsafeWindow.hudXPosition;
        const lbX = hudX * 2 - 265, lbY = 15, lbW = 250, entryH = 22;
        const theme = config.themes[config.activeTheme];

        ctx.save();
        ctx.globalAlpha = 0.85;
        ctx.fillStyle = theme.hudBg;
        ctx.strokeStyle = theme.hudBorder;
        ctx.lineWidth = 2;
        ctx.beginPath();
        if (ctx.roundRect) {
            ctx.roundRect(lbX, lbY, lbW, 40 + Math.min(leaderboard.current.length, 10) * entryH, 8);
        } else {
            ctx.rect(lbX, lbY, lbW, 40 + Math.min(leaderboard.current.length, 10) * entryH);
        }
        ctx.fill();
        ctx.stroke();

        ctx.globalAlpha = 1.0;
        ctx.fillStyle = theme.accent;
        ctx.font = `bold 16px ${config.fontFamily}`;
        ctx.textAlign = 'center';
        ctx.shadowColor = theme.glow;
        ctx.shadowBlur = 8;
        ctx.fillText("LEADERBOARD", lbX + lbW / 2, lbY + 25);
        ctx.shadowBlur = 0;

        leaderboard.current.forEach((p, i) => {
    if (i >= 10) return;
    const entryY = lbY + 40 + i * entryH;
    const isSelf = p.userId === unsafeWindow.isolatedUsername;
    const self = unsafeWindow.Player.pool[unsafeWindow.selfId];

    let textColor = theme.textLight;

    if (isSelf) {

        textColor = theme.accent;
        ctx.fillStyle = 'rgba(0, 255, 255, 0.15)';
        ctx.fillRect(lbX + 2, entryY, lbW - 4, entryH);
    } else if (self && self.teamCode !== 0 && p.teamCode !== 0) {
        if (p.teamCode === self.teamCode) {
            textColor = theme.teamBlue;
        } else {
            textColor = theme.teamRed;
        }
    }

    ctx.fillStyle = textColor;
    ctx.font = `500 13px ${config.fontFamily}`;
    ctx.textAlign = 'left';
    ctx.fillText(`${i + 1}. ${p.userId}`, lbX + 10, entryY + 15);

    ctx.textAlign = 'right';
    const killsText = p.kills !== undefined ? ` (${p.kills}K)` : '';
    ctx.fillText(`${p.score}${killsText}`, lbX + lbW - 10, entryY + 15);
});
        ctx.restore();
    },

    updateAll: function(player) {
        if (!player || unsafeWindow.spectating) {
            this.animatedHud.isInitialized = false;
            if (unsafeWindow.respawnButtonVisible) {
                unsafeWindow.originalDrawHud.apply(this, arguments);
            }
            return;
        }
        const ctx = unsafeWindow.ctx;
        const camera = unsafeWindow.camera;

        if (!this.animatedHud.isInitialized) {
            this.animatedHud.hp = player.hp;
            this.animatedHud.armor = player.armorAmount;
            this.animatedHud.score = player.score;
            this.animatedHud.isInitialized = true;
        }

        this.animatedHud.hp += (player.hp - this.animatedHud.hp) * 0.15;
        this.animatedHud.armor += (player.armorAmount - this.animatedHud.armor) * 0.15;
        this.animatedHud.score += (player.score - this.animatedHud.score) * 0.15;

        this.drawHealthArmor(ctx, player);
        this.drawScore(ctx, player);
        this.drawMinimap(ctx, player);
        this.drawWeaponAmmo(ctx, player);
        this.drawPerks(ctx, player);
        this.drawPlayerAttachedUI(ctx, camera, player);
        this.drawTopStatusBar(ctx, player);
        this.drawPlayerCount(ctx);
    }
};

const autoPerkSystem = {
    init: function(targetElement) {
        this.loadSettings();
        this.createUI(targetElement);
        this.updateUI();
    },

    loadSettings: function() {
        const savedSettings = localStorage.getItem('gatsModAutoPerkSettings');
        if (savedSettings) {
            config.autoPerk.settings = JSON.parse(savedSettings);
        }
    },

    saveSettings: function() {
        localStorage.setItem('gatsModAutoPerkSettings', JSON.stringify(config.autoPerk.settings));
    },

    createUI: function(targetElement) {
        if (!targetElement) {
            console.error("GatsMod: Target element for Auto-Perk UI not provided.");
            return;
        }

        const container = document.createElement('div');
        container.id = 'auto-perk-container';
        container.innerHTML = `
            <div id="autoPerkTitle" class="selection-title" style="margin-top: 0;">Auto-Perk Selection</div>
            <div class="auto-perk-slots">
                <div id="auto-perk-slot-1" class="perk-slot" data-tier="1">1</div>
                <div id="auto-perk-slot-2" class="perk-slot" data-tier="2">2</div>
                <div id="auto-perk-slot-3" class="perk-slot" data-tier="3">3</div>
            </div>
        `;
        targetElement.appendChild(container);

        document.querySelectorAll('.perk-slot').forEach(slot => {
            slot.addEventListener('click', (e) => {
                const tier = e.target.dataset.tier;
                this.showPerkSelectionModal(tier);
            });
        });
    },

    updateUI: function() {
        for (let i = 1; i <= 3; i++) {
            const slot = document.getElementById(`auto-perk-slot-${i}`);
            const perkName = config.autoPerk.settings[`tier${i}`];
            if (slot) {
                if (perkName) {
                    slot.style.backgroundImage = `url('/img/${perkName}.png')`;
                    slot.innerText = '';
                } else {
                    slot.style.backgroundImage = 'none';
                    slot.innerText = i;
                }
            }
        }
    },

    showPerkSelectionModal: function(tier) {
        const perkList = perkGUI[`tier${tier}`];
        let modal = document.getElementById('perk-selection-modal');
        if (modal) modal.remove();

        modal = document.createElement('div');
        modal.id = 'perk-selection-modal';
        modal.innerHTML = `<div class="modal-content"><h3>Select Tier ${tier} Perk</h3><div class="perk-grid"></div></div>`;
        document.body.appendChild(modal);

        const grid = modal.querySelector('.perk-grid');
        const noneOption = document.createElement('div');
        noneOption.className = 'perk-icon-modal';
        noneOption.innerText = 'None';
        noneOption.onclick = () => this.selectAutoPerk(tier, null);
        grid.appendChild(noneOption);

        perkList.forEach(perkName => {
            const icon = document.createElement('div');
            icon.className = 'perk-icon-modal';
            icon.style.backgroundImage = `url('/img/${perkName}.png')`;
            icon.title = perkName.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase());
            icon.onclick = () => this.selectAutoPerk(tier, perkName);
            grid.appendChild(icon);
        });

        modal.addEventListener('click', (e) => {
            if (e.target.id === 'perk-selection-modal') modal.remove();
        });
    },

    selectAutoPerk: function(tier, perkName) {
        config.autoPerk.settings[`tier${tier}`] = perkName;
        this.saveSettings();
        this.updateUI();
        const modal = document.getElementById('perk-selection-modal');
        if (modal) modal.remove();
    },

    attemptAutoUpgrade: function(tier) {
        if (!config.autoPerk.enabled) return false;

        const perkToSelect = config.autoPerk.settings[`tier${tier}`];
        if (perkToSelect) {
            const alreadySelected = Object.values(unsafeWindow.levelUpgrades).includes(perkToSelect);
            if (!alreadySelected) {
                console.log(`GatsMod: Auto-selecting Tier ${tier} perk: ${perkToSelect}`);
                unsafeWindow.levelUpgrades[tier] = perkToSelect;
                unsafeWindow.Connection.list[0].send(unsafeWindow.prepareMessage('upgrade', {
                    upgrade: perkToSelect,
                    upgradeLevel: tier
                }));
                perkGUI.hideTier(tier);
                return true;
            }
        }
        return false;
    }
};

const utilitySystem = {
    init: function(targetElement) {
        this.loadSettings();
        this.createUI(targetElement);
    },
    loadSettings: function() {
        const savedRespawn = localStorage.getItem('gatsModAutoRespawnEnabled');
        if (savedRespawn !== null) config.autoRespawn.enabled = (savedRespawn === 'true');

        const savedTheme = localStorage.getItem('gatsModActiveTheme');
        if (savedTheme && config.themes[savedTheme]) config.activeTheme = savedTheme;
    },
    saveSettings: function() {
        localStorage.setItem('gatsModAutoRespawnEnabled', config.autoRespawn.enabled);
        localStorage.setItem('gatsModActiveTheme', config.activeTheme);
    },
    createUI: function(targetElement) {
        if (!targetElement) {
            console.error("GatsMod: Target element for Utility UI not provided.");
            return;
        }

        const container = document.createElement('div');
        container.id = 'utility-container';
        container.innerHTML = `
            <div class="selection-title" style="margin-top: 0; margin-bottom: 12px; padding-bottom: 5px; font-size: 16px;">General Settings</div>
            <div class="utility-options-wrapper">
                <label for="autoRespawnCheckbox" class="utility-option">
                    <input type="checkbox" id="autoRespawnCheckbox">
                    <span>Auto-Respawn</span>
                </label>
                <div class="utility-option-group">
                    <label for="theme-selector" class="utility-label">Theme</label>
                    <select id="theme-selector" class="form-control">
                        <option value="cyberpunk">Cyberpunk</option>
                        <option value="military">Military</option>
                        <option value="retro">Retro</option>
                        <option value="darkMode">Dark Mode</option>
                    </select>
                </div>
            </div>
        `;
        targetElement.appendChild(container);

        const checkbox = document.getElementById('autoRespawnCheckbox');
        checkbox.checked = config.autoRespawn.enabled;
        checkbox.addEventListener('change', () => {
            config.autoRespawn.enabled = checkbox.checked;
            this.saveSettings();
            notificationSystem.show(`Auto-Respawn ${config.autoRespawn.enabled ? 'enabled' : 'disabled'}.`);
        });

        const themeSelector = document.getElementById('theme-selector');
        themeSelector.value = config.activeTheme;
        themeSelector.addEventListener('change', (e) => {
            applyTheme(e.target.value);
            this.saveSettings();
            notificationSystem.show(`Theme set to "${e.target.options[e.target.selectedIndex].text}".`);
        });
    }
};

const perkGUI = {
    tier1: ['bipod', 'optics', 'thermal', 'armorPiercing', 'extended', 'grip', 'silencer', 'lightweight', 'longRange', 'thickSkin'],
    tier2: ['shield', 'firstAid', 'grenade', 'knife', 'engineer', 'dash', 'gasGrenade', 'landMine', 'fragGrenade'],
    tier3: ['bipod', 'optics', 'thermal', 'armorPiercing', 'extended', 'grip', 'silencer', 'lightweight', 'longRange', 'thickSkin'],
    isInitialized: false,
    tierVisible: { 1: false, 2: false, 3: false },

    init: function() {
        if (this.isInitialized) return;
        const guiContainer = document.createElement('div');
        guiContainer.id = 'perk-gui-container';
        document.body.appendChild(guiContainer);
        this.applyStyles();
        this.isInitialized = true;
    },

    applyStyles: function() {
        GM_addStyle(`
            #perk-gui-container {
                position: fixed; bottom: 100px; left: 50%;
                transform: translateX(-50%); display: flex;
                flex-direction: column; align-items: center;
                gap: 10px; z-index: 1000; pointer-events: none;
            }
            .perk-tier {
                display: flex; gap: 10px; background: var(--hud-bg, rgba(18, 18, 22, 0.8));
                padding: 10px; border-radius: 10px;
                border: 1px solid var(--hud-border, rgba(0, 255, 255, 0.4));
                box-shadow: 0 0 20px var(--glow-color, rgba(0, 255, 255, 0.6));
                pointer-events: auto; opacity: 0;
                transform: translateY(10px);
                transition: opacity 0.3s ease, transform 0.3s ease;
            }
            .perk-tier.visible { opacity: 1; transform: translateY(0); }
            .perk-icon {
                width: 60px; height: 60px;
                background-color: var(--secondary-bg);
                border: 2px solid #444; border-radius: 6px;
                cursor: pointer; transition: all 0.2s ease;
                background-size: 85%; background-position: center;
                background-repeat: no-repeat;
            }
            .perk-icon:hover {
                border-color: var(--accent-color);
                transform: scale(1.1);
                filter: drop-shadow(0 0 8px var(--glow-color));
            }
        `);
    },

    update: function() {
        if (!config.perkGUI.enabled || !unsafeWindow.inGame || unsafeWindow.spectating) {
            this.hideAll();
            return;
        }
        this.init();
        const player = unsafeWindow.Player.pool[unsafeWindow.selfId];
        if (!player) return;
        const score = player.score;
        const levelUpgrades = unsafeWindow.levelUpgrades;

        if (score >= 100 && levelUpgrades[1] === '') {
            if (!autoPerkSystem.attemptAutoUpgrade(1)) {
                if (!this.tierVisible[1]) this.showTier(1, this.tier1.filter(perk => !Object.values(levelUpgrades).includes(perk)));
            }
        } else { this.hideTier(1); }

        if (score >= 300 && levelUpgrades[2] === '') {
            if (!autoPerkSystem.attemptAutoUpgrade(2)) {
                if (!this.tierVisible[2]) this.showTier(2, this.tier2.filter(perk => !Object.values(levelUpgrades).includes(perk)));
            }
        } else { this.hideTier(2); }

        if (score >= 600 && levelUpgrades[3] === '') {
            if (!autoPerkSystem.attemptAutoUpgrade(3)) {
                if (!this.tierVisible[3]) this.showTier(3, this.tier3.filter(perk => !Object.values(levelUpgrades).includes(perk)));
            }
        } else { this.hideTier(3); }
    },

    showTier: function(tier, perks) {
        this.tierVisible[tier] = true;
        let tierDiv = document.getElementById(`perk-tier-${tier}`);
        if (!tierDiv) {
            tierDiv = document.createElement('div');
            tierDiv.id = `perk-tier-${tier}`;
            tierDiv.className = 'perk-tier';
            document.getElementById('perk-gui-container').appendChild(tierDiv);
        }
        tierDiv.innerHTML = '';

        perks.forEach(perkName => {
            const icon = document.createElement('div');
            icon.className = 'perk-icon';
            icon.style.backgroundImage = `url('/img/${perkName}.png')`;
            icon.title = perkName.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase());
            icon.onclick = () => this.selectPerk(tier, perkName);
            tierDiv.appendChild(icon);
        });

        setTimeout(() => tierDiv.classList.add('visible'), 10);
    },

    hideTier: function(tier) {
        this.tierVisible[tier] = false;
        const tierDiv = document.getElementById(`perk-tier-${tier}`);
        if (tierDiv) tierDiv.classList.remove('visible');
    },

    hideAll: function() {
        this.hideTier(1); this.hideTier(2); this.hideTier(3);
    },

    selectPerk: function(tier, perkName) {
        unsafeWindow.levelUpgrades[tier] = perkName;
        unsafeWindow.Connection.list[0].send(unsafeWindow.prepareMessage('upgrade', {
            upgrade: perkName,
            upgradeLevel: tier
        }));
        this.hideTier(tier);
    }
};

const esp = {
    areas: {
        tdm: [{ x: 3400, y: 3400, w: 200, h: 200 }],
        dom: [
            { x: 2500, y: 2500, w: 200, h: 200 }, { x: 4300, y: 2500, w: 200, h: 200 },
            { x: 2500, y: 4300, w: 200, h: 200 }, { x: 4300, y: 4300, w: 200, h: 200 }
        ]
    },
    draw: function(ctx, camera) {
        if (!config.esp.enabled || !unsafeWindow.inGame || unsafeWindow.spectating) return;
        const self = unsafeWindow.Player.pool[unsafeWindow.selfId];
        if (!self) return;
        const gameType = unsafeWindow.gameType;
        let areasToDraw = [];
        if (gameType === 'TDM' || gameType === 'FFA') areasToDraw = this.areas.tdm;
        else if (gameType === 'DOM') areasToDraw = this.areas.dom;
        if (areasToDraw.length === 0) return;

        const theme = config.themes[config.activeTheme];

        ctx.save();
        ctx.lineWidth = 2.5;
        ctx.shadowColor = 'black'; ctx.shadowBlur = 6;
        areasToDraw.forEach(area => {
            const relPos = camera.getRelPos(area);
            const enemyCount = this.countEnemiesInArea(area, self);
            const isSelfInArea = (self.x >= area.x && self.x <= area.x + area.w && self.y >= area.y && self.y <= area.y + area.h);
            let color = theme.espSafe;
            if (enemyCount > 0) color = theme.espWarning;
            if (enemyCount >= 2) color = theme.espDanger;
            if (isSelfInArea && color === theme.espSafe) {
                color = theme.espWarning;
            }
            ctx.strokeStyle = color;
            const bracketSize = 20;
            ctx.beginPath(); ctx.moveTo(relPos.x + bracketSize, relPos.y); ctx.lineTo(relPos.x, relPos.y); ctx.lineTo(relPos.x, relPos.y + bracketSize); ctx.stroke();
            ctx.beginPath(); ctx.moveTo(relPos.x + area.w - bracketSize, relPos.y); ctx.lineTo(relPos.x + area.w, relPos.y); ctx.lineTo(relPos.x + area.w, relPos.y + bracketSize); ctx.stroke();
            ctx.beginPath(); ctx.moveTo(relPos.x + bracketSize, relPos.y + area.h); ctx.lineTo(relPos.x, relPos.y + area.h); ctx.lineTo(relPos.x, relPos.y + area.h - bracketSize); ctx.stroke();
            ctx.beginPath(); ctx.moveTo(relPos.x + area.w - bracketSize, relPos.y + area.h); ctx.lineTo(relPos.x + area.w, relPos.y + area.h); ctx.lineTo(relPos.x + area.w, relPos.y + area.h - bracketSize); ctx.stroke();
        });
        ctx.restore();
    },
    countEnemiesInArea: function(area, self) {
        let count = 0;
        for (const id in unsafeWindow.Player.pool) {
            const p = unsafeWindow.Player.pool[id];
            if (!p.activated || p.hp <= 0 || p.id === self.id) continue;
            if (unsafeWindow.gameType !== 'FFA' && p.teamCode === self.teamCode) continue;
            if (p.x >= area.x && p.x <= area.x + area.w && p.y >= area.y && p.y <= area.y + area.h) count++;
        }
        return count;
    }
};

const notificationSystem = {
       init: function() {
        if (document.getElementById('notification-container')) return;
        const container = document.createElement('div');
        container.id = 'notification-container';
        document.body.appendChild(container);
    },
    show: function(message) {
        if (!config.notifications.enabled) return;
        const container = document.getElementById('notification-container');
        if (!container) return;
        const notification = document.createElement('div');
        notification.className = 'notification';
        notification.textContent = message;
        container.appendChild(notification);
        if (container.children.length > config.notifications.maxDisplay) {
            container.removeChild(container.firstChild);
        }
        setTimeout(() => {
            if (container.contains(notification)) container.removeChild(notification);
        }, config.notifications.displayTime);
    }
};

const placementPreview = {
    draw: function(ctx, camera) {
        if (!unsafeWindow.inGame || unsafeWindow.spectating) return;
        const self = unsafeWindow.Player.pool[unsafeWindow.selfId];
        if (!self) return;
        const activePerk = unsafeWindow.levelUpgrades[2];
        let modelToDraw = null;
        let previewAngle = self.playerAngle;
        if (activePerk === 'landMine') {
            modelToDraw = unsafeWindow.getModel('landMine');
        } else if (activePerk === 'engineer') {
            modelToDraw = unsafeWindow.getModel('userCrate', self.isPremiumMember);
            previewAngle = 90;
        }
        if (!modelToDraw) return;
        const DISTANCE = 50;
        const angleRad = self.playerAngle * (Math.PI / 180);
        const previewPos = {
            x: self.x + DISTANCE * Math.cos(angleRad),
            y: self.y + DISTANCE * Math.sin(angleRad)
        };
        ctx.save();
        ctx.globalAlpha = 0.4;
        unsafeWindow.drawModel(ctx, camera, previewPos, previewAngle, modelToDraw[0], 2, config.themes[config.activeTheme].accent, 0);
        ctx.restore();
    }
};

const chatLogSystem = {
    history: [],
    ui: { container: null, content: null },

    init: function() {
        if (!config.chatLog.enabled) return;
        this.createUI();
        this.hookIntoGame();
    },

    createUI: function() {
        this.ui.container = document.createElement('div');
        this.ui.container.id = 'chat-log-container';

        const handle = document.createElement('div');
        handle.id = 'chat-log-handle';
        handle.textContent = 'LOG';

        this.ui.content = document.createElement('div');
        this.ui.content.id = 'chat-log-content';

        this.ui.container.appendChild(this.ui.content);
        this.ui.container.appendChild(handle);
        document.body.appendChild(this.ui.container);
    },

    addEntry: function(player) {
        if (!player || !player.chatMessage || player.chatMessage.trim() === '') return;

        this.history.push({
            name: player.username,
            message: player.chatMessage,
            teamCode: player.teamCode,
            isSelf: player.id === unsafeWindow.selfId
        });

        if (this.history.length > config.chatLog.maxEntries) {
            this.history.shift();
        }
        this.updateUI();
    },

    updateUI: function() {
        if (!this.ui.content) return;
        this.ui.content.innerHTML = '';

        const self = unsafeWindow.Player.pool[unsafeWindow.selfId];
        const theme = config.themes[config.activeTheme];

        this.history.forEach(entry => {
            const entryDiv = document.createElement('div');
            entryDiv.className = 'chat-log-entry';

            const nameSpan = document.createElement('span');
            nameSpan.className = 'chat-log-player-name';
            nameSpan.textContent = entry.name + ': ';

            if (entry.isSelf) {
                nameSpan.style.color = theme.accent;
            } else if (self && self.teamCode !== 0 && entry.teamCode === self.teamCode) {
                nameSpan.style.color = theme.teamBlue;
            } else {
                nameSpan.style.color = theme.teamRed;
            }

            const messageSpan = document.createElement('span');
            messageSpan.textContent = entry.message;

            entryDiv.appendChild(nameSpan);
            entryDiv.appendChild(messageSpan);
            this.ui.content.appendChild(entryDiv);
        });

        this.ui.content.scrollTop = this.ui.content.scrollHeight;
    },

    hookIntoGame: function() {
        const originalApplyAuxUpdate = unsafeWindow.Player.prototype.applyAuxUpdate;
        const self = this;

        unsafeWindow.Player.prototype.applyAuxUpdate = function(data) {
            if (data.chatMessage !== undefined && data.chatMessage !== '') {
                const playerStateForLog = {
                    username: this.username,
                    chatMessage: data.chatMessage,
                    teamCode: this.teamCode,
                    id: this.id
                };
                self.addEntry(playerStateForLog);
            }
            originalApplyAuxUpdate.apply(this, arguments);
        };
    }
};

const statsDisplay = {
    fps: 0,
    ping: 0,
    lastFrameTime: 0,
    frameCount: 0,
    lastUpdateTime: 0,
    container: null,
    fpsEl: null,
    pingEl: null,

    init: function() {
        this.container = document.createElement('div');
        this.container.id = 'stats-display-container';
        this.container.innerHTML = `
            <span id="stats-fps">FPS: --</span>
            <span id="stats-ping">Ping: --ms</span>
        `;
        document.body.appendChild(this.container);
        this.fpsEl = document.getElementById('stats-fps');
        this.pingEl = document.getElementById('stats-ping');
    },

    update: function(now) {
        if (!this.lastUpdateTime) this.lastUpdateTime = now;
        const delta = now - this.lastUpdateTime;
        this.frameCount++;

        if (delta >= 1000) {
            this.fps = this.frameCount;
            this.frameCount = 0;
            this.lastUpdateTime = now;
            if (this.fpsEl) this.fpsEl.textContent = `FPS: ${this.fps}`;
        }

        if (unsafeWindow.Connection && unsafeWindow.Connection.list[0]) {
            this.ping = unsafeWindow.Connection.list[0].currentPing || 0;
            if (this.pingEl) this.pingEl.textContent = `Ping: ${this.ping}ms`;
        }
    }
};


function applyTheme(themeName) {
    if (!config.themes[themeName]) {
        console.error(`Theme "${themeName}" not found.`);
        return;
    }
    config.activeTheme = themeName;
    const theme = config.themes[themeName];
    const root = document.documentElement;

    root.style.setProperty('--main-bg', theme.mainBg);
    root.style.setProperty('--secondary-bg', theme.secondaryBg);
    root.style.setProperty('--accent-color', theme.accent);
    root.style.setProperty('--accent-hover', theme.accentHover);
    root.style.setProperty('--accent-border', theme.accentBorder);
    root.style.setProperty('--glow-color', theme.glow);
    root.style.setProperty('--text-color-light', theme.textLight);
    root.style.setProperty('--text-color-dim', theme.textDim);
    root.style.setProperty('--btn-success-bg', theme.btnSuccessBg);
    root.style.setProperty('--btn-success-border', theme.btnSuccessBorder);


    if (unsafeWindow.config) {
        unsafeWindow.config.colors.canvasBg = theme.canvasBg;
    }
}

function initializeTheme() {
    const savedTheme = localStorage.getItem('gatsModActiveTheme');
    if (savedTheme && config.themes[savedTheme]) {
        applyTheme(savedTheme);
    } else {
        applyTheme(config.activeTheme);
    }
}

function initGameModifications() {
    if (typeof unsafeWindow.drawGrid === 'undefined' || typeof unsafeWindow.Player === 'undefined' || typeof unsafeWindow.despawn === 'undefined') {
        return;
    }
    console.log("GatsMod Overhaul: Applying all modifications...");

    notificationSystem.init();
    chatLogSystem.init();
    statsDisplay.init();

    const originalDrawGrid = unsafeWindow.drawGrid;

    unsafeWindow.originalDrawHud = unsafeWindow.drawHud;
    unsafeWindow.originalDrawNotifications = unsafeWindow.drawNotifications;
    unsafeWindow.originalDrawLeaderboard = unsafeWindow.drawLeaderboard;
    const originalGameLoop = unsafeWindow.gameLoop;
    const originalBulletDraw = unsafeWindow.Bullet.prototype.draw;
    const originalDespawn = unsafeWindow.despawn;

    const originalResizeCanvas = unsafeWindow.resizeCanvas;
    unsafeWindow.resizeCanvas = function() {
        originalResizeCanvas.apply(this, arguments);
        unsafeWindow.widthScaleFactor *= zoomState.level;
        unsafeWindow.heightScaleFactor *= zoomState.level;
        unsafeWindow.hudXPosition /= zoomState.level;
        unsafeWindow.hudYPosition /= zoomState.level;
        const ctx = unsafeWindow.ctx;
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        ctx.scale(unsafeWindow.widthScaleFactor, unsafeWindow.heightScaleFactor);
 };
    window.addEventListener('wheel', handleMouseWheel, { passive: false });



    unsafeWindow.despawn = function() {
        const wasInGame = unsafeWindow.inGame && !unsafeWindow.spectating;
        originalDespawn.apply(this, arguments);

        if (config.autoRespawn.enabled && wasInGame) {
             console.log("[GatsMod] Auto Respawn triggered.");
             if (typeof unsafeWindow.returnToSelectionScreen === 'function') {
                unsafeWindow.returnToSelectionScreen();
                setTimeout(() => {
                    if (typeof unsafeWindow.play === 'function' && document.getElementById('playButton')) {
                         unsafeWindow.play();
                    }
                }, 250);
             }
        }
    };

    unsafeWindow.drawHud = (player) => customUI.updateAll(player);
    unsafeWindow.drawHudMiniMap = () => {};
    unsafeWindow.drawLeaderboard = (ctx, leaderboard) => {
    if (leaderboard && typeof leaderboard.currentPlayers !== 'undefined') {
        unsafeWindow.gameStatus.currentPlayers = leaderboard.currentPlayers;
    }

        leaderboard.current = leaderboard.new;
        customUI.drawLeaderboard(ctx, leaderboard);
    };

    unsafeWindow.drawNotifications = function() {
        const notifications = unsafeWindow.displayedNotifications;
        if (notifications && notifications.length > 0) {
            const lastNotification = notifications.pop();
            let message = lastNotification.content;
            switch(lastNotification.type) {
                case 1: message = `Killed ${lastNotification.content}!`; break;
                case 2: message = `Killed by ${lastNotification.content}`; break;
                case 3: message = `Hit Damage ${lastNotification.content}`; break;
            }
            notificationSystem.show(message);
        }
    };

    unsafeWindow.gameLoop = function() {
        const theme = config.themes[config.activeTheme];
        if (unsafeWindow.crate) {
            unsafeWindow.crate[0][0][1][3] = theme.crateBody;
            unsafeWindow.crate[0][1][1][3] = theme.crateLid;
        }
        if (unsafeWindow.longCrate) {
            unsafeWindow.longCrate[0][0][1][3] = theme.crateBody;
            unsafeWindow.longCrate[0][1][1][3] = theme.crateLid;
        }
        const now = performance.now();
        statsDisplay.update(now);

        originalGameLoop.apply(this, arguments);

        if (unsafeWindow.inGame) {
            const ctx = unsafeWindow.ctx;
            const camera = unsafeWindow.camera;
            for (const id in unsafeWindow.Player.pool) {
                const player = unsafeWindow.Player.pool[id];
                if (player && player.activated) {
                    customUI.drawPlayerChat(ctx, camera, player);
                }
            }
        }

        placementPreview.draw(unsafeWindow.ctx, unsafeWindow.camera);
    };

    unsafeWindow.drawGrid = function(ctx, camera) {

        originalDrawGrid.apply(this, arguments);

        esp.draw(ctx, camera);


        ctx.save();
        ctx.setTransform(1, 0, 0, 1, 0, 0);

        const theme = config.themes[config.activeTheme];

        if (customUI.damageFlashAlpha > 0) {
            const centerX = unsafeWindow.canvas.width / 2;
            const centerY = unsafeWindow.canvas.height / 2;
            const outerRadius = Math.sqrt(centerX * centerX + centerY * centerY);

            const colorBase = theme.damageFlash.substring(0, theme.damageFlash.lastIndexOf(',') + 1);
            const finalColor = `${colorBase} ${customUI.damageFlashAlpha})`;

            const gradient = ctx.createRadialGradient(centerX, centerY, outerRadius * 0.6, centerX, centerY, outerRadius);
            gradient.addColorStop(0, 'rgba(255, 0, 50, 0)');
            gradient.addColorStop(1, finalColor);
            ctx.fillStyle = gradient;
            ctx.fillRect(0, 0, unsafeWindow.canvas.width, unsafeWindow.canvas.height);

            customUI.damageFlashAlpha -= 0.04;
        }

        if (unsafeWindow.spectating && customUI.deathFade > 0) {
            customUI.deathFade -= 0.02;
            ctx.globalAlpha = customUI.deathFade;
            ctx.fillStyle = theme.deathOverlay;
            ctx.fillRect(0, 0, unsafeWindow.canvas.width, unsafeWindow.canvas.height);
        } else if (!unsafeWindow.spectating) {
            customUI.deathFade = 1.0;
        }

        ctx.restore();
    };

    unsafeWindow.Bullet.prototype.draw = function(ctx, camera) {
        if (!this.activated || this.isKnife) {
            originalBulletDraw.apply(this, arguments);
            return;
        }
        const theme = config.themes[config.activeTheme];
        ctx.save();
        ctx.strokeStyle = theme.bulletTrail;
        ctx.lineWidth = this.width * 0.6;
        ctx.globalAlpha = 0.7;
        const relPos = camera.getRelPos(this);
        const prevX = relPos.x - this.spdX * 0.6;
        const prevY = relPos.y - this.spdY * 0.6;
        ctx.beginPath(); ctx.moveTo(prevX, prevY); ctx.lineTo(relPos.x, relPos.y); ctx.stroke();
        ctx.restore();

        const originalStrokeStyle = ctx.strokeStyle;
        ctx.strokeStyle = theme.bulletCore;
        ctx.shadowColor = theme.bulletGlow;
        ctx.shadowBlur = 8;
        originalBulletDraw.apply(this, arguments);
        ctx.shadowBlur = 0;
        ctx.strokeStyle = originalStrokeStyle;
    };

    unsafeWindow.weaponIconMap = {
        'pistol': 'pistol-outline', 'smg': 'smg-outline', 'shotgun': 'shotgun-outline',
        'assault': 'assault-outline', 'sniper': 'bolt-action-rifle-outline', 'lmg': 'machine-gun-outline'
    };

    clearInterval(modInterval);
    console.log("GatsMod Overhaul: All modifications applied successfully.");

    initTitleScreenFeatures();
    if (typeof unsafeWindow.processMessage === 'function') {
            const originalProcessMessage = unsafeWindow.processMessage;

            unsafeWindow.processMessage = function(event) {
                originalProcessMessage.apply(this, arguments);

                try {
                    const dataView = new Uint8Array(event.data);

                    if (dataView.length > 0 && dataView[0] === 97) {
                        console.log("GatsMod [AbilityHack]: Player spawn message ('a') detected.");
                        setTimeout(() => {
                            if (unsafeWindow.Connection && unsafeWindow.Connection.list[0] && unsafeWindow.selfId != null) {
                                console.log("GatsMod [AbilityHack]: Sending fake 'longRange' upgrade request...");
                                const longRangeMessage = unsafeWindow.prepareMessage('upgrade', {
                                    'upgrade': 'longRange',
                                    'upgradeLevel': 1
                                });
                                unsafeWindow.Connection.list[0].send(longRangeMessage);
                                console.log("GatsMod [AbilityHack]: Sending fake 'dash' upgrade request...");
                                const dashMessage = unsafeWindow.prepareMessage('upgrade', {
                                    'upgrade': 'dash',
                                    'upgradeLevel': 2
                                });
                                unsafeWindow.Connection.list[0].send(dashMessage);
                            }
                        }, 1000);
                    }
                } catch (e) {
                }
            };

            console.log("GatsMod [AbilityHack]: processMessage function hooked successfully.");
        }
}

function initTitleScreenFeatures() {
    const slct = document.getElementById('slct');
    if (!slct) {
        setTimeout(initTitleScreenFeatures, 100);
        return;
    }
    if (slct.querySelector('.main-tabs-container')) {
        return;
    }

    const tabsContainer = document.createElement('div');
    tabsContainer.className = 'main-tabs-container';

    const selectionTabBtn = document.createElement('button');
    selectionTabBtn.className = 'main-tab-btn active';
    selectionTabBtn.textContent = 'Loadout';
    selectionTabBtn.dataset.tab = 'selection';

    const utilityTabBtn = document.createElement('button');
    utilityTabBtn.className = 'main-tab-btn';
    utilityTabBtn.textContent = 'Utilities & Settings';
    utilityTabBtn.dataset.tab = 'utility';

    tabsContainer.appendChild(selectionTabBtn);
    tabsContainer.appendChild(utilityTabBtn);

    const selectionContent = document.createElement('div');
    selectionContent.id = 'selection-tab-content';
    selectionContent.className = 'main-tab-content active';

    const utilityContent = document.createElement('div');
    utilityContent.id = 'utility-tab-content';
    utilityContent.className = 'main-tab-content';

    const childrenToMove = [...slct.children];
    childrenToMove.forEach(child => {
        selectionContent.appendChild(child);
    });

    const discordBtn = selectionContent.querySelector('#discord-link-btn');
    if (discordBtn) {
       selectionContent.querySelector('#playButton').parentElement.appendChild(discordBtn);
    } else {
       const playButton = selectionContent.querySelector('#playButton');
       if (playButton && playButton.parentElement) {
            const newDiscordBtn = document.createElement('a');
            newDiscordBtn.href = 'https://discord.com/users/975535045047648266';
            newDiscordBtn.target = '_blank';
            newDiscordBtn.rel = 'noopener noreferrer';
            newDiscordBtn.id = 'discord-link-btn';
            newDiscordBtn.innerText = 'Contact on Discord';
            playButton.parentElement.appendChild(newDiscordBtn);
        }
    }


    slct.appendChild(tabsContainer);
    slct.appendChild(selectionContent);
    slct.appendChild(utilityContent);

    autoPerkSystem.init(utilityContent);
    utilitySystem.init(utilityContent);

    tabsContainer.addEventListener('click', (e) => {
        if (e.target.matches('.main-tab-btn')) {
            const tabId = e.target.dataset.tab;

            tabsContainer.querySelectorAll('.main-tab-btn').forEach(btn => btn.classList.remove('active'));
            e.target.classList.add('active');

            slct.querySelectorAll('.main-tab-content').forEach(content => content.classList.remove('active'));
            document.getElementById(`${tabId}-tab-content`).classList.add('active');
        }
    });
}


initializeTheme();
const modInterval = setInterval(initGameModifications, 100);
if (config.perkGUI.enabled) {
    setInterval(() => perkGUI.update(), 200);
}

})();