Lurkers.io, fly hack, weapon stats hack, teammate grief

Fly, modify weapon stats, such as: reload time, fire rate, entity fired, fire speed, infinite ammo etc

// ==UserScript==
// @name         Lurkers.io, fly hack, weapon stats hack, teammate grief
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Fly, modify weapon stats, such as: reload time, fire rate, entity fired, fire speed, infinite ammo etc
// @author       TENTACLES
// @match        https://lurkers.io/*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    let originalXg = null;
    let guiCreated = false;
    let gameContext = null;
    let lastPlayerState = null;
    let lastPlayerId = null;
    let originalPeerId = null; // For spectator mode toggle
    let playerSettings = {
        flyMode: false,
        weaponMods: {} // Will store settings for each weapon slot
    };

    // Game entity types for weapon customization
    const entityTypes = [
        "Marker", "Flag", "RectanglePhysicalEntity", "Prop", "Vehicle", "Living", 
        "CollapsingBlock", "Nail", "Item", "ItemSpawn", "Projectile", "Ladder", 
        "Shop", "Chest", "GunTurret", "Door", "Tunnel", "Zombie", "Animal", 
        "Human", "Pellet", "Snowball", "Bullet", "Arrow", "Explosive", 
        "SupplyCrate", "TrapDoor", "IronDoor", "CrabZombie", "FastZombie", 
        "BigZombie", "Wolf", "Fox", "Fish", "Deer", "Boar", "Sheep", "Trader", 
        "Bergobrine", "ThrowableWeapon", "Grenade", "IronTrapDoor", "ExplosiveZombie", 
        "DaddyZombie", "GrenadeLauncherGrenade", "TNT", "Rocket", "PumpkinLauncherGrenade", "HomingMissile"
    ];

    // Function to find and proxy _xg
    function findAndProxyXg() {
        for (let prop in window) {
            try {
                if (window[prop] && typeof window[prop] === 'object' && window[prop]._xg) {
                    console.log('Found _xg function:', window[prop]._xg);
                    
                    // Store original function and its context
                    originalXg = window[prop]._xg;
                    gameContext = window[prop];
                    
                    // Display the original function contents using toString()
                    console.log('Original _xg function contents:', originalXg.toString());
                    
                    // Get all available variables in the context
                    console.log('Available variables in game context:', Object.keys(window[prop]));
                    
                    // Proxy the function
                    window[prop]._xg = function(b, c) {
                        // Log arguments passed to the function
                        console.log('Arguments passed to _xg:', b, c);
                        
                        // Set up global getPlayer function
                        window.getPlayer = () => {
                            try {
                                // From the original function, we can see it uses V2f and YUi
                                if (typeof gameContext.V2f !== 'undefined' && 
                                    typeof gameContext.YUi !== 'undefined' && 
                                    typeof gameContext.ltf !== 'undefined' && 
                                    typeof gameContext.etf !== 'undefined') {
                                    
                                    console.log('Using game variables for player access');
                                    return gameContext.ltf(gameContext.etf(gameContext.V2f, 1), gameContext.YUi, 1, 5, [c])[0];
                                } else {
                                    // Try with original variables from the function body
                                    console.log('Attempting to get player with variables from context');
                                    // Loop through all properties to find the player
                                    if (c && c.sb) {
                                        console.log('Found player candidate with sb property:', c);
                                        return c;
                                    }
                                    console.log('Could not find player in context');
                                    return null;
                                }
                            } catch (e) {
                                console.error('Error getting player:', e);
                                console.log('Dumping context variables for debugging:');
                                for (let key in gameContext) {
                                    try {
                                        if (typeof gameContext[key] === 'function') {
                                            console.log(`${key}: [Function]`);
                                        } else if (gameContext[key] !== null && typeof gameContext[key] === 'object') {
                                            console.log(`${key}: [Object]`);
                                        } else {
                                            console.log(`${key}: ${gameContext[key]}`);
                                        }
                                    } catch (err) {
                                        console.log(`Error accessing ${key}: ${err.message}`);
                                    }
                                }
                                return null;
                            }
                        };
                        
                        // Create GUI if not already created
                        if (!guiCreated) {
                            createCheatGUI();
                            guiCreated = true;
                        }
                        
                        // Check for player respawn (death and coming back to life)
                        const player = window.getPlayer();
                        if (player) {
                            // Store the player's peer ID for spectator mode toggle
                            if (!originalPeerId && player.R) {
                                originalPeerId = player.R;
                                console.log('Saved original peer ID:', originalPeerId);
                            }
                            
                            const currentPlayerId = player.sb;
                            
                            // Check if this is a new player (respawn or first spawn)
                            if (lastPlayerId !== currentPlayerId) {
                                console.log('Player ID changed, possible respawn detected:', lastPlayerId, '->', currentPlayerId);
                                lastPlayerId = currentPlayerId;
                                
                                // Wait a short time for player to fully initialize after respawn
                                setTimeout(reapplyPlayerSettings, 500);
                            }
                            
                            // Store current player state for future comparison
                            lastPlayerState = {
                                id: player.sb,
                                health: player.Fb // Assuming Fb is health, adjust if needed
                            };
                        }
                        
                        // Call original function with original context
                        return originalXg.call(gameContext, b, c);
                    };
                    
                    console.log('Successfully proxied _xg function');
                    return true;
                }
            } catch (e) {
                // Ignore errors when checking properties
            }
        }
        return false;
    }

    // Function to toggle spectator mode
    window.toggleSpectatorMode = function(enabled) {
        try {
            const player = window.getPlayer();
            if (!player) {
                console.error('Player not available');
                return false;
            }
            
            if (enabled) {
                // Switch to spectator mode
                if (player.R) {
                    // Save current ID if not saved already
                    if (!originalPeerId) {
                        originalPeerId = player.R;
                    }
                    // Set to undefined to enter spectator mode
                    player.R = undefined;
                    console.log('Switched to spectator mode');
                    return true;
                }
            } else {
                // Return to player mode
                if (originalPeerId) {
                    player.R = originalPeerId;
                    console.log('Returned to player mode, restored ID:', originalPeerId);
                    return true;
                } else {
                    console.error('Original peer ID not found, cannot restore player mode');
                }
            }
            return false;
        } catch (e) {
            console.error('Error toggling spectator mode:', e);
            return false;
        }
    };

    // Function to change weapon entity type
    window.changeWeaponEntity = function(slotIndex, entityType) {
        try {
            const player = window.getPlayer();
            if (!player || !player.tb || !player.tb.b || !player.tb.b[slotIndex] || !player.tb.b[slotIndex].c) {
                console.error('Weapon not available in slot', slotIndex);
                return false;
            }
            
            // Set the entity type
            player.tb.b[slotIndex].c.f = entityType;
            console.log(`Changed weapon entity in slot ${slotIndex} to:`, entityType);
            
            // Save this setting
            if (!playerSettings.weaponMods[slotIndex]) {
                playerSettings.weaponMods[slotIndex] = {};
            }
            playerSettings.weaponMods[slotIndex].entityType = entityType;
            
            return true;
        } catch (e) {
            console.error('Error changing weapon entity:', e);
            return false;
        }
    };

    // Function to reapply all player settings after respawn
    function reapplyPlayerSettings() {
        try {
            const player = window.getPlayer();
            if (!player) {
                console.log('Cannot reapply settings - player not available');
                return;
            }
            
            console.log('Reapplying player settings after respawn');
            
            // Reapply fly mode if it was enabled
            if (playerSettings.flyMode) {
                player.P = true;
                console.log('Reapplied fly mode');
                
                // Update UI to match
                const flyToggle = document.getElementById('fly-toggle');
                if (flyToggle) flyToggle.checked = true;
            }
            
            // Reapply weapon modifications
            if (player.tb && player.tb.b) {
                for (let slotIndex in playerSettings.weaponMods) {
                    const slotMods = playerSettings.weaponMods[slotIndex];
                    const slot = parseInt(slotIndex, 10);
                    
                    // Check if this slot exists in the current inventory
                    if (player.tb.b[slot] && player.tb.b[slot].c) {
                        // Apply the saved modifications
                        player.tb.b[slot].c.w = slotMods.fireRate;
                        player.tb.b[slot].c.e = slotMods.projectiles;
                        player.tb.b[slot].c.G = slotMods.speed;
                        player.tb.b[slot].c.R = !slotMods.infiniteAmmo;
                        player.tb.b[slot].c.t = slotMods.autoFire;
                        player.tb.b[slot].c.a = slotMods.knockback;
                        player.tb.b[slot].c.j = slotMods.spread;
                        
                        // Apply entity type if saved
                        if (slotMods.entityType) {
                            player.tb.b[slot].c.f = slotMods.entityType;
                        }
                        
                        console.log(`Reapplied weapon mods to slot ${slot}:`, slotMods);
                    }
                }
            }
            
            // Refresh the inventory display
            refreshInventory();
            
        } catch (e) {
            console.error('Error reapplying player settings:', e);
        }
    }

    // Create the cheat GUI
    function createCheatGUI() {
        // Create main container
        const gui = document.createElement('div');
        gui.id = 'cheat-gui';
        gui.style.cssText = `
            position: fixed;
            top: 10px;
            right: 10px;
            width: 350px;
            max-height: 80vh;
            background: rgba(0, 0, 0, 0.9);
            border: 2px solid #333;
            border-radius: 8px;
            color: white;
            font-family: Arial, sans-serif;
            font-size: 12px;
            z-index: 10000;
            overflow-y: auto;
            display: none;
        `;

        // Create header
        const header = document.createElement('div');
        header.style.cssText = `
            background: #333;
            padding: 10px;
            cursor: move;
            user-select: none;
            display: flex;
            justify-content: space-between;
            align-items: center;
        `;
        header.innerHTML = `
            <span>Game Cheat Menu</span>
            <button id="close-gui" style="background: #f44; border: none; color: white; padding: 2px 6px; cursor: pointer;">×</button>
        `;

        // Create content area
        const content = document.createElement('div');
        content.style.padding = '10px';

        // Player controls section
        const playerSection = document.createElement('div');
        playerSection.innerHTML = `
            <h3 style="margin: 0 0 10px 0; color: #4CAF50;">Player Controls</h3>
            <label style="display: flex; align-items: center; margin-bottom: 10px;">
                <input type="checkbox" id="fly-toggle" style="margin-right: 8px;">
                Enable Fly Mode
            </label>
            <label style="display: flex; align-items: center; margin-bottom: 10px;">
                <input type="checkbox" id="spectator-toggle" style="margin-right: 8px;">
                Spectator Team
            </label>
        `;

        // Inventory section
        const inventorySection = document.createElement('div');
        inventorySection.id = 'inventory-section';
        inventorySection.innerHTML = `
            <h3 style="margin: 20px 0 10px 0; color: #4CAF50;">Inventory (Active Items)</h3>
            <div id="inventory-slots-container"></div>
        `;

        // Manual refresh button
        const refreshBtn = document.createElement('button');
        refreshBtn.textContent = 'Refresh Inventory';
        refreshBtn.style.cssText = `
            background: #2196F3;
            color: white;
            border: none;
            padding: 8px 16px;
            cursor: pointer;
            border-radius: 4px;
            width: 100%;
            margin-top: 10px;
        `;
        refreshBtn.onclick = refreshInventory;

        // Assemble GUI
        gui.appendChild(header);
        content.appendChild(playerSection);
        content.appendChild(inventorySection);
        content.appendChild(refreshBtn);
        gui.appendChild(content);
        document.body.appendChild(gui);

        // Add toggle button
        const toggleBtn = document.createElement('button');
        toggleBtn.textContent = 'Cheats';
        toggleBtn.style.cssText = `
            position: fixed;
            top: 10px;
            right: 10px;
            background: #4CAF50;
            color: white;
            border: none;
            padding: 8px 12px;
            cursor: pointer;
            border-radius: 4px;
            z-index: 10001;
            font-size: 12px;
        `;
        toggleBtn.onclick = () => {
            if (gui.style.display === 'none') {
                gui.style.display = 'block';
                toggleBtn.style.display = 'none';
            }
        };
        document.body.appendChild(toggleBtn);

        // Event listeners
        document.getElementById('close-gui').onclick = () => {
            gui.style.display = 'none';
            toggleBtn.style.display = 'block';
        };

        document.getElementById('fly-toggle').onchange = function() {
            try {
                if (window.getPlayer && window.getPlayer()) {
                    window.getPlayer().P = this.checked;
                    
                    // Save the setting for respawn
                    playerSettings.flyMode = this.checked;
                    
                    console.log('Fly mode:', this.checked ? 'enabled' : 'disabled');
                } else {
                    console.warn('Player not available, try again later');
                    this.checked = !this.checked; // Revert toggle
                }
            } catch (e) {
                console.error('Error toggling fly mode:', e);
                this.checked = !this.checked; // Revert toggle
            }
        };

        // Spectator mode toggle
        document.getElementById('spectator-toggle').onchange = function() {
            try {
                const success = window.toggleSpectatorMode(this.checked);
                if (!success) {
                    this.checked = !this.checked; // Revert if failed
                }
            } catch (e) {
                console.error('Error toggling spectator mode:', e);
                this.checked = !this.checked; // Revert toggle
            }
        };

        // Make GUI draggable
        let isDragging = false;
        let dragOffset = { x: 0, y: 0 };

        header.onmousedown = function(e) {
            isDragging = true;
            dragOffset.x = e.clientX - gui.offsetLeft;
            dragOffset.y = e.clientY - gui.offsetTop;
        };

        document.onmousemove = function(e) {
            if (isDragging) {
                gui.style.left = (e.clientX - dragOffset.x) + 'px';
                gui.style.top = (e.clientY - dragOffset.y) + 'px';
                gui.style.right = 'auto';
            }
        };

        document.onmouseup = function() {
            isDragging = false;
        };

        console.log('Cheat GUI created successfully');
    }

    // Global function to apply weapon modifications
    window.applyWeaponMods = function(slotIndex) {
        try {
            if (!window.getPlayer) {
                console.error('getPlayer function not available');
                return;
            }

            const player = window.getPlayer();
            if (!player) {
                console.error('Player is null, make sure you are in game');
                return;
            }

            // Check if slot exists and has weapon data
            if (!player.tb || !player.tb.b || !player.tb.b[slotIndex]) {
                console.error('Invalid slot or player inventory not found');
                return;
            }

            if (!player.tb.b[slotIndex].c) {
                console.error('Weapon data not found in slot', slotIndex);
                return;
            }

            // Get values from inputs
            const fireRate = parseInt(document.getElementById(`fire-rate-${slotIndex}`).value);
            const projectiles = parseInt(document.getElementById(`projectiles-${slotIndex}`).value);
            const speed = parseFloat(document.getElementById(`speed-${slotIndex}`).value);
            const infiniteAmmo = document.getElementById(`infinite-ammo-${slotIndex}`).checked;
            const autoFire = document.getElementById(`auto-fire-${slotIndex}`).checked;
            const knockback = parseFloat(document.getElementById(`knockback-${slotIndex}`).value);
            const spread = parseFloat(document.getElementById(`spread-${slotIndex}`).value);
            const entityType = document.getElementById(`entity-type-${slotIndex}`).value;

            // Apply modifications directly using getPlayer() (get fresh reference each time)
            window.getPlayer().tb.b[slotIndex].c.w = fireRate;
            window.getPlayer().tb.b[slotIndex].c.e = projectiles;
            window.getPlayer().tb.b[slotIndex].c.G = speed;
            window.getPlayer().tb.b[slotIndex].c.R = !infiniteAmmo;
            window.getPlayer().tb.b[slotIndex].c.t = autoFire;
            window.getPlayer().tb.b[slotIndex].c.a = knockback;
            window.getPlayer().tb.b[slotIndex].c.j = spread;
            window.getPlayer().tb.b[slotIndex].c.f = entityType;

            // Save settings for respawn
            playerSettings.weaponMods[slotIndex] = {
                fireRate,
                projectiles,
                speed,
                infiniteAmmo,
                autoFire,
                knockback,
                spread,
                entityType
            };

            console.log(`Applied modifications to slot ${slotIndex + 1}:`, {
                fireRate,
                projectiles,
                speed,
                infiniteAmmo,
                autoFire,
                knockback,
                spread,
                entityType
            });
        } catch (e) {
            console.error('Error applying weapon modifications:', e);
        }
    };

    // Function to refresh inventory display
    function refreshInventory() {
        try {
            if (!window.getPlayer) {
                console.error('getPlayer function not available');
                return;
            }

            const player = window.getPlayer();
            if (!player) {
                console.error('Player is null, make sure you are in game');
                return;
            }

            if (!player.tb || !player.tb.b) {
                console.error('Player inventory not found');
                return;
            }

            const inventorySlotsContainer = document.getElementById('inventory-slots-container');
            if (!inventorySlotsContainer) {
                console.error('Inventory slots container not found');
                return;
            }

            // Clear previous inventory display
            inventorySlotsContainer.innerHTML = '';

            // Check for items in all slots (not just the first 9)
            const maxSlots = player.tb.b.length;
            let hasItems = false;

            for (let i = 0; i < maxSlots; i++) {
                // Get fresh player reference for each slot
                const currentPlayer = window.getPlayer();
                if (currentPlayer && currentPlayer.tb && currentPlayer.tb.b && 
                    currentPlayer.tb.b[i] && currentPlayer.tb.b[i].c && 
                    currentPlayer.tb.b[i].c.H) {
                    
                    hasItems = true;
                    const itemName = currentPlayer.tb.b[i].c.H;
                    const currentEntityType = currentPlayer.tb.b[i].c.f || "Bullet";
                    
                    // Create slot div
                    const slotDiv = document.createElement('div');
                    slotDiv.style.cssText = `
                        border: 1px solid #555;
                        margin-bottom: 10px;
                        padding: 8px;
                        border-radius: 4px;
                        background: rgba(50, 50, 50, 0.6);
                    `;
                    
                    // Create entity type dropdown options
                    let entityOptions = '';
                    entityTypes.forEach(entity => {
                        const selected = entity === currentEntityType ? 'selected' : '';
                        entityOptions += `<option value="${entity}" ${selected}>${entity}</option>`;
                    });
                    
                    slotDiv.innerHTML = `
                        <div style="margin-bottom: 5px;">
                            <strong>Slot ${i + 1}: <span id="item-name-${i}">${itemName}</span></strong>
                        </div>
                        <div style="margin-bottom: 10px;">
                            <label>Entity Type:
                                <select id="entity-type-${i}" style="width: 150px; margin-left: 5px;">
                                    ${entityOptions}
                                </select>
                            </label>
                        </div>
                        <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 5px; margin-bottom: 5px;">
                            <label>Fire Rate (ms):
                                <input type="number" id="fire-rate-${i}" value="${currentPlayer.tb.b[i].c.w || 100}" min="1" style="width: 60px; margin-left: 5px;">
                            </label>
                            <label>Projectiles:
                                <input type="number" id="projectiles-${i}" value="${currentPlayer.tb.b[i].c.e || 1}" min="1" style="width: 60px; margin-left: 5px;">
                            </label>
                        </div>
                        <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 5px; margin-bottom: 5px;">
                            <label>Speed Multiplier:
                                <input type="number" id="speed-${i}" value="${currentPlayer.tb.b[i].c.G || 1}" min="0.1" step="0.1" style="width: 60px; margin-left: 5px;">
                            </label>
                            <div>
                                <label style="display: flex; align-items: center;">
                                    <input type="checkbox" id="infinite-ammo-${i}" ${currentPlayer.tb.b[i].c.R === false ? 'checked' : ''} style="margin-right: 5px;">
                                    Infinite Ammo
                                </label>
                            </div>
                        </div>
                        <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 5px; margin-bottom: 5px;">
                            <label>Knockback (Recoil):
                                <input type="number" id="knockback-${i}" value="${currentPlayer.tb.b[i].c.a || 1}" min="0" step="0.1" style="width: 60px; margin-left: 5px;">
                            </label>
                            <label>Spread:
                                <input type="number" id="spread-${i}" value="${currentPlayer.tb.b[i].c.j || 0}" min="0" step="0.1" style="width: 60px; margin-left: 5px;">
                            </label>
                        </div>
                        <div style="margin-bottom: 5px;">
                            <label style="display: flex; align-items: center;">
                                <input type="checkbox" id="auto-fire-${i}" ${currentPlayer.tb.b[i].c.t ? 'checked' : ''} style="margin-right: 5px;">
                                Auto Fire
                            </label>
                        </div>
                        <button onclick="applyWeaponMods(${i})" style="background: #4CAF50; color: white; border: none; padding: 4px 8px; cursor: pointer; border-radius: 3px; width: 100%;">
                            Apply Modifications
                        </button>
                    `;
                    
                    inventorySlotsContainer.appendChild(slotDiv);
                }
            }

            if (!hasItems) {
                inventorySlotsContainer.innerHTML = '<div style="color: #999; text-align: center; padding: 10px;">No items in inventory</div>';
            }
        } catch (e) {
            console.error('Error refreshing inventory:', e);
        }
    }

    // Try to find _xg immediately
    if (!findAndProxyXg()) {
        // If not found, keep trying every second
        const interval = setInterval(() => {
            if (findAndProxyXg()) {
                clearInterval(interval);
            }
        }, 1000);
    }

    console.log('Game Cheat Script loaded');
})();