// ==UserScript==
// @name         ZTweak - ZType Mod Menu
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Mod Menu with various mods
// @author       YSSF
// @match        https://zty.pe/*
// @grant        none
// ==/UserScript==

(() => {
    'use strict';

    // Create the menu container
    const menu = document.createElement('div');
    menu.id = 'custom-debug-menu';
    menu.innerHTML = `
        <div id="debug-menu-header">
            <span title="Made by YSSF">
                <span id="header-name">ZTweak</span>
                <span>(<span id="header-counted">0</span>/<span id="header-limit">0</span>)</span>
            </span>
            <button id="debug-menu-toggle" title="Minimize">−</button>
        </div>
        <div id="debug-menu-content">
            <label class="switch" title="Ships will crash upon contact, but you will remain unscathed">
                <input type="checkbox" id="invincible">
                <span class="slider"></span>
                <span class="label-text">Invincible</span>
            </label>
            <label class="switch" title="Gives you unlimited EMPs">
                <input type="checkbox" id="unlimitedEmps">
                <span class="slider"></span>
                <span class="label-text">Unlimited EMPs</span>
            </label>
            <label class="switch" title="Automatically shoots enemies">
                <input type="checkbox" id="autoShoot">
                <span class="slider"></span>
                <span class="label-text">Auto-Shoot</span>
            </label>
            <label class="switch" title="Allows you to move freely using arrow keys">
                <input type="checkbox" id="moveFreely">
                <span class="slider"></span>
                <span class="label-text">Free Movement</span>
            </label>
            <label class="switch" title="Freezing temperatures can immobilize ships, providing an opportunity for thinking or a break">
                <input type="checkbox" id="freezeShips">
                <span class="slider"></span>
                <span class="label-text">Freeze Ships</span>
            </label>
            <label class="switch" title="A red circle is drawn around the player, which triggers an automatic EMP usage when a ship enters it">
                <input type="checkbox" id="autoEmp">
                <span class="slider"></span>
                <span class="label-text">Auto-EMP</span>
            </label>
            <label class="switch" title="An ESP to show the distance between the player and the enemies">
                <input type="checkbox" id="esp">
                <span class="slider"></span>
                <span class="label-text">ESP</span>
            </label>
        </div>
    `;
    document.body.appendChild(menu);

    let empsInterval;
    let backupKill;
    let autoShootInterval;
    let originalPlayerUpdate;
    let playerMovementsTimeout;
    let originalPlayerDraw;
    let autoEmpTimeout;

    let mods = {
        unlimitedEmps() {
            empsInterval = setInterval(() => {
                ig.game.emps = 3;
            }, 100);
        },
        __unlimitedEmps() {
            clearInterval(empsInterval);
        },
        invincible() {
            backupKill = EntityPlayer.prototype.kill;
            EntityPlayer.prototype.kill = () => {};
        },
        __invincible() {
            EntityPlayer.prototype.kill = backupKill;
        },
        autoShoot() {
            autoShootEnemies();

            autoShootInterval = setInterval(() => {
                autoShootEnemies();
            }, 1000);
        },
        __autoShoot() {
            clearInterval(autoShootInterval);
        },
        moveFreely() {
            playerMovements();
        },
        __moveFreely() {
            removePlayerUpdateMod('moveFreelyMod');
        },
        freezeShips() {
            // Store the original update method of EntityEnemy
            this.originalUpdate = EntityEnemy.prototype.update;

            // Override the update method of EntityEnemy to prevent movement
            EntityEnemy.prototype.update = function () {
                // Skip movement updates by not calling the original update method
                if (this.currentAnim) {
                    this.currentAnim.update();
                }
            };

            // Stop all enemy movement
            let entities = ig.game.entities;
            for (let i = 0; i < entities.length; i++) {
                let ent = entities[i];
                if (ent instanceof EntityEnemy) {
                    ent.vel.x = 0;
                    ent.vel.y = 0;
                }
            }
        },
        __freezeShips() {
            // Restore the original update method to allow movement again
            EntityEnemy.prototype.update = this.originalUpdate;

            // Allow all enemies to resume movement
            let entities = ig.game.entities;
            for (let i = 0; i < entities.length; i++) {
                let ent = entities[i];
                if (ent instanceof EntityEnemy) {
                    ent.vel.x = ent.originalVel.x;
                    ent.vel.y = ent.originalVel.y;
                }
            }
        },
        autoEmp() {
            setupAutoEmp();
        },
        __autoEmp() {
            removePlayerUpdateMod('autoEmpMod');
            removePlayerDrawMod('autoEmpDrawMod');
        },
        esp() {
            function initGameModSystem() {
                if (typeof ig === 'undefined' || !ig.game) {
                    setTimeout(initGameModSystem, 100);
                    return;
                }

                if (!ig.game._drawMods) {
                    ig.game._drawMods = [];
                    ig.game._originalDraw = ig.game.draw;

                    ig.game.draw = function() {
                        // Call the original draw method
                        this._originalDraw();

                        // Call all draw mods
                        for (let i = 0; i < this._drawMods.length; i++) {
                            this._drawMods[i].call(this);
                        }
                    };
                }
            }

            initGameModSystem();

            function espDrawMod() {
                // Get the drawing context
                let ctx = ig.system.context;

                // Save the current state of the context
                ctx.save();

                // Set the drawing styles
                ctx.strokeStyle = '#ffcc3a'; // Line and rectangle color
                ctx.fillStyle = '#ffcc3a';   // Text color
                ctx.lineWidth = 1;           // Line width

                // Reference to the player
                let player = this.player;
                if (!player) {
                    console.error('Player entity not found.');
                    ctx.restore();
                    return;
                }

                // Player position on screen
                let px = player.pos.x - this._rscreen.x;
                let py = player.pos.y - this._rscreen.y;

                // Iterate over all entities in the game
                for(let i = 0; i < this.entities.length; i++) {
                    let ent = this.entities[i];

                    // Check if the entity is an enemy (type B)
                    if(ent.type === ig.Entity.TYPE.B) {
                        // Calculate the enemy's position on the screen
                        let ex = ent.pos.x - this._rscreen.x;
                        let ey = ent.pos.y - this._rscreen.y;

                        // Draw a line from the player to the enemy
                        ctx.beginPath();
                        ctx.moveTo(px + player.size.x / 2, py + player.size.y / 2);
                        ctx.lineTo(ex + ent.size.x / 2, ey + ent.size.y / 2);
                        ctx.stroke();

                        // Draw a rectangle around the enemy
                        ctx.strokeRect(ex, ey, ent.size.x, ent.size.y);

                        // Calculate the distance between the player and the enemy
                        let dx = ent.pos.x - player.pos.x;
                        let dy = ent.pos.y - player.pos.y;
                        let distance = Math.sqrt(dx * dx + dy * dy);

                        // Display the distance in cm at the bottom right corner of the rectangle
                        let size = 10;
                        let text = distance.toFixed(2) + 'cm';
                        ctx.font = `${size}px Arial`;
                        ctx.textBaseline = 'bottom';
                        ctx.textAlign = 'right';
                        ctx.fillText(text, ex + ent.size.x, ey + ent.size.y - size);
                    }
                }

                // Restore the context to its original state
                ctx.restore();
            }

            function waitForGameReady() {
                if (ig && ig.game && ig.game._drawMods) {
                    // Add the mod function to ig.game._drawMods
                    ig.game._drawMods.push(espDrawMod);

                    mods.espDrawMod = espDrawMod; // Save reference for removal
                } else {
                    setTimeout(waitForGameReady, 100);
                }
            }

            waitForGameReady();
        },
        __esp() {
            if (ig && ig.game && ig.game._drawMods && mods.espDrawMod) {
                let index = ig.game._drawMods.indexOf(mods.espDrawMod);
                if (index > -1) {
                    ig.game._drawMods.splice(index, 1);
                }
                mods.espDrawMod = null;
            }
        }
    };

    function getAllEnemyWords() {
        let enemies = [];
        for (let i = 0; i < ig.game.entities.length; i++) {
            let ent = ig.game.entities[i];
            if (ent instanceof EntityEnemy && !ent._killed) {
                enemies.push({
                    entity: ent,
                    word: ent.remainingWord
                });
            }
        }
        return enemies;
    }

    function autoShootEnemies() {
        let enemies = getAllEnemyWords();
        for (let i = 0; i < enemies.length; i++) {
            let word = enemies[i].word;
            for (let j = 0; j < word.length; j++) {
                let letter = word[j];
                ig.game.bufferedLetters.push(letter);
            }
        }

        ig.game.shootBufferedLetters();
    }

    // Utility function to initialize the mod system for update and draw methods
    function initPlayerModSystem() {
        if (ig && ig.game && ig.game.player) {
            let player = ig.game.player;

            // Initialize update mods
            if (!player._updateMods) {
                player._updateMods = [];
                player._originalUpdate = player.update;

                player.update = function() {
                    // Call the original update method
                    this._originalUpdate();

                    // Call all update mods
                    for (let i = 0; i < this._updateMods.length; i++) {
                        this._updateMods[i].call(this);
                    }
                };
            }

            // Initialize draw mods
            if (!player._drawMods) {
                player._drawMods = [];
                player._originalDraw = player.draw;

                player.draw = function() {
                    // Call the original draw method
                    this._originalDraw();

                    // Call all draw mods
                    for (let i = 0; i < this._drawMods.length; i++) {
                        this._drawMods[i].call(this);
                    }
                };
            }
        } else {
            setTimeout(initPlayerModSystem, 100);
        }
    }

    // Call the initialization function
    initPlayerModSystem();

    function playerMovements() {
        if (ig && ig.game && ig.game.player) {
            let player = ig.game.player;

            // Add the move freely mod to the update mods
            player._updateMods.push(function moveFreelyMod() {
                // Movement speed
                let speed = 200;

                // Check for movement input
                if (ig.input.state('left')) {
                    this.pos.x -= speed * ig.system.tick;
                }
                if (ig.input.state('right')) {
                    this.pos.x += speed * ig.system.tick;
                }
                if (ig.input.state('up')) {
                    this.pos.y -= speed * ig.system.tick;
                }
                if (ig.input.state('down')) {
                    this.pos.y += speed * ig.system.tick;
                }

                // Prevent the player from moving off-screen
                this.pos.x = this.pos.x.limit(0, ig.system.width - this.size.x);
                let maxY = ig.system.height - this.size.y;
                if (ig.game.keyboard && ig.game.keyboard.height && ig.game.keyboard.drawScale) {
                    maxY -= ig.game.keyboard.height * ig.game.keyboard.drawScale;
                }
                this.pos.y = this.pos.y.limit(0, maxY);
            });

            // Save reference to the mod function for removal
            mods.moveFreelyMod = player._updateMods[player._updateMods.length - 1];
        }
    }

    let autoEmpRadius = 100;

    function setupAutoEmp() {
        if (ig && ig.game && ig.game.player) {
            let player = ig.game.player;

            // Add the auto-EMP mod to the update mods
            player._updateMods.push(function autoEmpMod() {
                // Initialize empActivated flag if not present
                if (typeof this.empActivated === 'undefined') {
                    this.empActivated = false;
                }

                // Check if we have any EMPs left
                if (ig.game.emps > 0) {
                    // Get all entities (enemies) in the game
                    let entities = ig.game.entities;

                    // Get the player's position
                    let playerPos = {
                        x: this.pos.x + this.size.x / 2,
                        y: this.pos.y + this.size.y / 2
                    };

                    // Flag to check if any enemy is in radius
                    let enemyInRadius = false;

                    // Define the radius using the shared variable
                    let radius = autoEmpRadius;

                    // Loop through all entities
                    for (let i = 0; i < entities.length; i++) {
                        let ent = entities[i];
                        // Check if it's an enemy entity
                        if (ent instanceof EntityEnemy) {
                            // Calculate the distance to the enemy
                            let enemyPos = {
                                x: ent.pos.x + ent.size.x / 2,
                                y: ent.pos.y + ent.size.y / 2
                            };
                            let dx = enemyPos.x - playerPos.x;
                            let dy = enemyPos.y - playerPos.y;
                            let distance = Math.sqrt(dx * dx + dy * dy);

                            // If the enemy is within the radius
                            if (distance <= radius) {
                                enemyInRadius = true;
                                if (!this.empActivated) {
                                    // Activate EMP
                                    this.spawnEMP();
                                    // Set the flag to prevent further EMPs until enemy is no longer in radius
                                    this.empActivated = true;
                                }
                                // Exit the loop after detecting the first enemy in radius
                                break;
                            }
                        }
                    }

                    // If no enemy is in radius, reset empActivated flag
                    if (!enemyInRadius) {
                        this.empActivated = false;
                    }
                } else {
                    // Reset the flag if no EMPs are left
                    this.empActivated = false;
                }
            });

            // Save reference to the mod function for removal
            mods.autoEmpMod = player._updateMods[player._updateMods.length - 1];

            // Add the circle drawing mod to the draw mods
            player._drawMods.push(function autoEmpDrawMod() {
                // Get the canvas context
                let ctx = ig.system.context;

                // Save the current drawing state
                ctx.save();

                // Set the outline style
                ctx.strokeStyle = '#ffcc3a';
                ctx.lineWidth = 2;

                // Calculate the player's center position on the screen
                let x = this.pos.x - ig.game._rscreen.x + this.size.x / 2;
                let y = this.pos.y - ig.game._rscreen.y + this.size.y / 2;

                // Use the shared radius variable
                let radius = autoEmpRadius;

                // Draw a circle around the player
                ctx.beginPath();
                ctx.arc(x, y, radius, 0, 2 * Math.PI);
                ctx.stroke();

                // Restore the previous drawing state
                ctx.restore();
            });

            // Save reference to the draw mod function for removal
            mods.autoEmpDrawMod = player._drawMods[player._drawMods.length - 1];

        } else {
            // If player is not yet available, try again shortly
            setTimeout(setupAutoEmp, 100);
        }
    }

    // Function to remove a mod from update mods
    function removePlayerUpdateMod(modName) {
        if (ig && ig.game && ig.game.player && mods[modName]) {
            let player = ig.game.player;
            let index = player._updateMods.indexOf(mods[modName]);
            if (index > -1) {
                player._updateMods.splice(index, 1);
            }

            delete mods[modName];
        }
    }

    // Function to remove a mod from draw mods
    function removePlayerDrawMod(modName) {
        if (ig && ig.game && ig.game.player && mods[modName]) {
            let player = ig.game.player;
            let index = player._drawMods.indexOf(mods[modName]);
            if (index > -1) {
                player._drawMods.splice(index, 1);
            }

            delete mods[modName];
        }
    }

    const menuHeader = menu.querySelector('#debug-menu-header');
    const headerCounted = menuHeader.querySelector('#header-counted');
    const headerLimit = menuHeader.querySelector('#header-limit');

    const checkboxes = menu.querySelectorAll('.switch input');

    headerLimit.innerText = checkboxes.length;

    // Function to update the count of enabled checkboxes
    function updateCheckedCount() {
        const checkedCount = Array.from(checkboxes).filter(checkbox => checkbox.checked).length;
        headerCounted.innerText = checkedCount;
    };

    // Initialize the count on page load
    updateCheckedCount();

    checkboxes.forEach(checkbox => {
        checkbox.addEventListener('change', () => {
            if (checkbox.checked) {
                mods[checkbox.id]();
            } else {
                mods[`__${checkbox.id}`]();
            }
            updateCheckedCount();
        });
    });

    // Add styles
    const styles = document.createElement('style');
    styles.innerHTML = `
        #custom-debug-menu {
            position: fixed;
            top: 100px;
            left: 100px;
            width: 200px;
            background-color: #333;
            color: #fff;
            border: 1px solid #555;
            z-index: 9999999;
            box-shadow: 0 2px 10px rgba(0,0,0,0.2);
            border-radius: 8px;
            overflow: hidden;
            user-select: none;
            font-family: Arial, sans-serif;
        }
        #debug-menu-header {
            background-color: #444;
            color: #fff;
            padding: 10px;
            cursor: move;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        #debug-menu-header span {
            font-weight: bold;
        }
        #debug-menu-header button {
            background: none;
            color: #fff;
            border: none;
            font-size: 18px;
            cursor: pointer;
        }
        #debug-menu-content {
            padding: 10px;
            overflow: hidden;
            transition: max-height 0.3s ease, opacity 0.3s ease, padding 0.3s ease;
            max-height: 1000px;
            opacity: 1;
        }
        .switch {
            display: flex;
            align-items: center;
            margin-bottom: 10px;
        }
        .switch:last-child {
            margin-bottom: 0;
        }
        .switch input {
            display: none;
        }
        .slider {
            position: relative;
            width: 40px;
            height: 20px;
            background-color: #666;
            border-radius: 20px;
            margin-right: 10px;
            transition: background-color 0.3s;
            cursor: pointer;
        }
        .slider::before {
            content: '';
            position: absolute;
            width: 16px;
            height: 16px;
            left: 2px;
            top: 2px;
            background-color: #fff;
            border-radius: 50%;
            transition: transform 0.3s;
        }
        input:checked + .slider {
            background-color: #2196F3;
        }
        input:checked + .slider::before {
            transform: translateX(20px);
        }
        .label-text {
            flex-grow: 1;
            color: #fff;
        }
    `;
    document.head.appendChild(styles);

    // Make the menu draggable
    dragElement(menu);

    function dragElement(el) {
        const header = document.getElementById('debug-menu-header');
        let posX = 0, posY = 0, mouseX = 0, mouseY = 0;
        if (header) {
            header.onmousedown = dragMouseDown;
        } else {
            el.onmousedown = dragMouseDown;
        }

        function dragMouseDown(e) {
            e = e || window.event;
            e.preventDefault();
            mouseX = e.clientX;
            mouseY = e.clientY;
            document.onmouseup = closeDragElement;
            document.onmousemove = elementDrag;
        }

        function elementDrag(e) {
            e = e || window.event;
            e.preventDefault();
            posX = mouseX - e.clientX;
            posY = mouseY - e.clientY;
            mouseX = e.clientX;
            mouseY = e.clientY;

            // Calculate new position
            let newTop = el.offsetTop - posY;
            let newLeft = el.offsetLeft - posX;

            // Get viewport dimensions
            const viewportWidth = window.innerWidth;
            const viewportHeight = window.innerHeight;

            // Limit the menu within the viewport
            if (newTop < 0) newTop = 0; // Top boundary
            if (newLeft < 0) newLeft = 0; // Left boundary
            if (newTop + el.offsetHeight > viewportHeight) {
                newTop = viewportHeight - el.offsetHeight; // Bottom boundary
            }
            if (newLeft + el.offsetWidth > viewportWidth) {
                newLeft = viewportWidth - el.offsetWidth; // Right boundary
            }

            // Set the new position
            el.style.top = newTop + 'px';
            el.style.left = newLeft + 'px';
        }

        function closeDragElement() {
            document.onmouseup = null;
            document.onmousemove = null;
        }
    }

    // Set initial maxHeight of content
    const content = document.getElementById('debug-menu-content');
    content.style.maxHeight = content.scrollHeight + 'px';

    // Minimize/Restore functionality with transitions
    const toggleButton = document.getElementById('debug-menu-toggle');
    let isMinimized = false;

    toggleButton.addEventListener('click', () => {
        if (isMinimized) {
            // Restore
            content.style.maxHeight = content.scrollHeight + 'px';
            content.style.opacity = '1';
            content.style.padding = '10px';
            toggleButton.innerHTML = '−';
            toggleButton.title = 'Minimize';
            isMinimized = false;
        } else {
            // Minimize
            content.style.maxHeight = '0px';
            content.style.opacity = '0';
            content.style.padding = '0px';
            toggleButton.innerHTML = '+';
            toggleButton.title = 'Restore';
            isMinimized = true;
        }
    });
})();

---

This text:
// Display the distance in cm at the bottom right corner of the rectangle
                        let size = 10;
                        let text = distance.toFixed(2) + 'cm';
                        ctx.font = `${size}px Arial`;
                        ctx.textBaseline = 'bottom';
                        ctx.textAlign = 'right';
                        ctx.fillText(text, ex + ent.size.x, ey + ent.size.y - size);

---

Should be on the top, right corner of the rectange, on top of the rectangle, outside of it