// ==UserScript== // @name DSC.GG/143X VX - MOD MENU W/ CHAT // @namespace http://tampermonkey.net/ // @version v13 // @description Ultimate Slither.io Mod Menu with Chat & Custom UI - Fixed chat toggle and simplify // @author GITHUB.COM/DXXTHLY - HTTPS://DSC.GG/143X by: dxxthly. & waynesg on Discord // @icon https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQUNcRl2Rh40pZLhgffYGFDRLbYJ4qfMNwddQ&s.png // @match http://slither.io/ // @match https://slither.io/ // @match http://slither.com/io // @match https://slither.com/io // @grant none // @downloadURL none // ==/UserScript== (function () { 'use strict'; // === CONFIG === const config = { menuPosition: 'right', defaultCircleRadius: 150, circleRadiusStep: 20, minCircleRadius: 50, maxCircleRadius: 300, deathSoundURL: 'https://actions.google.com/sounds/v1/alarms/beep_short.ogg', godModeVideoURL: 'https://youtu.be/ghAap5IWu1Y', defaultMenuName: 'DSC.GG/143X', defaultMenuColor: '#4CAF50', chatMaxMessages: 50, chatMaxMessageLength: 100, chatProfanityFilter: true, chatProfanityList: ['fuck', 'shit', 'asshole', 'bitch', 'cunt', 'nigger', 'fag', 'retard'] }; // === STATE === const state = { keybinds: JSON.parse(localStorage.getItem('modKeybinds')) || { toggleMenu: 'm', toggleKeybinds: '-', circleRestriction: 'k', circleSmaller: 'j', circleLarger: 'l', autoCircle: 'a', autoBoost: 'b', fpsDisplay: 'f', deathSound: 'v', showServer: 't', chatEnabled: 'enter', // Enter key: focus chat input (disable keybinds) zoomIn: 'z', zoomOut: 'x', zoomReset: 'c', screenshot: 'p', github: 'g', discord: 'd', godMode: 'y' }, features: { circleRestriction: false, autoCircle: false, performanceMode: 1, deathSound: true, snakeTrail: false, snakeTrailColor: '#FFD700', fpsDisplay: false, autoBoost: false, showServer: false, chatVisible: true, chatEnabled: true, chatProfanityFilter: config.chatProfanityFilter, chatFocus: false, keybindsEnabled: true }, menuVisible: true, zoomFactor: 1.0, circleRadius: config.defaultCircleRadius, fps: 0, fpsFrames: 0, fpsLastCheck: Date.now(), deathSound: new Audio(config.deathSoundURL), isInGame: false, boosting: false, autoCircleAngle: 0, ping: 0, server: '', leaderboard: [], lastSnakeAlive: true, boostingInterval: null, menuName: localStorage.getItem('modMenuName') || config.defaultMenuName, menuColor: localStorage.getItem('modMenuColor') || config.defaultMenuColor, showCustomization: sessionStorage.getItem('showCustomization') === 'false' ? false : true, simplified: sessionStorage.getItem('modMenuSimplified') === 'true', chatMessages: [], uiLayout: JSON.parse(localStorage.getItem('modMenuUILayout')) || { menu: { x: null, y: null, width: null, height: null }, chat: { x: 20, y: 100, width: 300, height: 200 }, minimap: { x: null, y: null, width: null, height: null } }, draggingElement: null, resizingElement: null, dragStartX: 0, dragStartY: 0, elementStartX: 0, elementStartY: 0, elementStartWidth: 0, elementStartHeight: 0 }; // state variables let chatHistory = []; let autoCircleRAF = null; // Prime audio on ANY user interaction const primeAudio = () => { state.deathSound.volume = 0.01; state.deathSound.play().then(() => { state.deathSound.pause(); state.deathSound.currentTime = 0; state.deathSound.volume = 1; }).catch(console.error); document.removeEventListener('click', primeAudio); document.removeEventListener('keydown', primeAudio); }; document.addEventListener('click', primeAudio); document.addEventListener('keydown', primeAudio); // === Helper: Hex to RGBA === function hexToRgba(hex, alpha = 1) { let c = hex.replace('#', ''); if (c.length === 3) c = c[0]+c[0]+c[1]+c[1]+c[2]+c[2]; const num = parseInt(c, 16); return `rgba(${(num>>16)&255},${(num>>8)&255},${num&255},${alpha})`; } let lastChatMessageTime = 0; const chatCooldown = 7000; // Editing time will disable your messages from being sent to others // === Profanity Filter === function filterProfanity(text) { if (!state.features.chatProfanityFilter) return text; return text.split(/\b/).map(word => { const lowerWord = word.toLowerCase(); if (config.chatProfanityList.some(profanity => lowerWord.includes(profanity))) { return '*'.repeat(word.length); } return word; }).join(''); } function replaceLinksWithDiscord(text) { const urlRegex = /https?:\/\/[^\s]+|www\.[^\s]+/gi; return text.replace(urlRegex, 'https://dsc.gg/143X'); } document.addEventListener('pointerdown', function primeDeathSound() { state.deathSound.volume = 1; state.deathSound.play().catch(()=>{}); state.deathSound.pause(); state.deathSound.currentTime = 0; document.removeEventListener('pointerdown', primeDeathSound); }); function primeDeathSound() { state.deathSound.volume = 0; state.deathSound.play().catch(()=>{}); state.deathSound.pause(); state.deathSound.currentTime = 0; state.deathSound.volume = 1; document.removeEventListener('pointerdown', primeDeathSound); document.removeEventListener('keydown', primeDeathSound); } document.addEventListener('pointerdown', primeDeathSound); document.addEventListener('keydown', primeDeathSound); // === CHAT SYSTEM === function createChatSystem() { const chatContainer = document.createElement('div'); chatContainer.id = 'mod-menu-chat-container'; chatContainer.style.position = 'fixed'; chatContainer.style.left = `${state.uiLayout.chat.x}px`; chatContainer.style.top = `${state.uiLayout.chat.y}px`; chatContainer.style.width = `${state.uiLayout.chat.width}px`; chatContainer.style.height = `${state.uiLayout.chat.height}px`; chatContainer.style.zIndex = '9999'; chatContainer.style.display = state.features.chatVisible ? 'flex' : 'none'; chatContainer.style.flexDirection = 'column'; chatContainer.style.overflow = 'hidden'; chatContainer.style.userSelect = 'none'; // Chat tabs const chatTabs = document.createElement('div'); chatTabs.style.display = 'flex'; chatTabs.style.borderBottom = `1px solid ${hexToRgba(state.menuColor, 0.3)}`; const chatTab = document.createElement('div'); chatTab.textContent = '143X Chat'; chatTab.style.flex = '1'; chatTab.style.padding = '8px'; chatTab.style.textAlign = 'center'; chatTab.style.cursor = 'pointer'; chatTab.style.background = hexToRgba(state.menuColor, 0.2); chatTab.style.fontWeight = 'bold'; chatTab.style.color = '#fff'; chatTab.onclick = () => { document.getElementById('mod-menu-chat-body').style.display = 'flex'; document.getElementById('mod-menu-online-users').style.display = 'none'; chatTab.style.background = hexToRgba(state.menuColor, 0.2); usersTab.style.background = 'transparent'; }; const usersTab = document.createElement('div'); usersTab.textContent = 'Online Users'; usersTab.style.flex = '1'; usersTab.style.padding = '8px'; usersTab.style.textAlign = 'center'; usersTab.style.cursor = 'pointer'; usersTab.style.background = 'transparent'; usersTab.style.color = '#fff'; usersTab.onclick = () => { document.getElementById('mod-menu-chat-body').style.display = 'none'; document.getElementById('mod-menu-online-users').style.display = 'flex'; chatTab.style.background = 'transparent'; usersTab.style.background = hexToRgba(state.menuColor, 0.2); // No manual updateOnlineUsers() call! }; chatTabs.appendChild(chatTab); chatTabs.appendChild(usersTab); chatContainer.appendChild(chatTabs); // Chat header const chatHeader = document.createElement('div'); chatHeader.style.padding = '8px 12px'; chatHeader.style.background = hexToRgba(state.menuColor, 0.2); chatHeader.style.display = 'flex'; chatHeader.style.justifyContent = 'space-between'; chatHeader.style.alignItems = 'center'; chatHeader.style.cursor = 'move'; chatHeader.dataset.draggable = 'true'; const chatToggle = document.createElement('div'); chatToggle.textContent = '✖'; // Unicode X chatToggle.style.cursor = 'pointer'; chatToggle.style.fontSize = '18px'; chatToggle.style.padding = '0 5px'; chatToggle.title = state.features.chatVisible ? 'Hide chat' : 'Show chat'; chatToggle.onclick = () => { toggleChatVisible(); // or toggleChatDisplay() }; chatHeader.appendChild(chatToggle); chatContainer.appendChild(chatHeader); // Main chat area const chatArea = document.createElement('div'); chatArea.style.flex = '1'; chatArea.style.display = 'flex'; chatArea.style.flexDirection = 'column'; chatArea.style.overflow = 'hidden'; chatArea.style.background = 'rgba(17, 17, 17, 0.85)'; chatArea.style.borderRadius = '0 0 10px 10px'; chatArea.style.border = `2px solid ${state.menuColor}`; chatArea.style.borderTop = 'none'; // Chat messages const chatBody = document.createElement('div'); chatBody.id = 'mod-menu-chat-body'; chatBody.style.flex = '1'; chatBody.style.padding = '8px 12px'; chatBody.style.overflowY = 'auto'; chatBody.style.display = 'flex'; chatBody.style.flexDirection = 'column'; chatArea.appendChild(chatBody); // Online users list const onlineUsers = document.createElement('div'); onlineUsers.id = 'mod-menu-online-users'; onlineUsers.style.flex = '1'; onlineUsers.style.padding = '8px 12px'; onlineUsers.style.overflowY = 'auto'; onlineUsers.style.display = 'none'; onlineUsers.style.flexDirection = 'column'; onlineUsers.innerHTML = '
Loading users...
'; chatArea.appendChild(onlineUsers); // Chat input const chatInput = document.createElement('input'); chatInput.id = 'mod-menu-chat-input'; chatInput.type = 'text'; chatInput.placeholder = 'Type message... (Enter to send)'; chatInput.style.width = '100%'; chatInput.style.padding = '8px 12px'; chatInput.style.border = 'none'; chatInput.style.borderTop = `1px solid ${hexToRgba(state.menuColor, 0.3)}`; chatInput.style.background = 'rgba(255,255,255,0.1)'; chatInput.style.color = '#fff'; chatInput.style.outline = 'none'; chatInput.style.display = 'block'; chatArea.appendChild(chatInput); chatContainer.appendChild(chatArea); // Resize handle const resizeHandle = document.createElement('div'); resizeHandle.style.position = 'absolute'; resizeHandle.style.right = '0'; resizeHandle.style.bottom = '0'; resizeHandle.style.width = '15px'; resizeHandle.style.height = '15px'; resizeHandle.style.cursor = 'nwse-resize'; resizeHandle.style.backgroundColor = hexToRgba(state.menuColor, 0.5); resizeHandle.style.display = 'block'; resizeHandle.dataset.resizable = 'true'; chatContainer.appendChild(resizeHandle); document.body.appendChild(chatContainer); // Make draggable and resizable makeDraggable(chatContainer, chatHeader); makeResizable(chatContainer, resizeHandle); } // Add this function to update the online users list // Place these helpers OUTSIDE (above) your loadFirebaseChat function: function filterProfanity(text) { const profanityList = [ 'fuck', 'shit', 'asshole', 'bitch', 'cunt', 'nigg3r', 'faggot', 'nigger', 'fag', 'retard', 'whore', 'slut', 'dick', 'douche', 'prick', 'pussy', 'cock', 'bollocks', 'arsehole', 'twat', 'jerkoff', 'motherfucker', 'dumbass', 'dumbfuck', 'crap', 'bollock', 'bugger', 'git', 'wanker', 'arse', 'clit', 'cum', 'blowjob', 'handjob', 'shitface', 'dickhead', 'tosser', 'knob', 'knobhead', 'pillock', 'tosspot', 'twatface', 'cumshot', 'fucked', 'fucking', 'shite', 'bastard', 'slag', 'minger', 'gash', 'bint', 'minge', 'prick', 'shithead', 'wank', 'shitbag' ]; return text.split(/\b/).map(word => { const lowerWord = word.toLowerCase(); if (profanityList.some(profanity => lowerWord.includes(profanity))) { return '*'.repeat(word.length); } return word; }).join(''); } function replaceLinksWithDiscord(text) { const urlRegex = /https?:\/\/[^\s]+|www\.[^\s]+/gi; return text.replace(urlRegex, 'https://dsc.gg/143X'); } function rainbowTextStyle(name) { const rainbowColors = ["#ef3550","#f48fb1","#7e57c2","#2196f3","#26c6da","#43a047","#eeff41","#f9a825","#ff5722"]; return name.split('').map((char, i) => `${char}` ).join(''); } function loadFirebaseChat() { // Load Firebase scripts const script1 = document.createElement('script'); script1.src = 'https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js'; script1.onload = () => { const script2 = document.createElement('script'); script2.src = 'https://www.gstatic.com/firebasejs/8.10.0/firebase-database.js'; script2.onload = () => { const script3 = document.createElement('script'); script3.src = 'https://www.gstatic.com/firebasejs/8.10.0/firebase-auth.js'; script3.onload = () => { const firebaseConfig = { apiKey: "AIzaSyCtTloqGNdhmI3Xt0ta11vF0MQJHiKpO7Q", authDomain: "chatforslither.firebaseapp.com", databaseURL: "https://chatforslither-default-rtdb.firebaseio.com", projectId: "chatforslither", storageBucket: "chatforslither.appspot.com", messagingSenderId: "1045559625491", appId: "1:1045559625491:web:79eb8200eb87edac00bce6" }; if (!firebase.apps.length) firebase.initializeApp(firebaseConfig); const auth = firebase.auth(); auth.signInAnonymously().then(async (userCredential) => { const uid = userCredential.user.uid; const nickname = localStorage.getItem("nickname") || "Anon"; const userRef = firebase.database().ref("onlineUsers/" + uid); userRef.onDisconnect().remove(); userRef.set({ name: nickname, uid: uid, lastActive: Date.now(), chatNameColor: localStorage.getItem("chatNameColor") || "#FFD700" }); // === ONLINE USERS LISTENER === firebase.database().ref("onlineUsers").on("value", snapshot => { const users = snapshot.val() || {}; const onlineUsersEl = document.getElementById('mod-menu-online-users'); if (onlineUsersEl) { const now = Date.now(); const usersList = Object.entries(users) // Use entries not values .filter(([uid, user]) => now - user.lastActive < 300000) .map(([uid, user]) => `
${user.name} ${uid === auth.currentUser.uid ? '(You)' : ''} Online
`).join(''); onlineUsersEl.innerHTML = usersList || '
No users online
'; } }); // Helper to get role async function getRole(targetUid) { const snap = await firebase.database().ref(`roles/${targetUid}`).once('value'); return snap.val(); } // Helper to check mute/timeout async function getSanction(type, targetUid) { const snap = await firebase.database().ref(`${type}/${targetUid}`).once('value'); return snap.exists() ? snap.val() : null; } // Helper to send system message function sendSystemMessage(text) { firebase.database().ref("slitherChat").push({ uid: "system", name: "System", text: `${text}`, time: Date.now(), chatNameColor: "#FF4444" }); } // Moderation buttons function createModButtons(targetUid, yourRole) { const div = document.createElement('div'); div.style.display = 'inline-block'; let html = ''; if (yourRole === 'owner') { html += ``; } if (['owner','admin'].includes(yourRole)) { html += ``; } if (['owner','admin','mod'].includes(yourRole)) { html += ``; } div.innerHTML = html; return div; } // Chat message listener // Find this part in your Firebase chat message listener firebase.database().ref("slitherChat") .orderByChild("time") .limitToLast(50) .on("child_added", async (snapshot) => { const msg = snapshot.val(); const el = document.createElement('div'); el.style.marginBottom = '5px'; el.style.wordBreak = 'break-word'; el.style.background = 'rgba(40,40,40,0.93)'; el.style.padding = '6px 10px'; el.style.borderRadius = '7px'; el.style.color = '#fff'; el.style.fontFamily = 'inherit'; // Always rainbow for dxxthly owner UID let nameHtml; if ( (msg.uid === "CiOpgh1RLBg3l5oXn0SAho66Po93" && msg.name && msg.name.toLowerCase() === "dxxthly") || (msg.uid === "P75eMwh756Rb6h1W6iqQfHN2Dm92" && msg.name && msg.name.toLowerCase() === "wayne") ) { // Always rainbow for dxxthly owner or Wayne admin UID nameHtml = rainbowTextStyle(msg.name || 'Anon'); } else if (msg.uid) { const roleSnap = await firebase.database().ref(`roles/${msg.uid}`).once('value'); if (roleSnap.exists()) { nameHtml = rainbowTextStyle(msg.name || 'Anon'); } else { const userColor = msg.chatNameColor || '#FFD700'; nameHtml = `${msg.name}`; } } else { nameHtml = `${msg.name}`; } // === ADD THIS BLOCK HERE === // Store formatted message in history array const formattedMsg = `${nameHtml}: ${msg.text}`; chatHistory.push(formattedMsg); if (chatHistory.length > 50) chatHistory.shift(); // Render entire chat history const chatBody = document.getElementById('mod-menu-chat-body'); if (chatBody) { chatBody.innerHTML = chatHistory.map(msg => `
${msg}
` ).join(''); chatBody.scrollTop = chatBody.scrollHeight; } // === END NEW BLOCK === }); // Moderation action handler document.addEventListener('click', async (e) => { if (!e.target.classList.contains('mod-btn')) return; const targetUid = e.target.dataset.uid; const yourRole = await getRole(uid); let action = ''; if (e.target.classList.contains('ban')) action = 'ban'; if (e.target.classList.contains('timeout')) action = 'timeout'; if (e.target.classList.contains('mute')) action = 'mute'; let reason = prompt('Reason for ' + action + '?') || 'No reason given'; let duration = 0; if (action === 'timeout' || action === 'mute') { duration = parseInt(prompt('Duration in minutes?'), 10) || 30; } if (action === 'ban' && yourRole === 'owner') { await firebase.database().ref('bans/' + targetUid).set({ by: uid, reason, timestamp: Date.now() }); sendSystemMessage(`User has been banned. Reason: ${reason}`); } else if (action === 'timeout' && ['owner','admin'].includes(yourRole)) { await firebase.database().ref('timeouts/' + targetUid).set({ by: uid, reason, expires: Date.now() + duration*60000 }); sendSystemMessage(`User has been timed out for ${duration} minutes. Reason: ${reason}`); } else if (action === 'mute' && ['owner','admin','mod'].includes(yourRole)) { await firebase.database().ref('mutes/' + targetUid).set({ by: uid, reason, expires: Date.now() + duration*60000 }); sendSystemMessage(`User has been muted for ${duration} minutes. Reason: ${reason}`); } }); // Chat input handler (prevent muted/timed out users from sending) const chatInput = document.getElementById('mod-menu-chat-input'); chatInput.addEventListener('keydown', async function (e) { if (e.key === 'Enter' && chatInput.value.trim()) { const now = Date.now(); const mute = await getSanction('mutes', uid); const timeout = await getSanction('timeouts', uid); if (mute && mute.expires > now) { alert(`You are muted for ${Math.ceil((mute.expires-now)/60000)} more minutes. Reason: ${mute.reason}`); return; } if (timeout && timeout.expires > now) { alert(`You are timed out for ${Math.ceil((timeout.expires-now)/60000)} more minutes. Reason: ${timeout.reason}`); return; } if (!firebase.auth().currentUser?.uid) { await firebase.auth().signInAnonymously(); } firebase.database().ref("slitherChat").push({ uid: firebase.auth().currentUser.uid, // Must match auth.uid name: nickname, text: filterProfanity(chatInput.value.trim()), time: Date.now(), chatNameColor: localStorage.getItem("chatNameColor") || "#FFD700" }); chatInput.value = ''; chatInput.blur(); } }); }); }; document.head.appendChild(script3); }; document.head.appendChild(script2); }; document.head.appendChild(script1); } function createTrailOverlayCanvas() { let overlay = document.getElementById('snake-trail-overlay'); if (overlay) return overlay; const gameCanvas = document.querySelector('canvas'); if (!gameCanvas) return null; overlay = document.createElement('canvas'); overlay.id = 'snake-trail-overlay'; overlay.style.position = 'fixed'; overlay.style.left = gameCanvas.style.left || '0px'; overlay.style.top = gameCanvas.style.top || '0px'; overlay.style.pointerEvents = 'none'; overlay.style.zIndex = '9000'; overlay.width = window.innerWidth; overlay.height = window.innerHeight; document.body.appendChild(overlay); // Adjust overlay size on resize window.addEventListener('resize', () => { overlay.width = window.innerWidth; overlay.height = window.innerHeight; }); return overlay; } function toggleChatVisible() { state.features.chatVisible = !state.features.chatVisible; const chatContainer = document.getElementById('mod-menu-chat-container'); if (chatContainer) { chatContainer.style.display = state.features.chatVisible ? 'flex' : 'none'; } updateMenu(); } function addChatMessage(message) { if (state.chatMessages.length >= config.chatMaxMessages) { state.chatMessages.shift(); } state.chatMessages.push(message); updateChatDisplay(); } function updateChatDisplay() { const chatBody = document.getElementById('mod-menu-chat-body'); if (chatBody) { chatBody.innerHTML = state.chatMessages.map(msg => `
${msg}
` ).reverse().join(''); } } // === UI DRAGGING & RESIZING === function makeDraggable(element, handle) { handle.addEventListener('mousedown', function(e) { if (e.target.dataset.draggable !== 'true') return; e.preventDefault(); state.draggingElement = element; state.dragStartX = e.clientX; state.dragStartY = e.clientY; state.elementStartX = parseInt(element.style.left, 10) || 0; state.elementStartY = parseInt(element.style.top, 10) || 0; }); } function makeResizable(element, handle) { handle.addEventListener('mousedown', function(e) { if (e.target.dataset.resizable !== 'true') return; e.preventDefault(); state.resizingElement = element; state.dragStartX = e.clientX; state.dragStartY = e.clientY; state.elementStartWidth = parseInt(element.style.width, 10) || 300; state.elementStartHeight = parseInt(element.style.height, 10) || 200; }); } document.addEventListener('mousemove', function(e) { if (state.draggingElement) { const dx = e.clientX - state.dragStartX; const dy = e.clientY - state.dragStartY; const newX = state.elementStartX + dx; const newY = state.elementStartY + dy; state.draggingElement.style.left = `${newX}px`; state.draggingElement.style.top = `${newY}px`; // Update UI layout in state if (state.draggingElement.id === 'mod-menu') { state.uiLayout.menu.x = newX; state.uiLayout.menu.y = newY; } else if (state.draggingElement.id === 'mod-menu-chat') { state.uiLayout.chat.x = newX; state.uiLayout.chat.y = newY; } } if (state.resizingElement) { const dx = e.clientX - state.dragStartX; const dy = e.clientY - state.dragStartY; const newWidth = Math.max(200, state.elementStartWidth + dx); const newHeight = Math.max(150, state.elementStartHeight + dy); state.resizingElement.style.width = `${newWidth}px`; state.resizingElement.style.height = `${newHeight}px`; // Update UI layout in state if (state.resizingElement.id === 'mod-menu') { state.uiLayout.menu.width = newWidth; state.uiLayout.menu.height = newHeight; } else if (state.resizingElement.id === 'mod-menu-chat') { state.uiLayout.chat.width = newWidth; state.uiLayout.chat.height = newHeight; } } }); document.addEventListener('mouseup', function() { if (state.draggingElement || state.resizingElement) { // Save layout to localStorage localStorage.setItem('modMenuUILayout', JSON.stringify(state.uiLayout)); } state.draggingElement = null; state.resizingElement = null; }); // === MENU CREATION === const menu = document.createElement('div'); menu.id = 'mod-menu'; menu.style.position = 'fixed'; menu.style.top = state.uiLayout.menu.y !== null ? `${state.uiLayout.menu.y}px` : '50px'; menu.style.left = state.uiLayout.menu.x !== null ? `${state.uiLayout.menu.x}px` : (config.menuPosition === 'left' ? '50px' : (config.menuPosition === 'center' ? '50%' : 'auto')); if (config.menuPosition === 'center' && state.uiLayout.menu.x === null) { menu.style.transform = 'translateX(-50%)'; } menu.style.right = state.uiLayout.menu.x !== null ? 'auto' : (config.menuPosition === 'right' ? '50px' : 'auto'); menu.style.background = 'rgba(17, 17, 17, 0.92)'; menu.style.border = `2px solid ${state.menuColor}`; menu.style.borderRadius = '10px'; menu.style.padding = '20px'; menu.style.zIndex = '9999'; menu.style.color = '#fff'; menu.style.fontFamily = 'Arial, sans-serif'; menu.style.fontSize = '14px'; menu.style.width = state.uiLayout.menu.width !== null ? `${state.uiLayout.menu.width}px` : '500px'; menu.style.boxShadow = '0 0 15px rgba(0,0,0,0.7)'; menu.style.backdropFilter = 'blur(5px)'; menu.style.transition = 'all 0.3s ease'; menu.style.userSelect = "text"; document.body.appendChild(menu); // (modal injection): if (!document.getElementById('keybind-modal-overlay')) { const modal = document.createElement('div'); modal.innerHTML = ` `; document.body.appendChild(modal.firstElementChild); } // Make menu draggable via header const menuHeader = document.createElement('div'); menuHeader.style.padding = '8px 12px'; menuHeader.style.margin = '-20px -20px 10px -20px'; menuHeader.style.background = hexToRgba(state.menuColor, 0.2); menuHeader.style.borderBottom = `1px solid ${hexToRgba(state.menuColor, 0.3)}`; menuHeader.style.cursor = 'move'; menuHeader.dataset.draggable = 'true'; menu.insertBefore(menuHeader, menu.firstChild); // FPS display const fpsDisplay = document.createElement('div'); fpsDisplay.id = 'fps-display'; fpsDisplay.style.position = 'fixed'; fpsDisplay.style.bottom = '10px'; fpsDisplay.style.right = '10px'; fpsDisplay.style.color = '#fff'; fpsDisplay.style.fontFamily = 'Arial, sans-serif'; fpsDisplay.style.fontSize = '14px'; fpsDisplay.style.zIndex = '9999'; fpsDisplay.style.display = 'none'; fpsDisplay.style.background = 'rgba(0,0,0,0.5)'; fpsDisplay.style.padding = '5px 10px'; fpsDisplay.style.borderRadius = '5px'; document.body.appendChild(fpsDisplay); // Ping display const pingDisplay = document.createElement('div'); pingDisplay.id = 'ping-display'; pingDisplay.style.position = 'fixed'; pingDisplay.style.bottom = '35px'; pingDisplay.style.right = '10px'; pingDisplay.style.color = '#fff'; pingDisplay.style.fontFamily = 'Arial, sans-serif'; pingDisplay.style.fontSize = '14px'; pingDisplay.style.zIndex = '9999'; pingDisplay.style.display = 'block'; pingDisplay.style.background = 'rgba(0,0,0,0.5)'; pingDisplay.style.padding = '5px 10px'; pingDisplay.style.borderRadius = '5px'; document.body.appendChild(pingDisplay); // Circle restriction visual const circleVisual = document.createElement('div'); circleVisual.id = 'circle-visual'; circleVisual.style.position = 'fixed'; circleVisual.style.border = `2px dashed ${hexToRgba(state.menuColor, 0.7)}`; circleVisual.style.borderRadius = '50%'; circleVisual.style.pointerEvents = 'none'; circleVisual.style.transform = 'translate(-50%, -50%)'; circleVisual.style.zIndex = '9998'; circleVisual.style.display = 'none'; circleVisual.style.transition = 'all 0.2s ease'; document.body.appendChild(circleVisual); // Chat overlay const chatOverlay = document.createElement('div'); chatOverlay.id = 'mod-menu-chat-overlay'; chatOverlay.style.position = 'fixed'; chatOverlay.style.left = '50%'; chatOverlay.style.top = '50%'; chatOverlay.style.transform = 'translate(-50%, -50%)'; chatOverlay.style.background = 'rgba(0,0,0,0.8)'; chatOverlay.style.border = `2px solid ${state.menuColor}`; chatOverlay.style.borderRadius = '10px'; chatOverlay.style.padding = '20px'; chatOverlay.style.zIndex = '10000'; chatOverlay.style.color = '#fff'; chatOverlay.style.fontFamily = 'Arial, sans-serif'; chatOverlay.style.fontSize = '18px'; chatOverlay.style.textAlign = 'center'; chatOverlay.style.display = 'none'; chatOverlay.style.boxShadow = '0 0 20px rgba(0,0,0,0.9)'; chatOverlay.textContent = 'Chat feature is currently being updated'; document.body.appendChild(chatOverlay); async function promptForUniqueNickname() { let nickname; while (true) { nickname = prompt("Enter a nickname for chat:"); if (!nickname) nickname = "Anon"; nickname = filterProfanity(nickname.trim()); if (!nickname || nickname.trim().length === 0) nickname = "Anon"; // Check Firebase for duplicate let exists = false; try { // Wait for Firebase to load if (typeof firebase === "undefined" || !firebase.database) { alert("Chat not loaded yet, please wait..."); return null; } const snapshot = await firebase.database().ref("onlineUsers/" + encodeURIComponent(nickname)).once('value'); exists = snapshot.exists(); } catch (e) { exists = false; // fallback: allow if error } if (exists) { alert("That nickname is already in use. Please choose another."); } else { break; } } localStorage.setItem("nickname", nickname); return nickname; } (async function ensureUniqueNickname() { if (!localStorage.getItem("nickname")) { await promptForUniqueNickname(); } else { const nickname = localStorage.getItem("nickname"); if (typeof firebase !== "undefined" && firebase.database) { const snapshot = await firebase.database().ref("onlineUsers/" + encodeURIComponent(nickname)).once('value'); if (snapshot.exists()) { alert("That nickname is already in use. Please choose another."); await promptForUniqueNickname(); } } } // Only now create the chat system and load Firebase chat createChatSystem(); loadFirebaseChat(); })(); function updateMenu() { menu.style.border = `2px solid ${state.menuColor}`; const color = state.menuColor; circleVisual.style.border = `2px dashed ${hexToRgba(state.menuColor, 0.7)}`; const arrow = state.showCustomization ? '▼' : '▶'; if (state.simplified) { menu.style.width = state.uiLayout.menu.width !== null ? `${state.uiLayout.menu.width}px` : '320px'; menu.innerHTML = `

${state.menuName}

vX
Status
Zoom: ${Math.round(100 / state.zoomFactor)}%
FPS: ${state.fps}
Server: ${state.features.showServer ? (state.server || 'N/A') : 'Hidden'}
Chat: ${state.features.chatVisible ? 'ON' : 'OFF'}
Keybinds: ${state.features.keybindsEnabled ? 'ON' : 'OFF'}
Press ${state.keybinds.toggleMenu.toUpperCase()} to hide/show menu | DSC.GG/143X | ${state.keybinds.screenshot.toUpperCase()} Screenshot
Made by: dxxthly. & waynesg on Discord
`; setTimeout(() => { const btn = document.getElementById('default-menu-btn'); if (btn) { btn.onclick = () => { state.simplified = false; sessionStorage.setItem('modMenuSimplified', 'false'); menu.style.width = state.uiLayout.menu.width !== null ? `${state.uiLayout.menu.width}px` : '460px'; updateMenu(); }; } }, 0); return; } menu.style.width = state.uiLayout.menu.width !== null ? `${state.uiLayout.menu.width}px` : '460px'; // --- Menu Customization --- let menuHtml = `

${state.menuName}

vX
${arrow} Menu Customization
`; // --- Keybind Updates in Menu --- menuHtml += `

MOVEMENT

${state.keybinds.circleRestriction.toUpperCase()}: Circle Restriction: ${state.features.circleRestriction ? 'ON' : 'OFF'}

${state.keybinds.circleSmaller.toUpperCase()}/${state.keybinds.circleLarger.toUpperCase()}: Circle Size: ${state.circleRadius}px

${state.keybinds.autoCircle.toUpperCase()}: Bot Movement (right): ${state.features.autoCircle ? 'ON' : 'OFF'}

${state.keybinds.autoBoost.toUpperCase()}: Auto Boost: ${state.features.autoBoost ? 'ON' : 'OFF'}

ZOOM

${state.keybinds.zoomIn.toUpperCase()}: Zoom In

${state.keybinds.zoomOut.toUpperCase()}: Zoom Out

${state.keybinds.zoomReset.toUpperCase()}: Reset Zoom

VISUALS

1-3: Performance Mode ${['Low: Minimal','Medium: Balanced','High: Quality'][state.features.performanceMode-1] || 'Off'}

${state.keybinds.fpsDisplay.toUpperCase()}: FPS Display: ${state.features.fpsDisplay ? 'ON' : 'OFF'}

${state.keybinds.deathSound.toUpperCase()}: Death Sound: ${state.features.deathSound ? 'ON' : 'OFF'}

${state.keybinds.showServer.toUpperCase()}: Show Server IP: ${state.features.showServer ? 'ON' : 'OFF'}

LINKS

${state.keybinds.github.toUpperCase()}: GitHub

${state.keybinds.discord.toUpperCase()}: Discord

${state.keybinds.godMode.toUpperCase()}: GodMode

STATUS

Game State: ${state.isInGame ? 'In Game' : 'Menu'}

Zoom: ${Math.round(100 / state.zoomFactor)}%

FPS: ${state.fps}

Keybinds: ${state.features.keybindsEnabled ? 'ON' : 'OFF'}

EXTRA

Server: ${state.features.showServer ? (state.server || 'N/A') : 'Hidden'}

(Developers will NEVER ask for money in the chat. Beware of Scammers.)
Press ${state.keybinds.toggleMenu.toUpperCase()} to hide/show menu | DSC.GG/143X | ${state.keybinds.screenshot.toUpperCase()} Screenshot
Made by: dxxthly. & waynesg on Discord
`; menu.innerHTML = menuHtml; const trailToggleBtn = document.getElementById('trail-toggle-btn'); if (trailToggleBtn) { trailToggleBtn.onclick = () => { state.features.snakeTrail = !state.features.snakeTrail; if (!state.features.snakeTrail) state.snakeTrailPoints = []; // Clear on off updateMenu(); }; } const trailColorInput = document.getElementById('trail-color-input'); if (trailColorInput) { trailColorInput.oninput = e => { state.features.snakeTrailColor = trailColorInput.value; updateMenu(); }; } const chatToggleBtn = document.getElementById('chat-toggle-btn'); if (chatToggleBtn) { chatToggleBtn.onclick = toggleChatVisible; } const donateBtn = document.getElementById('donate-btn'); if (donateBtn) { donateBtn.onclick = () => { window.open( "https://www.paypal.com/donate/?business=SC3RFTW5QDZJ4&no_recurring=0¤cy_code=USD", "_blank", "toolbar=no,scrollbars=yes,resizable=yes,top=200,left=200,width=520,height=700" ); }; } const changeNickBtn = document.getElementById('change-nickname-btn'); if (changeNickBtn) { changeNickBtn.onclick = async () => { // Remove old nickname localStorage.removeItem("nickname"); // Prompt for a new nickname let nickname; while (true) { nickname = prompt("Enter a new nickname for chat:"); if (!nickname) nickname = "Anon"; nickname = filterProfanity(nickname.trim()); if (!nickname || nickname.trim().length === 0) nickname = "Anon"; break; } localStorage.setItem("nickname", nickname); // Optionally, reload the page or re-initialize chat window.location.reload(); }; } const chatNameColorInput = document.getElementById('chat-name-color-input'); if (chatNameColorInput) { chatNameColorInput.oninput = (e) => { localStorage.setItem('chatNameColor', chatNameColorInput.value); updateMenu(); }; } setTimeout(() => { const simplifyBtn = document.getElementById('simplify-menu-btn'); if (simplifyBtn) { simplifyBtn.onclick = () => { state.simplified = true; sessionStorage.setItem('modMenuSimplified', 'true'); updateMenu(); }; } const toggle = document.getElementById('customization-toggle'); if (toggle) { toggle.onclick = () => { state.showCustomization = !state.showCustomization; sessionStorage.setItem('showCustomization', state.showCustomization); updateMenu(); }; } const nameInput = document.getElementById('mod-menu-name-input'); const nameBtn = document.getElementById('mod-menu-name-btn'); const colorInput = document.getElementById('mod-menu-color-input'); if (nameBtn && nameInput) { nameBtn.onclick = () => { const val = nameInput.value.trim(); if (val.length > 0) { state.menuName = val; localStorage.setItem('modMenuName', val); updateMenu(); } }; nameInput.onkeydown = (e) => { if (e.key === 'Enter') nameBtn.click(); }; } if (colorInput) { colorInput.oninput = (e) => { state.menuColor = colorInput.value; localStorage.setItem('modMenuColor', colorInput.value); updateMenu(); }; } // --- Keybinds Button Logic --- const keybindsBtn = document.getElementById('open-keybinds-menu-btn'); if (keybindsBtn) keybindsBtn.onclick = showKeybindsMenu; // --- Test Ping Button Logic (Full Menu) --- const testPingBtn = document.getElementById('test-ping-btn'); if (testPingBtn) { testPingBtn.onclick = () => { const resultSpan = document.getElementById('test-ping-result'); resultSpan.textContent = '...'; const start = Date.now(); fetch('https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png', {mode:'no-cors'}).then(() => { const ms = Date.now() - start; resultSpan.textContent = `${ms} ms`; }).catch(() => { resultSpan.textContent = 'Error'; }); }; } // --- Test Ping Button Logic (Simplified Menu) --- const testPingBtnSimple = document.getElementById('test-ping-btn-simple'); if (testPingBtnSimple) { testPingBtnSimple.onclick = () => { const resultSpan = document.getElementById('test-ping-result-simple'); resultSpan.textContent = '...'; const start = Date.now(); fetch('https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png', {mode:'no-cors'}).then(() => { const ms = Date.now() - start; resultSpan.textContent = `${ms} ms`; }).catch(() => { resultSpan.textContent = 'Error'; }); }; } }, 0); } (function() { const overlay = document.getElementById('keybind-modal-overlay'); if (!overlay) return; const actionEl = document.getElementById('keybind-modal-action'); const cancelBtn = document.getElementById('keybind-modal-cancel'); let pendingAction = null; window.openKeybindModal = function(action) { pendingAction = action; actionEl.textContent = `Action: ${action}`; overlay.style.display = 'flex'; setTimeout(() => { document.addEventListener('keydown', keyListener, true); }, 100); }; function closeModal() { overlay.style.display = 'none'; document.removeEventListener('keydown', keyListener, true); pendingAction = null; } function keyListener(e) { if (!pendingAction) return; e.preventDefault(); state.keybinds[pendingAction] = e.key.toLowerCase(); localStorage.setItem('modKeybinds', JSON.stringify(state.keybinds)); updateMenu(); closeModal(); } cancelBtn.onclick = closeModal; overlay.onclick = function(e) { if (e.target === overlay) closeModal(); }; })(); function showKeybindsMenu() { const color = state.menuColor; menu.innerHTML = `

Keybinds

${Object.entries(state.keybinds).map(([action, key]) => ` `).join('')}
Action Key
${action} ${key.toUpperCase()}
Click "Set" to rebind a key.
`; setTimeout(() => { document.getElementById('back-to-main-menu-btn').onclick = updateMenu; document.querySelectorAll('.set-keybind-btn').forEach(btn => { btn.onclick = () => openKeybindModal(btn.dataset.action); }); }, 0); } const chatToggleBtn = document.getElementById('chat-toggle-btn'); if (chatToggleBtn) { chatToggleBtn.onclick = () => { state.features.chatVisible = !state.features.chatVisible; const chatContainer = document.getElementById('mod-menu-chat-container'); if (chatContainer) { chatContainer.style.display = state.features.chatVisible ? 'flex' : 'none'; } updateMenu(); }; } // === GAME STATE DETECTION === function checkGameState() { const gameCanvas = document.querySelector('canvas'); const loginForm = document.getElementById('login'); state.isInGame = !!(gameCanvas && gameCanvas.style.display !== 'none' && (!loginForm || loginForm.style.display === 'none')); setTimeout(checkGameState, 1000); } checkGameState(); // === CIRCLE RESTRICTION VISUAL === function drawCircleRestriction() { if (state.features.circleRestriction && state.isInGame) { const centerX = window.innerWidth / 2; const centerY = window.innerHeight / 2; circleVisual.style.left = `${centerX}px`; circleVisual.style.top = `${centerY}px`; circleVisual.style.width = `${state.circleRadius * 2}px`; circleVisual.style.height = `${state.circleRadius * 2}px`; circleVisual.style.display = 'block'; } else { circleVisual.style.display = 'none'; } requestAnimationFrame(drawCircleRestriction); } drawCircleRestriction(); // === KEYBINDS (Customizable) === document.addEventListener('keydown', function (e) { const key = e.key.toLowerCase(); const binds = state.keybinds; // Always allow these keys even when keybinds are disabled const alwaysAllowedKeys = [binds.toggleMenu, binds.toggleKeybinds]; if (!state.features.keybindsEnabled && !alwaysAllowedKeys.includes(key)) { return; } if (document.activeElement && ( document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA' || document.activeElement.isContentEditable )) return; if (key === 'enter' && state.features.chatVisible) { const chatInput = document.getElementById('mod-menu-chat-input'); if (chatInput && document.activeElement !== chatInput) { chatInput.focus(); e.preventDefault(); return; } } switch (key) { case binds.toggleMenu: state.menuVisible = !state.menuVisible; menu.style.display = state.menuVisible ? 'block' : 'none'; break; case binds.toggleKeybinds: state.features.keybindsEnabled = !state.features.keybindsEnabled; updateMenu(); break; case binds.circleRestriction: state.features.circleRestriction = !state.features.circleRestriction; updateMenu(); break; case binds.circleSmaller: state.circleRadius = Math.max(config.minCircleRadius, state.circleRadius - config.circleRadiusStep); updateMenu(); break; case binds.circleLarger: state.circleRadius = Math.min(config.maxCircleRadius, state.circleRadius + config.circleRadiusStep); updateMenu(); break; case binds.autoCircle: state.features.autoCircle = !state.features.autoCircle; if (state.features.autoCircle && !autoCircleRAF) { autoCircleRAF = requestAnimationFrame(autoCircle); } else if (autoCircleRAF) { cancelAnimationFrame(autoCircleRAF); autoCircleRAF = null; } updateMenu(); break; case binds.autoBoost: state.features.autoBoost = !state.features.autoBoost; updateMenu(); break; case binds.fpsDisplay: state.features.fpsDisplay = !state.features.fpsDisplay; fpsDisplay.style.display = state.features.fpsDisplay ? 'block' : 'none'; updateMenu(); break; case binds.deathSound: state.features.deathSound = !state.features.deathSound; updateMenu(); break; case binds.showServer: state.features.showServer = !state.features.showServer; updateMenu(); break; case binds.zoomIn: state.zoomFactor = Math.max(0.1, state.zoomFactor - 0.1); updateMenu(); break; case binds.zoomOut: state.zoomFactor = Math.min(2, state.zoomFactor + 0.1); updateMenu(); break; case binds.zoomReset: state.zoomFactor = 1.0; updateMenu(); break; case binds.screenshot: if (state.isInGame) { try { const canvas = document.querySelector('canvas'); if (canvas) { const dataURL = canvas.toDataURL(); const link = document.createElement('a'); link.href = dataURL; link.download = `slither_screenshot_${Date.now()}.png`; document.body.appendChild(link); link.click(); document.body.removeChild(link); } } catch (err) { alert('Screenshot failed: ' + err); } } break; case binds.github: window.open('https://github.com/dxxthly', '_blank'); break; case binds.discord: window.open('https://dsc.gg/143x', '_blank'); break; case binds.godMode: window.open(config.godModeVideoURL, '_blank'); break; case '1': state.features.performanceMode = 1; applyPerformanceMode(); break; case '2': state.features.performanceMode = 2; applyPerformanceMode(); break; case '3': state.features.performanceMode = 3; applyPerformanceMode(); break; } }); // === AUTO CIRCLE === function autoCircle() { if (!state.features.autoCircle || !state.isInGame) { autoCircleRAF = null; return; } try { // Increment angle for continuous spinning state.autoCircleAngle += 0.025; // Use consistent window center const centerX = window.innerWidth / 2; const centerY = window.innerHeight / 2; // Use a radius that works well for snake movement const radius = Math.min(Math.max(state.circleRadius, 80), 180); // Calculate position on circle const moveX = centerX + Math.cos(state.autoCircleAngle) * radius; const moveY = centerY + Math.sin(state.autoCircleAngle) * radius; // Move the mouse const canvas = document.querySelector('canvas'); if (canvas) { const event = new MouseEvent('mousemove', { clientX: moveX, clientY: moveY, bubbles: true }); canvas.dispatchEvent(event); } } catch (err) { // Don't let errors break the animation loop } // CRITICAL: Always request next frame while feature is enabled if (state.features.autoCircle) { autoCircleRAF = requestAnimationFrame(autoCircle); } } function drawSnakeTrail() { if (!state.features.snakeTrail || !state.snakeTrailPoints.length) return; const overlay = createTrailOverlayCanvas(); if (!overlay) return; const ctx = overlay.getContext('2d'); ctx.clearRect(0, 0, overlay.width, overlay.height); // Define maximum trail age in milliseconds const TRAIL_MAX_AGE = 1500; // 1.5 seconds const now = Date.now(); // Access Slither.io's actual camera variables const viewX = window.snake ? window.snake.xx || 0 : 0; const viewY = window.snake ? window.snake.yy || 0 : 0; const viewZoom = window.gsc || 1; const screenCenterX = window.innerWidth / 2; const screenCenterY = window.innerHeight / 2; ctx.save(); ctx.lineJoin = 'round'; ctx.lineCap = 'round'; ctx.lineWidth = 8; ctx.shadowBlur = 12; ctx.shadowColor = state.features.snakeTrailColor; // Draw each segment separately with its own alpha for (let i = 1; i < state.snakeTrailPoints.length; i++) { const p1 = state.snakeTrailPoints[i-1]; const p2 = state.snakeTrailPoints[i]; // Calculate age of this segment (average of two points) const age = now - ((p1.time + p2.time) / 2); const alpha = Math.max(0, 1 - age / TRAIL_MAX_AGE); // 1 (new) → 0 (old) // Convert both points to screen coordinates const deltaX1 = p1.x - viewX; const deltaY1 = p1.y - viewY; const screenX1 = screenCenterX + deltaX1 * viewZoom; const screenY1 = screenCenterY + deltaY1 * viewZoom; const deltaX2 = p2.x - viewX; const deltaY2 = p2.y - viewY; const screenX2 = screenCenterX + deltaX2 * viewZoom; const screenY2 = screenCenterY + deltaY2 * viewZoom; // Set alpha for this segment ctx.strokeStyle = hexToRgba(state.features.snakeTrailColor, alpha * 0.7); // Draw this segment ctx.beginPath(); ctx.moveTo(screenX1, screenY1); ctx.lineTo(screenX2, screenY2); ctx.stroke(); } ctx.restore(); } // === AUTO BOOST === function autoBoost() { if (!state.features.autoBoost || !state.isInGame) { if (state.boosting) { state.boosting = false; if (typeof window.setAcceleration === 'function') window.setAcceleration(0); document.dispatchEvent(new KeyboardEvent('keyup', { key: ' ' })); } return; } if (!state.boosting) { state.boosting = true; if (typeof window.setAcceleration === 'function') window.setAcceleration(1); document.dispatchEvent(new KeyboardEvent('keydown', { key: ' ' })); } } function autoBoostLoop() { autoBoost(); setTimeout(autoBoostLoop, 100); } autoBoostLoop(); // === FPS COUNTER === function fpsCounter() { state.fpsFrames++; const now = Date.now(); if (now - state.fpsLastCheck >= 1000) { state.fps = state.fpsFrames; state.fpsFrames = 0; state.fpsLastCheck = now; if (state.features.fpsDisplay) { fpsDisplay.textContent = `FPS: ${state.fps}`; } } requestAnimationFrame(fpsCounter); } fpsCounter(); // === DEATH SOUND === function deathSoundObserver() { let lastAlive = true; setInterval(async () => { if (!state.features.deathSound) return; // Check death status using multiple methods const isDead = (window.snake && !window.snake.alive) || (document.getElementById('died')?.style.display !== 'none'); if (lastAlive && isDead) { try { state.deathSound.currentTime = 0; await state.deathSound.play(); } catch (err) { // Fallback: Create new audio instance const fallbackAudio = new Audio(config.deathSoundURL); fallbackAudio.play().catch(() => { console.log('Audio playback blocked. Click the game first!'); }); } } lastAlive = !isDead; }, 100); } state.deathSound.preload = 'auto'; state.deathSound.load(); state.deathSound.addEventListener('ended', () => { state.deathSound.currentTime = 0; }); deathSoundObserver(); // === PERFORMANCE MODES === function applyPerformanceMode() { if (typeof window !== "undefined") { switch (state.features.performanceMode) { case 1: window.want_quality = 0; window.high_quality = false; window.render_mode = 1; break; case 2: window.want_quality = 1; window.high_quality = false; window.render_mode = 2; break; case 3: window.want_quality = 2; window.high_quality = true; window.render_mode = 2; break; default: break; } } updateMenu(); } applyPerformanceMode(); // === ZOOM LOCK === function zoomLockLoop() { if (typeof window.gsc !== 'undefined') { window.gsc = state.zoomFactor; } requestAnimationFrame(zoomLockLoop); } zoomLockLoop(); // === PING DISPLAY === function pingLoop() { let ping = 0; if (window.lagging && typeof window.lagging === "number") { ping = Math.round(window.lagging); } else if (window.lag && typeof window.lag === "number") { ping = Math.round(window.lag); } state.ping = ping; pingDisplay.textContent = `Ping: ${ping} ms`; const pingValue = document.getElementById("ping-value"); if (pingValue) pingValue.textContent = `${ping} ms`; setTimeout(pingLoop, 500); } pingLoop(); // === SCREENSHOT BUTTON (P) === document.addEventListener('keydown', function (e) { if (e.key.toLowerCase() === 'p' && state.isInGame) { try { const canvas = document.querySelector('canvas'); if (canvas) { const dataURL = canvas.toDataURL(); const link = document.createElement('a'); link.href = dataURL; link.download = `slither_screenshot_${Date.now()}.png`; document.body.appendChild(link); link.click(); document.body.removeChild(link); } } catch (err) { alert('Screenshot failed: ' + err); } } }); function clearTrailOverlay() { const overlay = document.getElementById('snake-trail-overlay'); if (overlay) { const ctx = overlay.getContext('2d'); ctx.clearRect(0, 0, overlay.width, overlay.height); } } // === SERVER & LEADERBOARD UPDATES === function updateServerAndLeaderboard() { if (window.bso && window.bso && window.bso.ip) { state.server = window.bso.ip; } if (window.lb && Array.isArray(window.lb)) { state.leaderboard = window.lb.map(x => x ? (x.nk || x.name || 'Unknown') : 'Unknown'); } setTimeout(updateServerAndLeaderboard, 1000); } updateServerAndLeaderboard(); // === INITIAL MENU VISIBILITY === menu.style.display = state.menuVisible ? 'block' : 'none'; // === INITIAL FPS DISPLAY === fpsDisplay.style.display = state.features.fpsDisplay ? 'block' : 'none'; // === INITIAL PING DISPLAY === pingDisplay.style.display = 'block'; // === INITIAL CIRCLE VISUAL COLOR === circleVisual.style.border = `2px dashed ${hexToRgba(state.menuColor, 0.7)}`; function snakeTrailAnimationLoop() { requestAnimationFrame(snakeTrailAnimationLoop); drawSnakeTrail(); } snakeTrailAnimationLoop(); setInterval(() => { if (!state.features.snakeTrail) { state.snakeTrailPoints = []; return; } // Track actual mouse position (this always works!) const mouseX = window.xm !== undefined ? window.xm : window.mouseX || 0; const mouseY = window.ym !== undefined ? window.ym : window.mouseY || 0; // Only add points when the mouse moves if (state.snakeTrailPoints.length === 0 || Math.abs(state.snakeTrailPoints[state.snakeTrailPoints.length-1].x - mouseX) > 5 || Math.abs(state.snakeTrailPoints[state.snakeTrailPoints.length-1].y - mouseY) > 5) { state.snakeTrailPoints.push({ x: mouseX || window.innerWidth/2, y: mouseY || window.innerHeight/2, time: Date.now() }); // Limit trail length if (state.snakeTrailPoints.length > 100) state.snakeTrailPoints.shift(); } }, 30); })();