您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Advanced controls, features, freeze/pause, change everyones skins, vertical split, use urls as skins
当前为
// ==UserScript== // @name Piccolo's Agario Mod // @namespace New Jack redoes agar.io after 10 years // @version 1.0 // @description Advanced controls, features, freeze/pause, change everyones skins, vertical split, use urls as skins // @author 𝓝𝑒ⓦ 𝓙ⓐ¢K🕹️ // @icon https://i.ibb.co/C3gdJwTP/piccolo.png // @match https://agar.io/* // @grant none // @license MIT // @run-at document-start // ==/UserScript== /* * Notes: * - Combined player data collector and skin manager in a single UI * - Acid mode as a toggle switch * - Pause/freeze functionality using keyboard (Hybrid freeze) * - Copy Names, see all the free skin names * - Vertical Split - hold V and split just right to line split up and down * - Name collection, scoreboard data, and extended nick limit * - Slider to call MC.activateAllOffers() from console * - For best results use Chrome or Oprea on this mod, pause might not work on edge * - Custom Skin Maker - drag and drop, upload from a url * - Contact discord new_jack_9999 for any new ideas (no bots, full map, disconnect or spectator requests ---Agar.io is for everyone, not your ego) * - Feel free to use all this code or any of this code for your own mod * - FYI, imgur has been giving me trouble lately and might not display. This mod accepts any image from anywhere. Try https://imgbb.com/ */ (function() { 'use strict'; // GLOBAL STATE VARIABLES - Move these to the very top let gameCanvas = null; let mainOverlay = null; let showControlsButton = null; let playerDataManagerBox = null; let modUIVisible = false; let isMacroFeeding = false; let macroFeedInterval = null; let isPaused = false; let isInputFocused = false; let fpsCounter = null; let frameCount = 0; let fpsValue = 0; let lastFpsUpdate = performance.now(); let enemySkins = {}; let leaderboardData = {}; let cellNames = new Set(); let playerScore = 0; let isStraightLineMode = false; let startingMousePosition = { x: 0, y: 0 }; let currentMousePosition = { x: 0, y: 0 }; let lockPosition = { x: 0, y: 0 }; let lockInterval = null; let originalSetTarget = null; let originalSendFunction = null; let cursorLockEnabled = true; let packetFreezeEnabled = true; //------------------------------------------------ // GLOBAL CONFIG & CONSTANTS //------------------------------------------------ const STORAGE_KEY = 'enhancedAgarioModUltimate'; const defaultConfig = { enableMod: true, // Mouse actions leftMouseAction: 'macroFeed', middleMouseAction: 'none', rightMouseAction: 'split', // Keyboard hotkeys singleFeedKey: 'w', macroFeedKey: 'm', doubleSplitKey: 'd', tripleSplitKey: 't', quadSplitKey: 'q', verticalLineKey: 'v', acidModeKey: 'a', skinSwitcherKey: 's', toggleUIKey: 'h', pauseMovementKey: 'p', // Toggles enableAcidMode: false, showFpsCounter: true, // Additional toggle for user’s request activateAllOffers: false, // We will trigger MC.activateAllOffers() when ON // FPS settings unlimitedFps: false, // Minimap enableMinimap: true, minimizeMap: false, showPlayersOnMap: true, // Custom skin enableCustomSkin: true, customSkinUrl: '', // Behavior feedRate: 10, splitDelay: 50, maxSavedSkins: 21 }; // UPDATED COLOR SCHEME const COLORS = { headingText: '#343434', normalText: '#000000', functionChoice: '#00d3ff', activePicked: '#1e67e0', buttonBg: '#54c800', buttonBgPress: '#357f00', sliderOff: '#f03737' }; //------------------------------------------------ // LOAD/SAVE CONFIG //------------------------------------------------ function loadConfig() { try { const stored = localStorage.getItem(STORAGE_KEY); if (stored) { const parsed = JSON.parse(stored); return { ...defaultConfig, ...parsed }; } } catch(e) { console.log('Error loading config from localStorage:', e); } return { ...defaultConfig }; } function saveConfig(config) { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(config)); } catch(e) { console.log('Error saving config to localStorage:', e); } } let CONFIG = loadConfig(); //------------------------------------------------ // GLOBAL STATE //------------------------------------------------ //------------------------------------------------ // FPS COUNTER (UPDATED) //------------------------------------------------ const originalClearRect = CanvasRenderingContext2D.prototype.clearRect; CanvasRenderingContext2D.prototype.clearRect = function(...args) { if (this.canvas && this.canvas.width > 500) { const now = performance.now(); frameCount++; if (now - lastFpsUpdate > 500) { fpsValue = Math.round((frameCount * 1000) / (now - lastFpsUpdate)); frameCount = 0; lastFpsUpdate = now; updateFpsCounter(); } } return originalClearRect.apply(this, args); }; function createFpsCounter() { fpsCounter = document.createElement('div'); fpsCounter.id = 'fps-counter'; fpsCounter.style.cssText = ` position: fixed; bottom: 15px; left: 50%; transform: translateX(-50%); background-color: rgba(0, 0, 0, 0.3); color: white; padding: 4px 8px; border-radius: 8px; font-family: Arial, sans-serif; font-weight: bold; font-size: 20px; z-index: 99999; `; document.body.appendChild(fpsCounter); updateFpsCounter(); } function updateFpsCounter() { if (fpsCounter && CONFIG.showFpsCounter) { fpsCounter.textContent = `${fpsValue} FPS`; fpsCounter.style.display = 'block'; } else if (fpsCounter) { fpsCounter.style.display = 'none'; } } function setUnlimitedFps(enable) { CONFIG.unlimitedFps = enable; if (window.core && typeof window.core.setFpsCap === 'function') { window.core.setFpsCap(enable ? 0 : 60); showNotification(`FPS Cap: ${enable ? 'UNLIMITED' : '60'}`); } else { console.error('No setFpsCap method available'); showNotification('Failed to set FPS cap', true); } saveConfig(CONFIG); } //------------------------------------------------ // NOTIFICATIONS //------------------------------------------------ function showNotification(message, isPinned = false) { let notification = document.getElementById('agario-mod-notification'); if (!notification) { notification = document.createElement('div'); notification.id = 'agario-mod-notification'; notification.style.cssText = ` position: absolute; top: 80px; left: 50%; transform: translateX(-50%); background-color: rgba(0,0,0,0.7); color: #fff; padding: 10px 20px; border-radius: 5px; font-family: Arial, sans-serif; font-size: 16px; z-index: 1000; transition: opacity 0.5s; pointer-events: none; `; document.body.appendChild(notification); } notification.textContent = message; notification.style.opacity = '1'; if (!isPinned) { clearTimeout(notification.fadeTimeout); notification.fadeTimeout = setTimeout(() => { notification.style.opacity = '0'; }, 2000); } } //------------------------------------------------ // PREVENT BACKGROUND IMAGE //------------------------------------------------ const originalDrawImage = CanvasRenderingContext2D.prototype.drawImage; CanvasRenderingContext2D.prototype.drawImage = function(img, ...args) { if (img && img.src === 'https://agar.io/img/background.png') { return; } return originalDrawImage.apply(this, [img, ...args]); }; //------------------------------------------------ // FIND GAME CANVAS //------------------------------------------------ function findGameCanvas() { const canvases = document.getElementsByTagName('canvas'); if (canvases.length > 0) { for (let i = 0; i < canvases.length; i++) { if (canvases[i].width > 500 && canvases[i].height > 500) { gameCanvas = canvases[i]; break; } } if (gameCanvas) { console.log('Game canvas found!'); gameCanvas.addEventListener('mousedown', handleMouseDown); gameCanvas.addEventListener('mouseup', handleMouseUp); gameCanvas.addEventListener('contextmenu', (e) => e.preventDefault()); gameCanvas.addEventListener('mousemove', (e) => { currentMousePosition.x = e.clientX; currentMousePosition.y = e.clientY; if (isStraightLineMode) applyLineConstraint(); }); document.addEventListener('pointerlockchange', onPointerLockChange); showNotification(`Advanced Controls Active! Press "${CONFIG.toggleUIKey.toUpperCase()}" to toggle UI`); } else { console.log('No large canvas found, retrying...'); setTimeout(findGameCanvas, 2000); } } else { console.log('No canvas found, retrying...'); setTimeout(findGameCanvas, 2000); } } //------------------------------------------------ // MOUSE & KEYBOARD HANDLING //------------------------------------------------ function handleMouseDown(e) { if (!CONFIG.enableMod) return; if (isPaused) return; if (!window.core) return; if (isInputFocused) return; if (e.button === 0) { doMouseAction(CONFIG.leftMouseAction, 'down'); } else if (e.button === 1) { e.preventDefault(); doMouseAction(CONFIG.middleMouseAction, 'down'); } else if (e.button === 2) { doMouseAction(CONFIG.rightMouseAction, 'down'); } } function handleMouseUp(e) { if (!CONFIG.enableMod) return; if (isPaused) return; if (isInputFocused) return; if (e.button === 0) { doMouseAction(CONFIG.leftMouseAction, 'up'); } else if (e.button === 1) { doMouseAction(CONFIG.middleMouseAction, 'up'); } else if (e.button === 2) { doMouseAction(CONFIG.rightMouseAction, 'up'); } } function doMouseAction(action, phase) { if (!window.core) return; if (action === 'none') return; switch (action) { case 'singleFeed': if (phase === 'down') window.core.eject?.(); break; case 'macroFeed': if (phase === 'down') startMacroFeed(); else if (phase === 'up') stopMacroFeed(); break; case 'split': if (phase === 'down') window.core.split?.(); break; } } function handleKeyDown(e) { const key = e.key.toLowerCase(); if (key === CONFIG.toggleUIKey) { toggleMainOverlay(); return; } if (isInputFocused) return; if (!CONFIG.enableMod) return; if (isPaused && key !== CONFIG.pauseMovementKey) return; switch (key) { case CONFIG.singleFeedKey: window.core?.eject?.(); break; case CONFIG.macroFeedKey: startMacroFeed(); break; case CONFIG.doubleSplitKey: performMultiSplit(2); break; case CONFIG.tripleSplitKey: performMultiSplit(3); break; case CONFIG.quadSplitKey: performMultiSplit(4); break; case CONFIG.verticalLineKey: setVerticalLinePosition(); break; case CONFIG.skinSwitcherKey: openSkinSwitcherUI(); break; case CONFIG.pauseMovementKey: togglePause(); break; } } function handleKeyUp(e) { if (!CONFIG.enableMod) return; if (isPaused) return; if (isInputFocused) return; if (e.key.toLowerCase() === CONFIG.macroFeedKey) { stopMacroFeed(); } } function setupKeyHandlers() { document.addEventListener('keydown', handleKeyDown); document.addEventListener('keyup', handleKeyUp); } //------------------------------------------------ // FEED & SPLIT //------------------------------------------------ function startMacroFeed() { if (isMacroFeeding) return; isMacroFeeding = true; showNotification('Macro feeding started'); window.core?.eject?.(); macroFeedInterval = setInterval(() => { window.core?.eject?.(); }, CONFIG.feedRate); } function stopMacroFeed() { if (!isMacroFeeding) return; clearInterval(macroFeedInterval); macroFeedInterval = null; isMacroFeeding = false; showNotification('Macro feeding stopped'); } function performMultiSplit(count) { if (!window.core?.playerHasCells || !window.core.playerHasCells()) { showNotification('Cannot split when dead'); return; } showNotification(`${count}x Split`); for (let i = 0; i < count; i++) { setTimeout(() => { window.core.split?.(); }, CONFIG.splitDelay * i); } } //------------------------------------------------ // STRAIGHT LINE & VERTICAL LINE //------------------------------------------------ function toggleStraightLineMode() { isStraightLineMode = !isStraightLineMode; if (isStraightLineMode) { startingMousePosition.x = currentMousePosition.x; startingMousePosition.y = currentMousePosition.y; showNotification('Straight line mode ON'); } else { showNotification('Straight line mode OFF'); } } function applyLineConstraint() { if (!isStraightLineMode) return; const dx = currentMousePosition.x - startingMousePosition.x; const dy = currentMousePosition.y - startingMousePosition.y; const angle = Math.atan2(dy, dx); const snappedAngle = Math.round(angle / (Math.PI / 4)) * (Math.PI / 4); const distance = Math.sqrt(dx*dx + dy*dy); const newX = startingMousePosition.x + Math.cos(snappedAngle) * distance; const newY = startingMousePosition.y + Math.sin(snappedAngle) * distance; window.core?.setTarget?.(newX, newY); } function setVerticalLinePosition() { if (!gameCanvas || !window.core) return; const X = window.innerWidth / 2; const Y = window.innerHeight / 2.006; window.core.setTarget(X, Y); showNotification('Vertical Line Position'); } //------------------------------------------------ // PAUSE (FREEZE) //------------------------------------------------ function onPointerLockChange() { if (document.pointerLockElement !== gameCanvas) { isPaused = false; disableFreeze(); } } function togglePause() { isPaused = !isPaused; if (isPaused) { enableFreeze(); showNotification('⏸️ GAME PAUSED ⏸️', true); } else { disableFreeze(); showNotification('▶️ GAME RESUMED'); } } function enableFreeze() { // 1. Get center of screen for cursor lock const canvas = document.querySelector('canvas'); if (canvas) { const rect = canvas.getBoundingClientRect(); lockPosition.x = rect.left + rect.width / 2; lockPosition.y = rect.top + rect.height / 2; } else { lockPosition.x = window.innerWidth / 2; lockPosition.y = window.innerHeight / 2; } // 2. Enable cursor lock if enabled if (cursorLockEnabled) { startCursorLock(); } } function disableFreeze() { if (lockInterval) { clearInterval(lockInterval); lockInterval = null; } } function startCursorLock() { if (lockInterval) clearInterval(lockInterval); lockInterval = setInterval(() => { if (isPaused && window.core && typeof window.core.setTarget === 'function') { window.core.setTarget(lockPosition.x, lockPosition.y); } }, 1); // More frequent updates (1ms) for stability } function interceptCoreForFreeze() { const checkForCore = setInterval(() => { if (window.core && typeof window.core.setTarget === 'function') { originalSetTarget = window.core.setTarget; window.core.setTarget = function(x, y) { if (isPaused) { if (x === lockPosition.x && y === lockPosition.y) { return originalSetTarget.call(this, x, y); } return; } return originalSetTarget.call(this, x, y); }; clearInterval(checkForCore); } }, 100); } function interceptWebSocket() { // Store original WebSocket constructor const OriginalWebSocket = window.WebSocket; // Replace with our proxy version window.WebSocket = function(url, protocols) { console.log('WebSocket intercepted:', url); // Create actual WebSocket const ws = new OriginalWebSocket(url, protocols); // Store original send function originalSendFunction = ws.send; // Override send function ws.send = function(data) { // If frozen and this is a movement packet, block it if (isPaused && isMouseMovementPacket(data)) { // Don't send the packet console.log('Blocked movement packet'); return; } // Otherwise send normally return originalSendFunction.apply(this, arguments); }; return ws; }; // Copy properties from original WebSocket window.WebSocket.prototype = OriginalWebSocket.prototype; window.WebSocket.CONNECTING = OriginalWebSocket.CONNECTING; window.WebSocket.OPEN = OriginalWebSocket.OPEN; window.WebSocket.CLOSING = OriginalWebSocket.CLOSING; window.WebSocket.CLOSED = OriginalWebSocket.CLOSED; } function isMouseMovementPacket(data) { if (data instanceof ArrayBuffer || data instanceof Uint8Array) { // Convert to Uint8Array if needed const dataView = data instanceof ArrayBuffer ? new Uint8Array(data) : data; // Most Agar.io clients use opcode 16 or 0x10 for mouse movement if (dataView.length > 0 && (dataView[0] === 16 || dataView[0] === 0x10)) { return true; } // Backup detection - movement packets are typically small if (dataView.length >= 9 && dataView.length <= 13) { return true; } } return false; } //------------------------------------------------ // TOGGLES & FEATURES //------------------------------------------------ function toggleAcidMode(enable) { CONFIG.enableAcidMode = enable; if (window.core) { window.core.setAcid(CONFIG.enableAcidMode); } saveConfig(CONFIG); showNotification(CONFIG.enableAcidMode ? 'Acid Mode: ON' : 'Acid Mode: OFF'); } function toggleMinimap(enable) { if (!window.core) return; CONFIG.enableMinimap = enable; window.core.setMinimap(CONFIG.enableMinimap); if (CONFIG.enableMinimap) { window.core.minimizeMinimap(CONFIG.minimizeMap); window.core.playersMinimap(CONFIG.showPlayersOnMap); showNotification('Minimap: ON'); } else { showNotification('Minimap: OFF'); } saveConfig(CONFIG); } function togglePlayersOnMap(enable) { if (!window.core || !CONFIG.enableMinimap) return; CONFIG.showPlayersOnMap = enable; window.core.playersMinimap(CONFIG.showPlayersOnMap); showNotification(CONFIG.showPlayersOnMap ? 'Players on Map: ON' : 'Players on Map: OFF'); saveConfig(CONFIG); } //------------------------------------------------ // DATA COLLECTION //------------------------------------------------ function setupNameCollection() { if (window._namesToolInitialized) return; window._namesToolInitialized = true; const originalFillText = CanvasRenderingContext2D.prototype.fillText; CanvasRenderingContext2D.prototype.fillText = function(text, x, y) { if (text.match(/^([0-9]+)\.(.+)$/)) { const parts = text.split('.'); const position = parseInt(parts[0]); const name = parts[1].trim(); leaderboardData[position] = name; } else if (text.match(/^score:\s([0-9]+)$/i)) { playerScore = parseInt(text.split(/score:\s([0-9]+)?/i)[1]); } else if ( text && text.length <= 15 && !text.match(/(leaderboard|connect|loading|starting\smass|xp\sboost|open\sshop|([0-9]{2})m\s(([0-9]{2})h\s)?([0-9]{2})s)/i) && !isScoreNumber(text) // Add this check ) { cellNames.add(text); } return originalFillText.call(this, text, x, y); }; } // Add this helper function to check if text is a score number function isScoreNumber(text) { // Check if the text is only digits const onlyDigits = /^\d+$/.test(text); if (onlyDigits) { const num = parseInt(text); // Check if it's in the score range (10 to 22500) return num >= 10 && num <= 22500; } return false; } //------------------------------------------------ // SKIN MANAGEMENT //------------------------------------------------ let originalSkin = null; function captureOriginalSkin() { try { const localData = localStorage.getItem('ogarioSettings'); if (localData) { const settings = JSON.parse(localData); if (settings && settings.skin) { originalSkin = settings.skin; } } } catch(e) { // ignore } const obs = new MutationObserver((mutations, o) => { const sp = document.querySelector('#skin-preview img'); if (sp && sp.src) { originalSkin = sp.src; o.disconnect(); } }); obs.observe(document.body, { childList:true, subtree:true }); } function applyCustomSkin(url) { if (!window.core) return; try { if (!originalSkin) captureOriginalSkin(); window.core.registerSkin(null, 'customskin', url, 0, 0); window.core.loadSkin('customskin'); CONFIG.customSkinUrl = url; CONFIG.enableCustomSkin = true; saveConfig(CONFIG); showNotification('Custom skin applied'); } catch (e) { showNotification('Failed to apply skin: ' + e.message); } } function registerEnemySkin(name, url) { if (!window.core) return false; try { window.core.registerSkin(name.toLowerCase(), null, url, 2, null); return true; } catch(e) { console.error('Error registering skin:', e); return false; } } function applyAllEnemySkins() { let count = 0; for (const name in enemySkins) { if (registerEnemySkin(name, enemySkins[name])) { count++; } } showNotification(`Applied ${count} enemy skins`); } function loadSkinsFromStorage() { try { const stored = localStorage.getItem('myCustomSkins'); return stored ? JSON.parse(stored) : []; } catch(e) { return []; } } function saveSkinsToStorage(arr) { localStorage.setItem('myCustomSkins', JSON.stringify(arr)); } function loadEnemySkins() { try { const stored = localStorage.getItem('agarioEnemySkins'); if (stored) enemySkins = JSON.parse(stored); } catch(e) { console.error('Error loading enemy skins:', e); enemySkins = {}; } } function saveEnemySkins() { localStorage.setItem('agarioEnemySkins', JSON.stringify(enemySkins)); } //------------------------------------------------ // CHECK CORE & INIT //------------------------------------------------ function checkCoreAccess() { if (typeof window.core === 'undefined') { setTimeout(checkCoreAccess, 1000); return; } console.log('Core access established'); if (CONFIG.enableMinimap) { window.core.setMinimap(true); window.core.minimizeMinimap(CONFIG.minimizeMap); window.core.playersMinimap(CONFIG.showPlayersOnMap); } if (CONFIG.enableAcidMode) { window.core.setAcid(true); } if (CONFIG.unlimitedFps) { setUnlimitedFps(true); if (window.core.setFpsCap) { window.core.setFpsCap(0); setTimeout(() => window.core.setFpsCap(0), 1000); } } } //------------------------------------------------ // RUSSIA -> UKRAINE //------------------------------------------------ function initRussiaToUkraine() { function replaceText() { const options = document.querySelectorAll('option[value="RU-Russia"]'); options.forEach(opt => { if (opt.textContent.includes('Russia')) { opt.textContent = opt.textContent.replace('Russia','Ukraine'); } }); } replaceText(); if (document.body) { const obs = new MutationObserver(replaceText); obs.observe(document.body, { childList:true, subtree:true }); } else { document.addEventListener('DOMContentLoaded', () => { const obs = new MutationObserver(replaceText); obs.observe(document.body, { childList:true, subtree:true }); }); } } //------------------------------------------------ // INCREASE NICK LIMIT //------------------------------------------------ function increaseNickLimit() { const updateNickInput = () => { const nickInputs = document.querySelectorAll('input[id="nick"], input[placeholder="Nick"], input[maxlength="15"]'); if (nickInputs.length > 0) { nickInputs.forEach(input => input.setAttribute('maxlength', '50')); showNotification('Nickname limit increased to 50'); } else { setTimeout(updateNickInput, 2000); } }; updateNickInput(); try { document.addEventListener('DOMContentLoaded', () => { const observer = new MutationObserver(mutations => { for (const mutation of mutations) { if (mutation.type === 'childList' && mutation.addedNodes.length) { mutation.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { const inputs = node.querySelectorAll ? node.querySelectorAll('input[id="nick"], input[placeholder="Nick"], input[maxlength="15"]') : []; if ( node.tagName === 'INPUT' && ( node.id === 'nick' || node.placeholder === 'Nick' || node.getAttribute('maxlength') === '15' ) ) { node.setAttribute('maxlength', '50'); } inputs.forEach(inp => inp.setAttribute('maxlength', '50')); } }); } } }); observer.observe(document.body, { childList: true, subtree: true }); }); } catch (e) { console.error('Error with MutationObserver for nick limit:', e); } } //------------------------------------------------ // MAIN UI //------------------------------------------------ function createShowControlsButton() { // Create container for the buttons const buttonContainer = document.createElement('div'); buttonContainer.id = 'controls-button-container'; buttonContainer.style.cssText = ` position: fixed; top: 10px; left: 10px; z-index: 99999; display: flex; gap: 5px; `; // Create the show controls button showControlsButton = document.createElement('button'); showControlsButton.id = 'show-controls-button'; showControlsButton.textContent = 'Show Controls'; showControlsButton.style.cssText = ` padding: 5px 10px; background-color: ${COLORS.buttonBg}; color: #fff; border: none; border-radius: 5px; cursor: pointer; font-family: Arial, sans-serif; transition: background-color 0.2s ease; `; // Create close button const closeButton = document.createElement('button'); closeButton.id = 'close-controls-button'; closeButton.textContent = '×'; closeButton.style.cssText = ` padding: 5px 8px; background-color: #f44336; color: #fff; border: none; border-radius: 5px; cursor: pointer; font-family: Arial, sans-serif; font-size: 16px; font-weight: bold; transition: background-color 0.2s ease; `; // Add hover effects for show controls button showControlsButton.addEventListener('mouseover', () => { showControlsButton.style.backgroundColor = COLORS.buttonBgPress; }); showControlsButton.addEventListener('mouseout', () => { showControlsButton.style.backgroundColor = COLORS.buttonBg; }); showControlsButton.addEventListener('mousedown', () => { showControlsButton.style.backgroundColor = COLORS.buttonBgPress; }); showControlsButton.addEventListener('mouseup', () => { showControlsButton.style.backgroundColor = COLORS.buttonBg; }); // Add hover effects for close button closeButton.addEventListener('mouseover', () => { closeButton.style.backgroundColor = '#d32f2f'; }); closeButton.addEventListener('mouseout', () => { closeButton.style.backgroundColor = '#f44336'; }); // Add click handlers showControlsButton.onclick = toggleMainOverlay; closeButton.onclick = () => { buttonContainer.style.display = 'none'; showToast(`Controls hidden. Press "${CONFIG.toggleUIKey.toUpperCase()}" to show again.`); }; // Add buttons to container buttonContainer.appendChild(showControlsButton); buttonContainer.appendChild(closeButton); // Add container to body document.body.appendChild(buttonContainer); // Show initial toast message about hotkey setTimeout(() => { showToast(`Tip: Press "${CONFIG.toggleUIKey.toUpperCase()}" to toggle controls panel.`); }, 2000); } // Add this function for toast notifications function showToast(message, duration = 3000) { let toast = document.getElementById('controls-toast'); if (!toast) { toast = document.createElement('div'); toast.id = 'controls-toast'; toast.style.cssText = ` position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background-color: rgba(0, 0, 0, 0.8); color: #fff; padding: 10px 20px; border-radius: 5px; font-family: Arial, sans-serif; font-size: 14px; z-index: 1000000; transition: opacity 0.5s; pointer-events: none; `; document.body.appendChild(toast); } // Set message and show toast toast.textContent = message; toast.style.opacity = '1'; // Clear any existing timeout if (toast.hideTimeout) { clearTimeout(toast.hideTimeout); } // Set timeout to hide the toast toast.hideTimeout = setTimeout(() => { toast.style.opacity = '0'; }, duration); } function createMainOverlay() { if (mainOverlay) return; mainOverlay = document.createElement('div'); mainOverlay.id = 'main-overlay'; mainOverlay.style.cssText = ` display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(255, 255, 255, 0.85); padding: 20px; border-radius: 10px; z-index: 999999; width: 900px; max-width: 90vw; max-height: 90vh; overflow-y: auto; color: ${COLORS.normalText}; font-family: Arial, sans-serif; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); `; // Title bar const topBar = document.createElement('div'); topBar.style.cssText = 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;'; const title = document.createElement('h2'); title.textContent = '🕹️ Mod'; title.style.cssText = `margin: 0; color: ${COLORS.headingText};`; topBar.appendChild(title); // Close button const closeOverlayBtn = document.createElement('button'); closeOverlayBtn.textContent = 'Close'; closeOverlayBtn.style.cssText = ` background-color: ${COLORS.buttonBg}; color: white; border: none; border-radius: 5px; padding: 5px 10px; cursor: pointer; font-weight: bold; `; closeOverlayBtn.addEventListener('mouseover', () => { closeOverlayBtn.style.backgroundColor = COLORS.buttonBgPress; }); closeOverlayBtn.addEventListener('mouseout', () => { closeOverlayBtn.style.backgroundColor = COLORS.buttonBg; }); closeOverlayBtn.addEventListener('click', () => { mainOverlay.style.display = 'none'; modUIVisible = false; if (showControlsButton) { showControlsButton.textContent = 'Show Controls'; } }); topBar.appendChild(closeOverlayBtn); mainOverlay.appendChild(topBar); // Content const contentContainer = document.createElement('div'); contentContainer.style.cssText = 'display: flex; flex-wrap: wrap; gap: 20px;'; mainOverlay.appendChild(contentContainer); // Left const leftColumn = document.createElement('div'); leftColumn.style.cssText = 'flex: 1; min-width: 320px;'; contentContainer.appendChild(leftColumn); // Right const rightColumn = document.createElement('div'); rightColumn.style.cssText = 'flex: 1; min-width: 320px;'; contentContainer.appendChild(rightColumn); // Mouse/Skins const mouseBindingsDiv = document.createElement('div'); mouseBindingsDiv.innerHTML = ` <h3 style="color: ${COLORS.headingText}; border-bottom: 1px solid ${COLORS.headingText}; padding-bottom: 5px;"> Mouse Actions & Skins </h3> `; buildMouseBindingsUI(mouseBindingsDiv); leftColumn.appendChild(mouseBindingsDiv); // Hotkeys const hotkeysContainer = document.createElement('div'); hotkeysContainer.style.marginBottom = '20px'; hotkeysContainer.innerHTML = ` <h3 style="color: ${COLORS.headingText}; border-bottom: 1px solid ${COLORS.headingText}; padding-bottom: 5px;"> Hotkeys </h3> `; buildPCHotkeysUI(hotkeysContainer); leftColumn.appendChild(hotkeysContainer); // Game Options const optionsContainer = document.createElement('div'); optionsContainer.innerHTML = ` <h3 style="color: ${COLORS.headingText}; border-bottom: 1px solid ${COLORS.headingText}; padding-bottom: 5px;"> Game Options </h3> `; buildGameOptionsUI(optionsContainer); rightColumn.appendChild(optionsContainer); // Player Data const playerDataContainer = document.createElement('div'); playerDataContainer.innerHTML = ` <h3 style="color: ${COLORS.headingText}; border-bottom: 1px solid ${COLORS.headingText}; padding-bottom: 5px;"> Player Data & Skins </h3> `; buildPlayerDataButton(playerDataContainer); rightColumn.appendChild(playerDataContainer); // Links to free skins const skinsLinkContainer = document.createElement('div'); skinsLinkContainer.style.cssText = 'margin-top: 20px;'; const linkHeading = document.createElement('h4'); linkHeading.textContent = 'Free Skin URLs:'; linkHeading.style.cssText = `color: ${COLORS.headingText}; margin-bottom: 6px; text-shadow: 1px 1px 1px grey;`; skinsLinkContainer.appendChild(linkHeading); const link1 = document.createElement('a'); link1.href = 'https://agario-skin.glitch.me/'; link1.target = '_blank'; link1.textContent = 'https://agario-skin.glitch.me/'; link1.style.cssText = ` display: block; color: black; margin-bottom: 6px; text-decoration: underline; text-shadow: 1px 1px 1px grey; `; skinsLinkContainer.appendChild(link1); const link2 = document.createElement('a'); link2.href = 'https://www.legendmod.ml/skins/'; link2.target = '_blank'; link2.textContent = 'https://www.legendmod.ml/skins/'; link2.style.cssText = ` display: block; color: black; margin-bottom: 6px; text-decoration: underline; text-shadow: 1px 1px 1px grey; `; skinsLinkContainer.appendChild(link2); // Add the third link to agario-skins.net const link3 = document.createElement('a'); link3.href = 'https://www.agario-skins.net/'; link3.target = '_blank'; link3.textContent = 'https://www.agario-skins.net/'; link3.style.cssText = ` display: block; color: black; text-decoration: underline; text-shadow: 1px 1px 1px grey; `; skinsLinkContainer.appendChild(link3); rightColumn.appendChild(skinsLinkContainer); // Thank You Note const thanksSection = document.createElement('div'); thanksSection.style.cssText = 'margin-top: 20px;'; const thanksHeader = document.createElement('h4'); thanksHeader.textContent = 'Special Thank You Note:'; thanksHeader.style.cssText = `color: ${COLORS.headingText}; margin-bottom: 6px;`; thanksSection.appendChild(thanksHeader); const thanksNote = document.createElement('p'); thanksNote.style.cssText = `color: ${COLORS.normalText}; font-style: italic;`; thanksNote.innerHTML = 'Special thanks to <a href="https://imsolo.pro/web/" target="_blank" style="color: inherit; text-decoration: underline;">imsolo.pro/web</a> for helping me out – click their link for a different Agar.io game. ' + 'Also, thanks to <a href="https://www.legendmod.ml/" target="_blank" style="color: inherit; text-decoration: underline;">legendmod.ml</a> for helping out. Check out their mod for chat and for playing in private servers. ' + 'Special thanks to <a href="https://www.youtube.com/@BeeChasnyAgario" target="_blank" style="color: inherit; text-decoration: underline;">@BeeChasnyAgario</a> for sharing the first code I ever used – visit his ' + '<a href="https://www.youtube.com/@BeeChasnyAgario" target="_blank" style="color: inherit; text-decoration: underline;">YouTube channel</a> and Thank You to the ' + 'Agar.io community.'; thanksSection.appendChild(thanksNote); rightColumn.appendChild(thanksSection); document.body.appendChild(mainOverlay); } function toggleMainOverlay() { modUIVisible = !modUIVisible; if (mainOverlay) { mainOverlay.style.display = modUIVisible ? 'block' : 'none'; } if (showControlsButton) { showControlsButton.textContent = modUIVisible ? 'Hide Controls' : 'Show Controls'; } } //------------------------------------------------ // MOUSE BINDINGS UI //------------------------------------------------ function buildMouseBindingsUI(container) { const wrapper = document.createElement('div'); wrapper.style.cssText = 'display: flex; flex-wrap: wrap; gap: 20px;'; // Left sub-section (Mouse Actions) const mouseSection = document.createElement('div'); mouseSection.style.cssText = 'flex: 1; min-width: 200px;'; const rowStyle = 'display:flex; align-items:center; justify-content:space-between; margin-bottom:12px;'; const possibleActions = ['none', 'singleFeed', 'macroFeed', 'split']; function makeDropdownRow(labelText, configKey) { const row = document.createElement('div'); row.style.cssText = rowStyle; const lbl = document.createElement('label'); lbl.textContent = labelText; lbl.style.cssText = `font-weight: bold; margin-right: 8px; color: ${COLORS.normalText};`; row.appendChild(lbl); const sel = document.createElement('select'); sel.style.cssText = ` flex:1; margin-left:10px; background:#f0f0f0; color:#000; border-radius:4px; border:1px solid #444; padding:8px; cursor: pointer; font-family: Arial, sans-serif; `; possibleActions.forEach(act => { const opt = document.createElement('option'); opt.value = act; opt.textContent = act; sel.appendChild(opt); }); sel.value = CONFIG[configKey]; sel.addEventListener('change', () => { CONFIG[configKey] = sel.value; saveConfig(CONFIG); showNotification(`${labelText} => ${sel.value}`); }); row.appendChild(sel); return row; } mouseSection.appendChild(makeDropdownRow('Left Mouse', 'leftMouseAction')); mouseSection.appendChild(makeDropdownRow('Middle Mouse', 'middleMouseAction')); mouseSection.appendChild(makeDropdownRow('Right Mouse', 'rightMouseAction')); wrapper.appendChild(mouseSection); // Right sub-section for Named Skins & Emoji placeholders const skinsSection = document.createElement('div'); skinsSection.style.cssText = 'flex: 1; min-width: 200px;'; // Named Skins List const namedSkinsLabel = document.createElement('label'); namedSkinsLabel.textContent = 'Free Named Skins List:'; namedSkinsLabel.style.cssText = ` display: block; margin-bottom: 5px; font-weight: bold; color: ${COLORS.normalText}; `; skinsSection.appendChild(namedSkinsLabel); const namedSkinsSelect = document.createElement('select'); namedSkinsSelect.style.cssText = ` width: 100%; background:#f0f0f0; color: #000; border-radius: 4px; border:1px solid #444; padding:8px; margin-bottom: 15px; cursor: pointer; `; // Populate with skin names from the provided list const skinNames = [ "2Ch.Hk", "3Ezzy", "3Lk", "4Chan", "7Modka", "8", "9Gag", "Agar.ionews", "Agario", "Agarmurfs", "Albania", "Alejo", "Alejoyoutube", "Alejoyt", "Alejoyt2", "Araizon", "Argentina", "Ashwin", "Ashwinyt", "Australia", "Austria", "Ayy Lmao", "Babadook", "Bahrain", "Bait", "Bang", "Bangladesh", "Belgium", "Berlusconi", "Blatter", "Boris", "Bosnia", "Botswana", "Brax", "Brazil", "Bulba", "Bulgaria", "Bush", "Byzantium", "Cambodia", "Cameron", "Canada", "Chaplin", "Char", "Chavez", "Chile", "China", "Cia", "Clinton", "Colombia", "Croatia", "Crystal", "Cuba", "Demon", "Denmark", "Dilma", "Dna Clan", "Doge", "Ea", "Earth", "Egypt", "Estonia", "European Union", "Evilmonkey", "Facebook", "Facepunch", "Feminism", "Fidel", "Finland", "Football", "France", "French Kingdom", "Gdk Xmas", "German Empire", "Germany", "Getdeadkid", "Greece", "Guri", "Hero", "Hillary", "Hollande", "Hong Kong", "Hungary", "Imperial Japan", "India", "Indiana", "Indonesia", "Iran", "Iraq", "Ireland", "Irs", "Italy", "Jamaica", "Japan", "Jonnn", "Jordan", "Kbkb", "Kim Jong-Un", "Kristoffer", "Kurdistan", "Kuwait", "Latvia", "Lebanon", "Lithuania", "Luxembourg", "Majnoon", "Maldives", "Mars", "Matjoy", "Matriarchy", "Merkel", "Mexico", "Minhvu", "Mister", "Mistik", "Moon", "N0Psa", "Nasa", "Nbrhmi", "Netherlands", "Nigeria", "North Korea", "Norway", "Obama", "Origin", "Pakistan", "Palin", "Patriarchy", "Peru", "Piccolo", "Pika", "Pok", "Pokerface", "Pokyt", "Poland", "Portugal", "Prodota", "Prussia", "Qing Dynasty", "Quebec", "Queen", "Rayday", "Receita Federal", "Reddit", "Romania", "Sanik", "Sarok1", "Sarok2", "Saudi Arabia", "Scotland", "Sealand", "Silver", "Sir", "Sirius", "Skills", "Skillsyt", "Sneddy Gaming", "Somalia", "Sonic", "Sonicgames", "South Africa", "South Korea", "Spain", "Sparky", "Squi", "Stalin", "Statik", "Steam", "Strike", "Stussy", "Sweden", "Switzerland", "Taiwan", "Texas", "Thailand", "Timid", "Togoman", "Togomanyt", "Trump", "Tsipras", "Tumblr", "Turkey", "Twisted", "Tyt", "Uae", "Ukraine", "United Kingdom", "Usa", "Varoufakis", "Venezuela", "Vinesauce", "Wojak", "Woobs", "Xxnetro", "Xxnetro2", "Yaranaika", "Yemeni", "Yemeniyt", "Zanax", "Zone" ]; // Clear any default placeholder and add each skin name as an option namedSkinsSelect.innerHTML = ''; skinNames.forEach(name => { const option = document.createElement('option'); option.value = name; option.textContent = name; namedSkinsSelect.appendChild(option); }); skinsSection.appendChild(namedSkinsSelect); // Add a copy button for the selected skin name const copySkinButton = document.createElement('button'); copySkinButton.textContent = 'Copy Skin Name'; copySkinButton.style.cssText = ` margin-top: 5px; cursor: pointer; background-color: #54c800; /* Agar.io green */ color: white; font-weight: bold; border: none; border-radius: 4px; padding: 6px 12px; transition: background-color 0.2s ease; `; // Add hover and active (press) effects copySkinButton.addEventListener('mouseover', () => { copySkinButton.style.backgroundColor = '#45a800'; /* Darker green */ }); copySkinButton.addEventListener('mouseout', () => { copySkinButton.style.backgroundColor = '#54c800'; /* Back to Agar.io green */ }); copySkinButton.addEventListener('mousedown', () => { copySkinButton.style.backgroundColor = '#357f00'; /* Even darker green when pressed */ }); copySkinButton.addEventListener('mouseup', () => { copySkinButton.style.backgroundColor = '#45a800'; /* Back to hover state */ }); copySkinButton.addEventListener('click', () => { const selectedSkin = namedSkinsSelect.value; navigator.clipboard.writeText(selectedSkin) .then(() => { showNotification(`Copied skin name: ${selectedSkin}`); // Flash effect to indicate copy success copySkinButton.style.backgroundColor = '#357f00'; /* Darker green flash */ setTimeout(() => { copySkinButton.style.backgroundColor = '#54c800'; /* Back to normal */ }, 300); }) .catch(err => showNotification(`Failed to copy skin name: ${err}`)); }); skinsSection.appendChild(copySkinButton); // Emoji List const emojiLabel = document.createElement('label'); emojiLabel.textContent = 'Emoji List:'; emojiLabel.style.cssText = ` display: block; margin-bottom: 5px; font-weight: bold; color: ${COLORS.normalText}; `; skinsSection.appendChild(emojiLabel); const emojiSelect = document.createElement('select'); emojiSelect.style.cssText = ` width: 100%; background:#f0f0f0; color: #000; border-radius: 4px; border:1px solid #444; padding:8px; cursor: pointer; `; // Populate with a sample list of emojis const emojis = [ "😀", "😂", "🤣", "😊", "😍", "😘", "😜", "🤪", "😎", "😏", "😢", "😭", "😡", "👍", "👏", "🙏", "💯", "🎉", "❤️", "🧡", "💛", "💚", "💙", "💜", "🤍", "🤎", "🥰", "🤗", "🤩", "🥳", "🤔", "🤭", "🤫", "🤯", "😤", "😴", "😇", "😲", "🤤", "😋", "🤠", "😺", "😻", "😼", "😽", "😹", "😿", "😸", "🙀", "😾" ]; // Clear any default content and add emojis emojiSelect.innerHTML = ''; emojis.forEach(emoji => { const option = document.createElement('option'); option.value = emoji; option.textContent = emoji; emojiSelect.appendChild(option); }); skinsSection.appendChild(emojiSelect); // Add a copy button for the selected emoji const copyEmojiButton = document.createElement('button'); copyEmojiButton.textContent = 'Copy Emoji'; copyEmojiButton.style.cssText = ` margin-top: 5px; cursor: pointer; background-color: #54c800; /* Agar.io green */ color: white; font-weight: bold; border: none; border-radius: 4px; padding: 6px 12px; transition: background-color 0.2s ease; `; // Add hover and active (press) effects copyEmojiButton.addEventListener('mouseover', () => { copyEmojiButton.style.backgroundColor = '#45a800'; /* Darker green */ }); copyEmojiButton.addEventListener('mouseout', () => { copyEmojiButton.style.backgroundColor = '#54c800'; /* Back to Agar.io green */ }); copyEmojiButton.addEventListener('mousedown', () => { copyEmojiButton.style.backgroundColor = '#357f00'; /* Even darker green when pressed */ }); copyEmojiButton.addEventListener('mouseup', () => { copyEmojiButton.style.backgroundColor = '#45a800'; /* Back to hover state */ }); copyEmojiButton.addEventListener('click', () => { const selectedEmoji = emojiSelect.value; navigator.clipboard.writeText(selectedEmoji) .then(() => { showNotification(`Copied emoji: ${selectedEmoji}`); // Flash effect to indicate copy success copyEmojiButton.style.backgroundColor = '#357f00'; /* Darker green flash */ setTimeout(() => { copyEmojiButton.style.backgroundColor = '#54c800'; /* Back to normal */ }, 300); }) .catch(err => showNotification(`Failed to copy emoji: ${err}`)); }); skinsSection.appendChild(copyEmojiButton); wrapper.appendChild(skinsSection); container.appendChild(wrapper); } //------------------------------------------------ // HOTKEYS UI (WITH OFFERS SLIDER ADDED) //------------------------------------------------ function buildPCHotkeysUI(container) { const keysToDisplay = [ { label: 'Single Feed', key: 'singleFeedKey' }, { label: 'Macro Feed', key: 'macroFeedKey' }, { label: 'Double Split', key: 'doubleSplitKey' }, { label: 'Triple Split', key: 'tripleSplitKey' }, { label: 'Quad Split', key: 'quadSplitKey' }, { label: 'Vertical Line', key: 'verticalLineKey' }, { label: 'Skin Switcher', key: 'skinSwitcherKey' }, { label: 'Toggle UI', key: 'toggleUIKey' }, { label: 'Pause Movement', key: 'pauseMovementKey' } ]; // Build rows for each hotkey keysToDisplay.forEach(item => { container.appendChild(createHotkeyRow(item.label, item.key)); }); // AFTER the hotkeys, add a slider to call MC.activateAllOffers() // We'll replicate a "toggle" style row const offersToggleRow = document.createElement('div'); offersToggleRow.style.cssText = ` margin-top: 15px; padding: 10px; background: rgba(255,255,255,0.05); border-radius: 5px; display: flex; justify-content: space-between; align-items: center; `; const offersLabel = document.createElement('span'); offersLabel.textContent = 'Activate All Offers'; offersLabel.style.cssText = `font-weight: bold; color: ${COLORS.normalText};`; offersToggleRow.appendChild(offersLabel); const toggleSwitch = document.createElement('label'); toggleSwitch.style.cssText = ` position: relative; display: inline-block; width:60px; height:30px; cursor: pointer; `; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.checked = CONFIG.activateAllOffers; checkbox.style.cssText = 'opacity:0; width:0; height:0;'; toggleSwitch.appendChild(checkbox); const slider = document.createElement('span'); slider.style.cssText = ` position:absolute; top:0; left:0; right:0; bottom:0; transition:0.4s; border-radius:30px; background-color:${CONFIG.activateAllOffers ? COLORS.buttonBg : COLORS.sliderOff}; `; const circle = document.createElement('span'); circle.style.cssText = ` position:absolute; content:''; height:22px; width:22px; bottom:4px; left:${CONFIG.activateAllOffers ? '34px' : '4px'}; background-color:#fff; transition:0.4s; border-radius:50%; `; slider.appendChild(circle); toggleSwitch.appendChild(slider); checkbox.addEventListener('change', function() { CONFIG.activateAllOffers = this.checked; slider.style.backgroundColor = this.checked ? COLORS.buttonBg : COLORS.sliderOff; circle.style.left = this.checked ? '34px' : '4px'; saveConfig(CONFIG); // If turned ON, try calling MC.activateAllOffers() if (this.checked) { console.log('ActivateAllOffers slider ON: trying MC.activateAllOffers()...'); try { if (typeof MC !== 'undefined' && typeof MC.activateAllOffers === 'function') { MC.activateAllOffers(); showNotification('All Offers Activated!'); } else { console.warn('MC.activateAllOffers() not found.'); showNotification('MC.activateAllOffers() not found in console.'); } } catch (err) { console.error('Error calling MC.activateAllOffers():', err); } } }); offersToggleRow.appendChild(toggleSwitch); container.appendChild(offersToggleRow); // Add server info section const serverInfoRow = document.createElement('div'); serverInfoRow.style.cssText = ` margin-top: 15px; padding: 10px; background: rgba(255,255,255,0.05); border-radius: 5px; display: flex; flex-direction: column; `; const serverLabel = document.createElement('span'); serverLabel.textContent = 'Your Game Server:'; serverLabel.style.cssText = ` font-weight: bold; color: ${COLORS.normalText}; margin-bottom: 8px; `; serverInfoRow.appendChild(serverLabel); // Create display for server info const serverDisplay = document.createElement('div'); serverDisplay.style.cssText = ` display: flex; justify-content: space-between; align-items: center; `; const serverInfo = document.createElement('input'); serverInfo.id = 'server-info'; serverInfo.readOnly = true; serverInfo.style.cssText = ` flex: 1; padding: 8px; margin-right: 10px; border: 1px solid #777; border-radius: 4px; background: #f0f0f0; color: #333; font-family: monospace; font-size: 12px; `; // Create a refresh button const refreshBtn = document.createElement('button'); refreshBtn.textContent = '🔄'; refreshBtn.title = 'Refresh Server Info'; refreshBtn.style.cssText = ` background-color: ${COLORS.buttonBg}; color: white; border: none; border-radius: 4px; padding: 8px; cursor: pointer; font-weight: bold; transition: background-color 0.2s; `; refreshBtn.addEventListener('mouseover', () => { refreshBtn.style.backgroundColor = COLORS.buttonBgPress; }); refreshBtn.addEventListener('mouseout', () => { refreshBtn.style.backgroundColor = COLORS.buttonBg; }); // Create copy button const copyBtn = document.createElement('button'); copyBtn.textContent = '📋'; copyBtn.title = 'Copy Server Info'; copyBtn.style.cssText = ` background-color: ${COLORS.buttonBg}; color: white; border: none; border-radius: 4px; padding: 8px; cursor: pointer; font-weight: bold; margin-left: 5px; transition: background-color 0.2s; `; copyBtn.addEventListener('mouseover', () => { copyBtn.style.backgroundColor = COLORS.buttonBgPress; }); copyBtn.addEventListener('mouseout', () => { copyBtn.style.backgroundColor = COLORS.buttonBg; }); serverDisplay.appendChild(serverInfo); serverDisplay.appendChild(refreshBtn); serverDisplay.appendChild(copyBtn); serverInfoRow.appendChild(serverDisplay); // Add a small note with instructions const helpText = document.createElement('div'); helpText.textContent = 'Share this with friends to play on the same server'; helpText.style.cssText = ` font-size: 12px; color: #888; margin-top: 5px; font-style: italic; `; serverInfoRow.appendChild(helpText); // Add event listeners for the buttons refreshBtn.addEventListener('click', () => { try { if (typeof MC !== 'undefined' && typeof MC.getHost === 'function') { const serverAddress = MC.getHost(); serverInfo.value = serverAddress; showNotification('Server info updated!'); } else { console.warn('MC.getHost() not found.'); serverInfo.value = 'Server info not available'; showNotification('Server info not available'); } } catch (err) { console.error('Error getting server info:', err); serverInfo.value = 'Error: ' + err.message; } }); copyBtn.addEventListener('click', () => { if (serverInfo.value) { navigator.clipboard.writeText(serverInfo.value) .then(() => { showNotification('Server info copied to clipboard!'); // Visual feedback copyBtn.style.backgroundColor = COLORS.buttonBgPress; setTimeout(() => { copyBtn.style.backgroundColor = COLORS.buttonBg; }, 300); }) .catch(err => { showNotification('Failed to copy: ' + err); }); } else { showNotification('No server info to copy'); } }); // Initial attempt to get server info setTimeout(() => { try { if (typeof MC !== 'undefined' && typeof MC.getHost === 'function') { serverInfo.value = MC.getHost(); } else { serverInfo.value = 'Click refresh to check'; } } catch (err) { serverInfo.value = 'Click refresh to check'; } }, 1000); container.appendChild(serverInfoRow); } function createHotkeyRow(label, configKey) { const row = document.createElement('div'); row.style.cssText = 'display:flex; align-items:center; margin-bottom:8px;'; const lbl = document.createElement('span'); lbl.textContent = label + ': '; lbl.style.cssText = `width: 130px; color: ${COLORS.normalText};`; row.appendChild(lbl); const inp = document.createElement('input'); inp.type = 'text'; inp.readOnly = true; inp.value = CONFIG[configKey]; inp.style.cssText = ` width: 50px; text-align:center; border:1px solid #777; border-radius:3px; background:#f0f0f0; color:black; cursor:pointer; padding: 5px; font-family: Arial, sans-serif; `; row.appendChild(inp); let waitingForKey = false; inp.addEventListener('focus', () => { isInputFocused = true; }); inp.addEventListener('blur', () => { setTimeout(() => { isInputFocused = false; }, 100); }); inp.addEventListener('click', () => { waitingForKey = true; inp.value = '???'; inp.focus(); }); inp.addEventListener('keydown', (evt) => { if (!waitingForKey) return; evt.preventDefault(); evt.stopPropagation(); const newKey = evt.key.toLowerCase(); CONFIG[configKey] = newKey; inp.value = newKey; waitingForKey = false; saveConfig(CONFIG); showNotification(`${label} => ${newKey.toUpperCase()}`); }); return row; } //------------------------------------------------ // GAME OPTIONS UI //------------------------------------------------ function buildGameOptionsUI(container) { container.appendChild(createToggleRow( 'Acid Mode', 'Enable colorful visual effects', CONFIG.enableAcidMode, function() { CONFIG.enableAcidMode = this.checked; toggleAcidMode(this.checked); } )); container.appendChild(createToggleRow( 'Show FPS Counter', 'Display frames per second counter', CONFIG.showFpsCounter, function() { CONFIG.showFpsCounter = this.checked; updateFpsCounter(); saveConfig(CONFIG); } )); container.appendChild(createToggleRow( 'Unlimited FPS', 'Remove 60 FPS cap (may cause higher CPU/GPU usage)', CONFIG.unlimitedFps, function() { setUnlimitedFps(this.checked); } )); container.appendChild(createToggleRow( 'Show Minimap', 'Display the game minimap', CONFIG.enableMinimap, function() { CONFIG.enableMinimap = this.checked; toggleMinimap(this.checked); } )); container.appendChild(createToggleRow( 'Players on Minimap', 'Show other players on the minimap', CONFIG.showPlayersOnMap, function() { CONFIG.showPlayersOnMap = this.checked; togglePlayersOnMap(this.checked); } )); } function createToggleRow(label, description, isChecked, onChange) { const row = document.createElement('div'); row.style.cssText = ` margin-bottom:15px; background: rgba(255,255,255,0.05); padding: 10px; border-radius: 5px; `; const labelDiv = document.createElement('div'); labelDiv.style.cssText = 'display:flex; justify-content:space-between; margin-bottom:5px;'; const labelSpan = document.createElement('span'); labelSpan.textContent = label; labelSpan.style.cssText = `font-weight: bold; color: ${COLORS.normalText};`; labelDiv.appendChild(labelSpan); const toggleSwitch = document.createElement('label'); toggleSwitch.style.cssText = ` position: relative; display: inline-block; width:60px; height:30px; cursor: pointer; `; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.checked = isChecked; checkbox.style.cssText = 'opacity:0; width:0; height:0;'; checkbox.addEventListener('change', onChange); const slider = document.createElement('span'); slider.style.cssText = ` position:absolute; top:0; left:0; right:0; bottom:0; background-color:${isChecked ? COLORS.buttonBg : COLORS.sliderOff}; transition:0.4s; border-radius:30px; `; const circle = document.createElement('span'); circle.style.cssText = ` position:absolute; content:''; height:22px; width:22px; bottom:4px; left:${isChecked ? '34px' : '4px'}; background-color:white; transition:0.4s; border-radius:50%; `; slider.appendChild(circle); toggleSwitch.appendChild(checkbox); toggleSwitch.appendChild(slider); checkbox.addEventListener('change', function() { slider.style.backgroundColor = this.checked ? COLORS.buttonBg : COLORS.sliderOff; circle.style.left = this.checked ? '34px' : '4px'; }); labelDiv.appendChild(toggleSwitch); row.appendChild(labelDiv); if (description) { const desc = document.createElement('div'); desc.style.cssText = `font-size:14px; color:#000; margin-top:5px;`; desc.textContent = description; row.appendChild(desc); } return row; } //------------------------------------------------ // PLAYER DATA & SKINS MANAGER //------------------------------------------------ // Example color definitions for the new style: const TAB_ACTIVE_COLOR = '#003366'; // Dark blue for the active tab const TAB_INACTIVE_COLOR = '#66a3ff'; // Light blue for the inactive tab const BACKGROUND_COLOR = '#ffffff'; // White background const TEXT_COLOR = '#000'; // Black text const FONT_SIZE = '20px'; // We'll remove references to the old `COLORS.*` and inline the new ones //------------------------------------------------ // PLAYER DATA & SKINS MANAGER //------------------------------------------------ //------------------------------------------------ function buildPlayerDataButton(container) { const btn = document.createElement('button'); btn.textContent = 'Open Player Data & Skins Manager'; btn.style.cssText = ` background-color: #54c800; /* Agar.io green */ color: white; font-weight: bold; border: none; border-radius: 5px; padding: 10px 15px; width: 100%; font-size: 24px; margin-top: 10px; cursor: pointer; transition: background-color 0.2s ease; `; // Add hover and press effects with darker green btn.addEventListener('mouseover', () => { btn.style.backgroundColor = '#45a800'; /* Darker green on hover */ }); btn.addEventListener('mouseout', () => { btn.style.backgroundColor = '#54c800'; /* Return to Agar.io green */ }); btn.addEventListener('mousedown', () => { btn.style.backgroundColor = '#357f00'; /* Even darker green when pressed */ }); btn.addEventListener('mouseup', () => { btn.style.backgroundColor = '#45a800'; /* Back to hover state if still hovering */ }); btn.addEventListener('click', openPlayerDataManager); const description = document.createElement('p'); description.textContent = 'View player names and manage custom skins for yourself and other players.'; description.style.cssText = ` font-size: 16px; margin-top: 10px; color: ${TEXT_COLOR}; `; container.appendChild(btn); container.appendChild(description); } let playerDataManager = null; function openPlayerDataManager() { // Hide main overlay if it's open if (mainOverlay) { mainOverlay.style.display = 'none'; modUIVisible = false; if (showControlsButton) { showControlsButton.textContent = 'Show Controls'; } } if (playerDataManager) { playerDataManager.style.display = 'block'; return; } playerDataManager = document.createElement('div'); playerDataManager.id = 'player-data-manager'; playerDataManager.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 900px; max-width: 90vw; height: 600px; max-height: 90vh; background-color: ${BACKGROUND_COLOR}; border-radius: 10px; padding: 20px; z-index: 1000000; color: ${TEXT_COLOR}; font-family: Arial, sans-serif; display: flex; flex-direction: column; box-shadow: 0 0 20px rgba(0,0,0,0.7); `; const header = document.createElement('div'); header.style.cssText = ` display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; `; const title = document.createElement('h2'); title.textContent = 'Player Data & Skins Manager'; title.style.cssText = ` margin: 0; font-size: ${FONT_SIZE}; color: ${TEXT_COLOR}; `; header.appendChild(title); const closeBtn = document.createElement('button'); closeBtn.textContent = 'X'; closeBtn.style.cssText = ` background: none; border: 2px solid #f33; color: #f33; width: 30px; height: 30px; font-size: 18px; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.2s; `; closeBtn.addEventListener('mouseover', () => { closeBtn.style.backgroundColor = '#f33'; closeBtn.style.color = '#fff'; }); closeBtn.addEventListener('mouseout', () => { closeBtn.style.backgroundColor = 'transparent'; closeBtn.style.color = '#f33'; }); closeBtn.onclick = () => { playerDataManager.style.display = 'none'; isInputFocused = false; }; header.appendChild(closeBtn); playerDataManager.appendChild(header); const contentContainer = document.createElement('div'); contentContainer.style.cssText = ` display: flex; flex: 1; gap: 20px; height: calc(100% - 70px); `; playerDataManager.appendChild(contentContainer); // Left col const leftColumn = document.createElement('div'); leftColumn.style.cssText = 'flex: 1; display: flex; flex-direction: column; height: 100%;'; contentContainer.appendChild(leftColumn); buildPlayerNamesSection(leftColumn); // Right col const rightColumn = document.createElement('div'); rightColumn.style.cssText = 'flex: 1; display: flex; flex-direction: column; height: 100%;'; contentContainer.appendChild(rightColumn); buildSkinsSection(rightColumn); document.body.appendChild(playerDataManager); updatePlayerDataDisplays(); } //------------------------------------ // Build the "Player Names" Section //------------------------------------ function buildPlayerNamesSection(container) { const nameHeader = document.createElement('h3'); nameHeader.textContent = 'Player Names'; nameHeader.style.cssText = ` margin-top: 0; font-size: ${FONT_SIZE}; color: ${TEXT_COLOR}; border-bottom: 2px solid ${TAB_ACTIVE_COLOR}; padding-bottom: 5px; `; container.appendChild(nameHeader); const tabsContainer = document.createElement('div'); tabsContainer.style.cssText = 'display: flex; margin-bottom: 15px;'; function createTab(text, isActive = false) { const tab = document.createElement('div'); tab.textContent = text; tab.style.cssText = ` padding: 8px 15px; cursor: pointer; border-radius: 4px 4px 0 0; margin-right: 5px; transition: background-color 0.2s; font-size: 18px; background-color: ${isActive ? TAB_ACTIVE_COLOR : TAB_INACTIVE_COLOR}; color: #fff; `; return tab; } const leaderboardTab = createTab('Leaderboard', true); const cellNamesTab = createTab('Cell Names'); const scoreTab = createTab('Your Score'); tabsContainer.appendChild(leaderboardTab); tabsContainer.appendChild(cellNamesTab); tabsContainer.appendChild(scoreTab); container.appendChild(tabsContainer); const leaderboardContent = document.createElement('div'); leaderboardContent.id = 'leaderboard-content'; leaderboardContent.style.cssText = ` flex: 1; overflow-y: auto; background-color: #f2f2f2; padding: 10px; border-radius: 4px; margin-bottom: 10px; `; const cellNamesContent = document.createElement('div'); cellNamesContent.id = 'cell-names-content'; cellNamesContent.style.cssText = ` display: none; flex: 1; overflow-y: auto; background-color: #f2f2f2; padding: 10px; border-radius: 4px; margin-bottom: 10px; `; const scoreContent = document.createElement('div'); scoreContent.id = 'score-content'; scoreContent.style.cssText = ` display: none; flex: 1; overflow-y: auto; background-color: #f2f2f2; padding: 10px; border-radius: 4px; margin-bottom: 10px; `; container.appendChild(leaderboardContent); container.appendChild(cellNamesContent); container.appendChild(scoreContent); leaderboardTab.addEventListener('click', () => { leaderboardTab.style.backgroundColor = TAB_ACTIVE_COLOR; cellNamesTab.style.backgroundColor = TAB_INACTIVE_COLOR; scoreTab.style.backgroundColor = TAB_INACTIVE_COLOR; leaderboardContent.style.display = 'block'; cellNamesContent.style.display = 'none'; scoreContent.style.display = 'none'; }); cellNamesTab.addEventListener('click', () => { leaderboardTab.style.backgroundColor = TAB_INACTIVE_COLOR; cellNamesTab.style.backgroundColor = TAB_ACTIVE_COLOR; scoreTab.style.backgroundColor = TAB_INACTIVE_COLOR; leaderboardContent.style.display = 'none'; cellNamesContent.style.display = 'block'; scoreContent.style.display = 'none'; }); scoreTab.addEventListener('click', () => { leaderboardTab.style.backgroundColor = TAB_INACTIVE_COLOR; cellNamesTab.style.backgroundColor = TAB_INACTIVE_COLOR; scoreTab.style.backgroundColor = TAB_ACTIVE_COLOR; leaderboardContent.style.display = 'none'; cellNamesContent.style.display = 'none'; scoreContent.style.display = 'block'; }); // Refresh button const refreshBtnContainer = document.createElement('div'); refreshBtnContainer.style.cssText = 'display: flex; justify-content: flex-end; margin-top: 10px;'; const refreshBtn = document.createElement('button'); refreshBtn.textContent = 'Refresh Data'; refreshBtn.style.cssText = ` background-color: ${TAB_INACTIVE_COLOR}; color: #fff; border: none; border-radius: 4px; padding: 8px 15px; cursor: pointer; font-size: 16px; `; refreshBtn.addEventListener('click', updatePlayerDataDisplays); refreshBtn.addEventListener('mouseover', () => { refreshBtn.style.backgroundColor = TAB_ACTIVE_COLOR; }); refreshBtn.addEventListener('mouseout', () => { refreshBtn.style.backgroundColor = TAB_INACTIVE_COLOR; }); refreshBtnContainer.appendChild(refreshBtn); container.appendChild(refreshBtnContainer); } //------------------------------------ // Build the "Skins Manager" Section //------------------------------------ function buildSkinsSection(container) { const skinsHeader = document.createElement('h3'); skinsHeader.textContent = 'Skins Manager'; skinsHeader.style.cssText = ` margin-top: 0; font-size: ${FONT_SIZE}; color: ${TEXT_COLOR}; border-bottom: 2px solid ${TAB_ACTIVE_COLOR}; padding-bottom: 5px; `; container.appendChild(skinsHeader); const tabsContainer = document.createElement('div'); tabsContainer.style.cssText = 'display: flex; margin-bottom: 15px;'; function createTab(text, isActive = false) { const tab = document.createElement('div'); tab.textContent = text; tab.style.cssText = ` padding: 8px 15px; cursor: pointer; border-radius: 4px 4px 0 0; margin-right: 5px; transition: background-color 0.2s; font-size: 18px; background-color: ${isActive ? TAB_ACTIVE_COLOR : TAB_INACTIVE_COLOR}; color: #fff; `; return tab; } const yourSkinTab = createTab('Your Skin', true); const enemySkinTab = createTab('Enemy Skins'); tabsContainer.appendChild(yourSkinTab); tabsContainer.appendChild(enemySkinTab); container.appendChild(tabsContainer); const yourSkinContent = document.createElement('div'); yourSkinContent.id = 'your-skin-content'; yourSkinContent.style.cssText = ` display: flex; flex-direction: column; flex: 1; overflow-y: auto; background-color: #f2f2f2; padding: 15px; border-radius: 4px; margin-bottom: 10px; `; const enemySkinContent = document.createElement('div'); enemySkinContent.id = 'enemy-skin-content'; enemySkinContent.style.cssText = ` display: none; flex-direction: column; flex: 1; overflow-y: auto; background-color: #f2f2f2; padding: 15px; border-radius: 4px; margin-bottom: 10px; `; container.appendChild(yourSkinContent); container.appendChild(enemySkinContent); yourSkinTab.addEventListener('click', () => { yourSkinTab.style.backgroundColor = TAB_ACTIVE_COLOR; enemySkinTab.style.backgroundColor = TAB_INACTIVE_COLOR; yourSkinContent.style.display = 'flex'; enemySkinContent.style.display = 'none'; }); enemySkinTab.addEventListener('click', () => { yourSkinTab.style.backgroundColor = TAB_INACTIVE_COLOR; enemySkinTab.style.backgroundColor = TAB_ACTIVE_COLOR; yourSkinContent.style.display = 'none'; enemySkinContent.style.display = 'flex'; }); buildYourSkinUI(yourSkinContent); buildEnemySkinUI(enemySkinContent); // Add a button to open the additional skin pages popup const openSkinSitesBtn = document.createElement('button'); openSkinSitesBtn.textContent = 'Open Additional Skin Pages'; openSkinSitesBtn.style.cssText = ` background-color: ${TAB_INACTIVE_COLOR}; color: #fff; border: none; border-radius: 4px; padding: 8px 15px; cursor: pointer; font-size: 16px; margin-top: 10px; font-weight: bold; `; openSkinSitesBtn.addEventListener('mouseover', () => { openSkinSitesBtn.style.backgroundColor = TAB_ACTIVE_COLOR; }); openSkinSitesBtn.addEventListener('mouseout', () => { openSkinSitesBtn.style.backgroundColor = TAB_INACTIVE_COLOR; }); openSkinSitesBtn.addEventListener('click', openSkinSitesPopup); container.appendChild(openSkinSitesBtn); } //------------------------------------ // Popout for the Additional Skin Pages //------------------------------------ function openSkinSitesPopup() { // If it already exists, show it let existing = document.getElementById('skin-sites-popup'); if (existing) { existing.style.display = 'block'; return; } // Create container const popup = document.createElement('div'); popup.id = 'skin-sites-popup'; popup.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 1000px; max-width: 90vw; height: 600px; max-height: 90vh; background-color: ${BACKGROUND_COLOR}; border-radius: 10px; padding: 20px; z-index: 1000001; color: ${TEXT_COLOR}; font-family: Arial, sans-serif; display: flex; flex-direction: column; box-shadow: 0 0 20px rgba(0,0,0,0.7); `; document.body.appendChild(popup); // Header const header = document.createElement('div'); header.style.cssText = ` display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; `; popup.appendChild(header); const title = document.createElement('h2'); title.textContent = 'Additional Skin Pages'; title.style.cssText = ` margin: 0; font-size: ${FONT_SIZE}; color: ${TEXT_COLOR}; `; header.appendChild(title); const closeBtn = document.createElement('button'); closeBtn.textContent = 'X'; closeBtn.style.cssText = ` background: none; border: 2px solid #f33; color: #f33; width: 30px; height: 30px; font-size: 18px; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.2s; `; closeBtn.addEventListener('mouseover', () => { closeBtn.style.backgroundColor = '#f33'; closeBtn.style.color = '#fff'; }); closeBtn.addEventListener('mouseout', () => { closeBtn.style.backgroundColor = 'transparent'; closeBtn.style.color = '#f33'; }); closeBtn.onclick = () => { popup.style.display = 'none'; }; header.appendChild(closeBtn); // Tab buttons for each site const tabContainer = document.createElement('div'); tabContainer.style.cssText = 'display: flex; gap: 10px; margin-bottom: 15px;'; popup.appendChild(tabContainer); const iframeContainer = document.createElement('div'); iframeContainer.style.cssText = ` flex: 1; border: 2px solid ${TAB_ACTIVE_COLOR}; border-radius: 5px; overflow: hidden; position: relative; `; popup.appendChild(iframeContainer); // Add Enemy List tab to the sites array const sites = [ { name: 'Current Skins', url: 'https://agario-skin.glitch.me/index.html', type: 'iframe' }, { name: 'Og Skins', url: 'https://agario-skin.glitch.me/og-skins.html', type: 'iframe' }, { name: 'Enemy List', url: '', type: 'custom' } ]; let currentView = null; sites.forEach((site, i) => { const tabBtn = document.createElement('button'); tabBtn.textContent = site.name; tabBtn.style.cssText = ` background-color: ${i === 0 ? TAB_ACTIVE_COLOR : TAB_INACTIVE_COLOR}; color: #fff; border: none; padding: 10px 20px; border-radius: 4px 4px 0 0; cursor: pointer; font-size: 16px; `; tabBtn.addEventListener('mouseover', () => { if (tabBtn.style.backgroundColor !== TAB_ACTIVE_COLOR) { tabBtn.style.backgroundColor = TAB_ACTIVE_COLOR; tabBtn.style.color = '#fff'; } }); tabBtn.addEventListener('mouseout', () => { if (currentView !== site) { tabBtn.style.backgroundColor = TAB_INACTIVE_COLOR; tabBtn.style.color = '#fff'; } }); tabBtn.addEventListener('click', () => { // Switch to this site or view if (site.type === 'iframe') { switchIframe(site.url); } else if (site.type === 'custom' && site.name === 'Enemy List') { showEnemySkinsList(); } // Update tab colors Array.from(tabContainer.children).forEach(btn => { btn.style.backgroundColor = TAB_INACTIVE_COLOR; }); tabBtn.style.backgroundColor = TAB_ACTIVE_COLOR; currentView = site; }); tabContainer.appendChild(tabBtn); // If first site, load it by default if (i === 0) { switchIframe(site.url); currentView = site; } }); function switchIframe(url) { iframeContainer.innerHTML = ''; const iframe = document.createElement('iframe'); iframe.src = url; iframe.style.cssText = ` width: 100%; height: 500px; border: none; `; // Allow clipboard access iframe.setAttribute("allow", "clipboard-read; clipboard-write"); iframeContainer.appendChild(iframe); } // Function to display the Enemy Skins List function showEnemySkinsList() { iframeContainer.innerHTML = ''; const enemyListContainer = document.createElement('div'); enemyListContainer.style.cssText = ` width: 100%; height: 500px; padding: 15px; overflow-y: auto; background-color: #f8f8f8; `; // Add header const listHeader = document.createElement('h3'); listHeader.textContent = 'Your Enemy Skin Mappings'; listHeader.style.cssText = ` color: ${TAB_ACTIVE_COLOR}; font-size: 24px; margin-bottom: 20px; border-bottom: 2px solid ${TAB_ACTIVE_COLOR}; padding-bottom: 10px; `; enemyListContainer.appendChild(listHeader); // Create grid for skin mappings const skinsGrid = document.createElement('div'); skinsGrid.style.cssText = ` display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 15px; `; // Fill with enemy skins if (Object.keys(enemySkins).length === 0) { const emptyMessage = document.createElement('div'); emptyMessage.textContent = 'No enemy skins have been added yet.'; emptyMessage.style.cssText = ` grid-column: 1 / -1; text-align: center; color: #666; font-size: 18px; padding: 30px; `; skinsGrid.appendChild(emptyMessage); } else { // Create a card for each enemy skin for (const name in enemySkins) { const url = enemySkins[name]; const card = document.createElement('div'); card.style.cssText = ` background-color: white; border-radius: 8px; padding: 15px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); display: flex; flex-direction: column; align-items: center; position: relative; `; // Skin preview const preview = document.createElement('div'); preview.style.cssText = ` width: 100px; height: 100px; border-radius: 50%; overflow: hidden; background-color: #f2f2f2; margin-bottom: 10px; border: 2px solid ${TAB_INACTIVE_COLOR}; `; const img = document.createElement('img'); img.src = url; img.style.cssText = 'width: 100%; height: 100%; object-fit: cover;'; img.onerror = () => { img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; }; preview.appendChild(img); // Name label const nameLabel = document.createElement('div'); nameLabel.textContent = name; nameLabel.style.cssText = ` font-weight: bold; text-align: center; margin-bottom: 5px; word-break: break-word; `; // URL shortened display const urlLabel = document.createElement('div'); const shortenedUrl = url.length > 25 ? url.substring(0, 22) + '...' : url; urlLabel.textContent = shortenedUrl; urlLabel.title = url; // Full URL on hover urlLabel.style.cssText = ` font-size: 12px; color: #666; text-align: center; margin-bottom: 10px; word-break: break-word; `; // Action buttons const buttonsContainer = document.createElement('div'); buttonsContainer.style.cssText = 'display: flex; gap: 5px; width: 100%;'; const copyBtn = document.createElement('button'); copyBtn.textContent = 'Copy URL'; copyBtn.style.cssText = ` flex: 1; background-color: ${TAB_INACTIVE_COLOR}; color: white; border: none; border-radius: 4px; padding: 5px; cursor: pointer; font-size: 12px; `; copyBtn.addEventListener('click', () => { navigator.clipboard.writeText(url) .then(() => { showToast(`Copied URL for "${name}"`); }) .catch(err => { showToast(`Failed to copy: ${err}`); }); }); const removeBtn = document.createElement('button'); removeBtn.textContent = 'Remove'; removeBtn.style.cssText = ` flex: 1; background-color: #f33; color: white; border: none; border-radius: 4px; padding: 5px; cursor: pointer; font-size: 12px; `; removeBtn.addEventListener('click', () => { delete enemySkins[name]; saveEnemySkins(); showToast(`Removed skin for "${name}"`); showEnemySkinsList(); // Refresh the list }); buttonsContainer.appendChild(copyBtn); buttonsContainer.appendChild(removeBtn); // Add elements to card card.appendChild(preview); card.appendChild(nameLabel); card.appendChild(urlLabel); card.appendChild(buttonsContainer); // Add card to grid skinsGrid.appendChild(card); } } enemyListContainer.appendChild(skinsGrid); iframeContainer.appendChild(enemyListContainer); } } //------------------------------------ // Sub-UI: "Your Skin" content //------------------------------------ function buildYourSkinUI(container) { const previewContainer = document.createElement('div'); previewContainer.style.cssText = ` width: auto; height: auto; border-radius: 50%; margin: 0 auto 20px; background: #ccc; overflow: hidden; display: flex; justify-content: center; align-items: center; border: 3px solid ${TAB_ACTIVE_COLOR}; `; container.appendChild(previewContainer); const previewImg = document.createElement('img'); previewImg.id = 'skin-preview-image'; previewImg.style.cssText = 'width: 100%; height: 100%;'; previewImg.onerror = () => { previewImg.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; }; previewContainer.appendChild(previewImg); const inputArea = document.createElement('div'); inputArea.style.cssText = 'margin-bottom: 20px;'; container.appendChild(inputArea); const urlLabel = document.createElement('label'); urlLabel.textContent = 'Skin URL:'; urlLabel.style.cssText = ` display: block; margin-bottom: 5px; font-weight: bold; color: ${TEXT_COLOR}; font-size: 18px; `; inputArea.appendChild(urlLabel); const urlInput = document.createElement('input'); urlInput.type = 'text'; urlInput.placeholder = 'https://example.com/yourskin.png'; urlInput.style.cssText = ` width: 100%; padding: 8px; margin-bottom: 10px; border-radius: 4px; border: 1px solid #999; background: #fff; color: ${TEXT_COLOR}; font-family: Arial, sans-serif; `; urlInput.addEventListener('focus', () => { isInputFocused = true; }); urlInput.addEventListener('blur', () => { setTimeout(() => { isInputFocused = false; }, 100); }); urlInput.addEventListener('input', () => { previewImg.src = urlInput.value.trim(); }); inputArea.appendChild(urlInput); const buttonsContainer = document.createElement('div'); buttonsContainer.style.cssText = 'display: flex; gap: 10px;'; inputArea.appendChild(buttonsContainer); const applyBtn = document.createElement('button'); applyBtn.textContent = 'Apply Skin'; applyBtn.style.cssText = ` flex: 1; background-color: ${TAB_INACTIVE_COLOR}; color: #fff; border: none; border-radius: 4px; padding: 8px 15px; cursor: pointer; font-weight: bold; `; applyBtn.addEventListener('mouseover', () => { applyBtn.style.backgroundColor = TAB_ACTIVE_COLOR; }); applyBtn.addEventListener('mouseout', () => { applyBtn.style.backgroundColor = TAB_INACTIVE_COLOR; }); applyBtn.addEventListener('click', () => { const url = urlInput.value.trim(); if (url) { applyCustomSkin(url); saveSkinToGallery(url); updateSkinGallery(); } else { showNotification('Please enter a valid URL'); } }); buttonsContainer.appendChild(applyBtn); const clearBtn = document.createElement('button'); clearBtn.textContent = 'Clear'; clearBtn.style.cssText = ` background-color: #999; color: #fff; border: none; border-radius: 4px; padding: 8px 15px; cursor: pointer; `; clearBtn.addEventListener('click', () => { urlInput.value = ''; previewImg.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; }); buttonsContainer.appendChild(clearBtn); const gallerySection = document.createElement('div'); gallerySection.style.cssText = 'margin-top: 20px; display: block;'; container.appendChild(gallerySection); const galleryTitle = document.createElement('h4'); galleryTitle.textContent = 'Saved Skins'; galleryTitle.style.cssText = ` margin-top: 0; margin-bottom: 10px; color: ${TEXT_COLOR}; font-size: 18px; font-weight: bold; `; gallerySection.appendChild(galleryTitle); const galleryGrid = document.createElement('div'); galleryGrid.id = 'skin-gallery-grid'; galleryGrid.style.cssText = ` display: grid; grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); gap: 10px; margin-top: 10px; `; gallerySection.appendChild(galleryGrid); updateSkinGallery(); } function updateSkinGallery() { const galleryGrid = document.getElementById('skin-gallery-grid'); if (!galleryGrid) return; galleryGrid.innerHTML = ''; const skins = loadSkinsFromStorage(); if (skins.length === 0) { const emptyMsg = document.createElement('p'); emptyMsg.textContent = 'No skins saved yet.'; emptyMsg.style.cssText = 'grid-column: 1 / -1; text-align: center; color: #555;'; galleryGrid.appendChild(emptyMsg); } else { // Only one forEach loop inside the else block skins.forEach((url, index) => { const item = document.createElement('div'); item.style.cssText = ` width: 100%; aspect-ratio: 1; border-radius: 8px; overflow: hidden; position: relative; border: 2px solid #999; background: #ddd; cursor: pointer; `; const img = document.createElement('img'); img.src = url; img.style.cssText = 'width: 100%; height: 100%; object-fit: cover;'; img.onerror = () => { img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; }; item.appendChild(img); const overlay = document.createElement('div'); overlay.style.cssText = ` position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); display: flex; justify-content: center; align-items: center; opacity: 0; transition: opacity 0.2s; `; item.appendChild(overlay); const btnContainer = document.createElement('div'); btnContainer.style.cssText = 'display: flex; gap: 5px;'; overlay.appendChild(btnContainer); const useBtn = document.createElement('button'); useBtn.textContent = '✓'; useBtn.title = 'Use Skin'; useBtn.style.cssText = ` width: 24px; height: 24px; background-color: #66a3ff; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 12px; `; useBtn.addEventListener('click', (e) => { e.stopPropagation(); applyCustomSkin(url); const preview = document.getElementById('skin-preview-image'); if (preview) preview.src = url; const urlInput = document.querySelector('#your-skin-content input[type="text"]'); if (urlInput) urlInput.value = url; }); btnContainer.appendChild(useBtn); const delBtn = document.createElement('button'); delBtn.textContent = '×'; delBtn.title = 'Delete Skin'; delBtn.style.cssText = ` width: 24px; height: 24px; background-color: #f33; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 12px; `; delBtn.addEventListener('click', (e) => { e.stopPropagation(); removeSkinFromGallery(index); updateSkinGallery(); }); btnContainer.appendChild(delBtn); item.addEventListener('mouseover', () => { overlay.style.opacity = '1'; }); item.addEventListener('mouseout', () => { overlay.style.opacity = '0'; }); item.addEventListener('click', () => { const preview = document.getElementById('skin-preview-image'); if (preview) preview.src = url; const urlInput = document.querySelector('#your-skin-content input[type="text"]'); if (urlInput) urlInput.value = url; }); galleryGrid.appendChild(item); }); } } function saveSkinToGallery(url) { const skins = loadSkinsFromStorage(); if (skins.includes(url)) return; skins.unshift(url); if (skins.length > CONFIG.maxSavedSkins) skins.pop(); saveSkinsToStorage(skins); } function removeSkinFromGallery(index) { const skins = loadSkinsFromStorage(); skins.splice(index, 1); saveSkinsToStorage(skins); } //------------------------------------ // Sub-UI: "Enemy Skins" content //------------------------------------ function buildEnemySkinUI(container) { const form = document.createElement('div'); form.style.cssText = ` margin-bottom: 20px; background: #e6e6e6; padding: 15px; border-radius: 5px; `; const nameLabel = document.createElement('label'); nameLabel.textContent = 'Enemy Name:'; nameLabel.style.cssText = ` display: block; margin-bottom: 5px; font-weight: bold; color: ${TEXT_COLOR}; font-size: 18px; `; form.appendChild(nameLabel); const nameInput = document.createElement('input'); nameInput.id = 'enemy-name-input'; nameInput.type = 'text'; nameInput.placeholder = 'Enter exact enemy name'; nameInput.style.cssText = ` width: 100%; padding: 8px; margin-bottom: 10px; border-radius: 4px; border: 1px solid #999; background: #fff; color: ${TEXT_COLOR}; font-family: Arial, sans-serif; `; nameInput.addEventListener('focus', () => { isInputFocused = true; }); nameInput.addEventListener('blur', () => { setTimeout(() => { isInputFocused = false; }, 100); }); form.appendChild(nameInput); const urlLabel = document.createElement('label'); urlLabel.textContent = 'Skin URL:'; urlLabel.style.cssText = ` display: block; margin-bottom: 5px; font-weight: bold; color: ${TEXT_COLOR}; font-size: 18px; `; form.appendChild(urlLabel); const urlInput = document.createElement('input'); urlInput.id = 'enemy-skin-url-input'; urlInput.type = 'text'; urlInput.placeholder = 'https://example.com/enemyskin.png'; urlInput.style.cssText = ` width: 100%; padding: 8px; margin-bottom: 15px; border-radius: 4px; border: 1px solid #999; background: #fff; color: ${TEXT_COLOR}; font-family: Arial, sans-serif; `; urlInput.addEventListener('focus', () => { isInputFocused = true; }); urlInput.addEventListener('blur', () => { setTimeout(() => { isInputFocused = false; }, 100); }); const previewImg = document.createElement('img'); previewImg.id = 'enemy-skin-preview'; previewImg.style.cssText = ` width: 60px; height: 60px; border-radius: 50%; margin: 0 auto 15px; background: #ccc; display: block; object-fit: cover; border: 2px solid #999; `; previewImg.onerror = () => { previewImg.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; }; form.appendChild(urlInput); form.appendChild(previewImg); urlInput.addEventListener('input', () => { previewImg.src = urlInput.value.trim(); }); const buttonRow = document.createElement('div'); buttonRow.style.cssText = 'display: flex; gap: 10px;'; form.appendChild(buttonRow); const addBtn = document.createElement('button'); addBtn.textContent = 'Add Skin Mapping'; addBtn.style.cssText = ` flex: 1; background-color: ${TAB_INACTIVE_COLOR}; color: #fff; border: none; padding: 8px 15px; border-radius: 4px; cursor: pointer; font-weight: bold; `; addBtn.addEventListener('mouseover', () => { addBtn.style.backgroundColor = TAB_ACTIVE_COLOR; }); addBtn.addEventListener('mouseout', () => { addBtn.style.backgroundColor = TAB_INACTIVE_COLOR; }); addBtn.addEventListener('click', () => { const name = nameInput.value.trim(); const url = urlInput.value.trim(); if (!name || !url) { showNotification('Please enter both a name and URL'); return; } enemySkins[name] = url; saveEnemySkins(); registerEnemySkin(name, url); updateEnemySkinList(); nameInput.value = ''; urlInput.value = ''; previewImg.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; showNotification(`Added skin for "${name}"`); }); buttonRow.appendChild(addBtn); const clearBtn = document.createElement('button'); clearBtn.textContent = 'Clear'; clearBtn.style.cssText = ` background-color: #999; color: #fff; border: none; border-radius: 4px; padding: 8px 15px; cursor: pointer; `; clearBtn.addEventListener('click', () => { nameInput.value = ''; urlInput.value = ''; previewImg.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; }); buttonRow.appendChild(clearBtn); container.appendChild(form); const listContainer = document.createElement('div'); listContainer.style.cssText = 'flex: 1; overflow-y: auto;'; container.appendChild(listContainer); const listTitle = document.createElement('h4'); listTitle.textContent = 'Enemy Skin Mappings'; listTitle.style.cssText = ` margin-top: 0; margin-bottom: 10px; color: ${TEXT_COLOR}; font-size: 18px; font-weight: bold; `; listContainer.appendChild(listTitle); const enemySkinList = document.createElement('div'); enemySkinList.id = 'enemy-skin-list'; // Make the container bigger for saved skins: enemySkinList.style.cssText = 'max-height: 400px; overflow-y: auto;'; listContainer.appendChild(enemySkinList); const applyAllBtn = document.createElement('button'); applyAllBtn.textContent = 'Apply All Enemy Skins'; applyAllBtn.style.cssText = ` background-color: #66c2ff; color: #fff; border: none; padding: 10px; border-radius: 4px; cursor: pointer; width: 100%; margin-top: 15px; font-weight: bold; font-size: 16px; `; applyAllBtn.addEventListener('click', applyAllEnemySkins); applyAllBtn.addEventListener('mouseover', () => { applyAllBtn.style.backgroundColor = TAB_ACTIVE_COLOR; }); applyAllBtn.addEventListener('mouseout', () => { applyAllBtn.style.backgroundColor = '#66c2ff'; }); container.appendChild(applyAllBtn); loadEnemySkins(); updateEnemySkinList(); } function updateEnemySkinList() { const listContainer = document.getElementById('enemy-skin-list'); if (!listContainer) return; listContainer.innerHTML = ''; if (Object.keys(enemySkins).length === 0) { const emptyMsg = document.createElement('p'); emptyMsg.textContent = 'No skin mappings added yet'; emptyMsg.style.textAlign = 'center'; emptyMsg.style.color = '#666'; listContainer.appendChild(emptyMsg); return; } for (const name in enemySkins) { const url = enemySkins[name]; const item = document.createElement('div'); item.style.cssText = ` display: flex; justify-content: space-between; align-items: center; padding: 8px; border-bottom: 1px solid rgba(0,0,0,0.1); margin-bottom: 5px; background: #fff; border-radius: 4px; `; const nameDisplay = document.createElement('div'); nameDisplay.textContent = name; nameDisplay.style.cssText = ` flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: ${TEXT_COLOR}; font-size: 16px; `; item.appendChild(nameDisplay); const preview = document.createElement('img'); preview.src = url; preview.style.cssText = ` width: 30px; height: 30px; border-radius: 50%; margin: 0 10px; border: 1px solid #999; object-fit: cover; `; preview.onerror = () => { preview.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; }; item.appendChild(preview); const removeBtn = document.createElement('button'); removeBtn.textContent = '×'; removeBtn.style.cssText = ` background-color: #f33; color: #fff; border: none; width: 24px; height: 24px; border-radius: 50%; cursor: pointer; font-size: 16px; display: flex; align-items: center; justify-content: center; `; removeBtn.addEventListener('click', () => { delete enemySkins[name]; saveEnemySkins(); updateEnemySkinList(); showNotification(`Removed skin for "${name}"`); }); item.appendChild(removeBtn); listContainer.appendChild(item); } } //------------------------------------------------ // PLAYER DATA DISPLAYS //------------------------------------------------ function updatePlayerDataDisplays() { updateLeaderboard(); updateCellNames(); updateScore(); } function updateLeaderboard() { const container = document.getElementById('leaderboard-content'); if (!container) return; container.innerHTML = ''; const keys = Object.keys(leaderboardData); if (keys.length === 0) { container.innerHTML = `<p style="color: #666; text-align: center;">No leaderboard data collected yet</p>`; return; } const positions = keys.sort((a,b) => parseInt(a) - parseInt(b)); positions.forEach(pos => { const name = leaderboardData[pos]; const item = document.createElement('div'); item.style.cssText = ` display: flex; justify-content: space-between; align-items: center; padding: 8px; border-bottom: 1px solid rgba(0,0,0,0.1); margin-bottom: 5px; background: #fff; border-radius: 4px; `; const posDisplay = document.createElement('span'); posDisplay.textContent = pos + '.'; posDisplay.style.marginRight = '10px'; item.appendChild(posDisplay); const nameDisplay = document.createElement('span'); nameDisplay.textContent = name; nameDisplay.style.flex = '1'; item.appendChild(nameDisplay); const copyBtn = document.createElement('button'); copyBtn.textContent = 'Copy'; copyBtn.style.cssText = ` background-color: ${TAB_INACTIVE_COLOR}; border: none; color: #fff; padding: 3px 8px; border-radius: 3px; cursor: pointer; margin-right: 5px; `; copyBtn.addEventListener('mouseover', () => { copyBtn.style.backgroundColor = TAB_ACTIVE_COLOR; }); copyBtn.addEventListener('mouseout', () => { copyBtn.style.backgroundColor = TAB_INACTIVE_COLOR; }); copyBtn.addEventListener('click', () => { copyToClipboard(name); showNotification(`Copied "${name}" to clipboard`); }); item.appendChild(copyBtn); const addSkinBtn = document.createElement('button'); addSkinBtn.textContent = 'Add Skin'; addSkinBtn.style.cssText = ` background-color: #66c2ff; border: none; color: #fff; padding: 3px 8px; border-radius: 3px; cursor: pointer; `; addSkinBtn.addEventListener('mouseover', () => { addSkinBtn.style.backgroundColor = TAB_ACTIVE_COLOR; }); addSkinBtn.addEventListener('mouseout', () => { addSkinBtn.style.backgroundColor = '#66c2ff'; }); addSkinBtn.addEventListener('click', () => { addNameToSkinManager(name); }); item.appendChild(addSkinBtn); container.appendChild(item); }); } function updateCellNames() { const container = document.getElementById('cell-names-content'); if (!container) return; container.innerHTML = ''; if (cellNames.size === 0) { container.innerHTML = `<p style="color: #666; text-align: center;">No cell names collected yet</p>`; return; } const namesArray = Array.from(cellNames).sort(); namesArray.forEach(name => { const item = document.createElement('div'); item.style.cssText = ` display: flex; justify-content: space-between; align-items: center; padding: 8px; border-bottom: 1px solid rgba(0,0,0,0.1); margin-bottom: 5px; background: #fff; border-radius: 4px; `; const nameDisplay = document.createElement('span'); nameDisplay.textContent = name; nameDisplay.style.flex = '1'; item.appendChild(nameDisplay); const copyBtn = document.createElement('button'); copyBtn.textContent = 'Copy'; copyBtn.style.cssText = ` background-color: ${TAB_INACTIVE_COLOR}; border: none; color: #fff; padding: 3px 8px; border-radius: 3px; cursor: pointer; margin-right: 5px; `; copyBtn.addEventListener('mouseover', () => { copyBtn.style.backgroundColor = TAB_ACTIVE_COLOR; }); copyBtn.addEventListener('mouseout', () => { copyBtn.style.backgroundColor = TAB_INACTIVE_COLOR; }); copyBtn.addEventListener('click', () => { copyToClipboard(name); showNotification(`Copied "${name}" to clipboard`); }); item.appendChild(copyBtn); const addSkinBtn = document.createElement('button'); addSkinBtn.textContent = 'Add Skin'; addSkinBtn.style.cssText = ` background-color: #66c2ff; border: none; color: #fff; padding: 3px 8px; border-radius: 3px; cursor: pointer; `; addSkinBtn.addEventListener('mouseover', () => { addSkinBtn.style.backgroundColor = TAB_ACTIVE_COLOR; }); addSkinBtn.addEventListener('mouseout', () => { addSkinBtn.style.backgroundColor = '#66c2ff'; }); addSkinBtn.addEventListener('click', () => { addNameToSkinManager(name); }); item.appendChild(addSkinBtn); container.appendChild(item); }); } function updateScore() { const container = document.getElementById('score-content'); if (!container) return; container.innerHTML = ` <div style="text-align: center; padding: 20px;"> <h3 style="color: ${TEXT_COLOR}; font-size: 24px;">Your Current Score</h3> <div style="font-size: 36px; margin: 20px 0; font-weight: bold; color: ${TEXT_COLOR};">${playerScore.toLocaleString()}</div> <button id="copy-score-btn" style="background-color: ${TAB_INACTIVE_COLOR}; border: none; color: #fff; padding: 8px 15px; border-radius: 4px; cursor: pointer; font-size: 16px;"> Copy Score </button> </div> `; const copyBtn = document.getElementById('copy-score-btn'); copyBtn?.addEventListener('click', () => { copyToClipboard(playerScore.toString()); showNotification('Score copied to clipboard'); }); copyBtn?.addEventListener('mouseover', () => { copyBtn.style.backgroundColor = TAB_ACTIVE_COLOR; }); copyBtn?.addEventListener('mouseout', () => { copyBtn.style.backgroundColor = TAB_INACTIVE_COLOR; }); } function copyToClipboard(text) { const textarea = document.createElement('textarea'); textarea.value = text; textarea.style.position = 'fixed'; textarea.style.opacity = '0'; document.body.appendChild(textarea); textarea.select(); document.execCommand('copy'); document.body.removeChild(textarea); } function addNameToSkinManager(name) { openPlayerDataManager(); const tabs = document.querySelectorAll('#player-data-manager div'); // naive approach to find the "Enemy Skins" tab for (const tab of tabs) { if (tab.textContent === 'Enemy Skins') { tab.click(); break; } } const nameInput = document.getElementById('enemy-name-input'); if (nameInput) { nameInput.value = name; nameInput.focus(); setTimeout(() => { document.getElementById('enemy-skin-url-input')?.focus(); }, 100); showNotification(`Added "${name}" to skin manager`); } } function openSkinSwitcherUI() { openPlayerDataManager(); const tabs = document.querySelectorAll('#player-data-manager div'); for (const tab of tabs) { if (tab.textContent === 'Your Skin') { tab.click(); break; } } } //------------------------------------------------ // INIT & START //------------------------------------------------ function initialize() { setupKeyHandlers(); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initOnReady); } else { initOnReady(); } } function initOnReady() { document.documentElement.removeAttribute('style'); const adDiv = document.querySelector('#agar-io_970x90'); if (adDiv) adDiv.remove(); createShowControlsButton(); createMainOverlay(); createFpsCounter(); initRussiaToUkraine(); increaseNickLimit(); interceptWebSocket(); // Add this here interceptCoreForFreeze(); setupNameCollection(); captureOriginalSkin(); loadEnemySkins(); setTimeout(findGameCanvas, 2000); checkCoreAccess(); showNotification('Enhanced Agario Mod initialized!', true); console.log('Enhanced Agario Mod initialized successfully!'); } // Call it so it loads initialize(); })(); (function() { 'use strict'; // Config const config = { containerWidth: '400px', maxPreviewSize: 180, buttonColor: '#54c800', // Agar.io green buttonHoverColor: '#45a800', dropZoneHeight: '120px', dropZoneBorderColor: '#ccc', dropZoneActiveColor: '#54c800', agarioColors: { green: '#54c800',// Primary green blue: '#0078fa',// Blue red: '#ff3d3d',// Red yellow: '#ffcc00',// Yellow background: 'rgb(255, 255, 255)', text: '#000000' } }; // Use MutationObserver to detect when skin editor opens or closes const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.addedNodes && mutation.addedNodes.length > 0) { for (let i = 0; i < mutation.addedNodes.length; i++) { const node = mutation.addedNodes[i]; if (node.nodeType === Node.ELEMENT_NODE) { // Check for skin editor elements if (node.querySelector('#skin-editor-canvas') || node.id === 'skin-editor-canvas') { console.log('Skin editor detected!'); setTimeout(initializeImageUploader, 500); // Give it time to fully initialize return; } } } } // Check for editor closing - look for removed elements if (mutation.removedNodes && mutation.removedNodes.length > 0) { for (let i = 0; i < mutation.removedNodes.length; i++) { const node = mutation.removedNodes[i]; if (node.nodeType === Node.ELEMENT_NODE) { // Try to detect if skin editor was removed if (node.querySelector && ( node.querySelector('#skin-editor-canvas') || node.id === 'skin-editor-canvas' || node.classList && ( node.classList.contains('skin-editor') || node.classList.contains('skin-editor-dialog') ) )) { console.log('Skin editor closed!'); removeImageUploader(); return; } // Also check for any other indicators the editor might be closing const editorCloseIndicators = [ '.sk-app', '.editor-app', '.skin-editor', '[data-v-skin-editor]', '#skin-editor' ]; for (const selector of editorCloseIndicators) { if (node.matches && node.matches(selector)) { console.log('Possible skin editor close detected!'); setTimeout(checkIfEditorClosed, 100); return; } } } } } }); }); // Wait for document body to be available before observing function startObserver() { if (document.body) { observer.observe(document.body, { childList: true, subtree: true }); console.log('Observer started successfully'); } else { console.log('Body not ready, waiting...'); setTimeout(startObserver, 100); // Try again in 100ms } } // Make sure the script runs after the DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', startObserver); } else { startObserver(); } // Main initialization function function initializeImageUploader() { // Avoid duplicate initialization if (document.getElementById('custom-image-uploader-container')) { return; } console.log('Initializing image uploader...'); // Create upload container and UI - no need to find a parent container const uploadContainer = createUploadContainer(); // Add directly to body for positioning freedom document.body.appendChild(uploadContainer); // Position next to the skin editor positionUploaderNextToEditor(uploadContainer); console.log('Image uploader initialized successfully!'); } // Find the controls container in the skin editor function findControlsContainer() { // Try various selectors that might contain the editor controls const canvas = document.getElementById('skin-editor-canvas'); if (!canvas) return null; // Look for various containers based on Agar.io's structure // First, try to find specific container classes const toolsSelector = '.tools, .colors, .controls, .editor-controls, .skin-editor-tools'; const toolsContainer = document.querySelector(toolsSelector); if (toolsContainer) return toolsContainer; // Next, try common parent patterns const skinEditorContainer = document.querySelector('.skin-editor, #skin-editor, [data-v-skin-editor]'); if (skinEditorContainer) { const controls = skinEditorContainer.querySelector('.controls, .tools'); if (controls) return controls; // If no controls found inside, return the container itself return skinEditorContainer; } // Look for parent container that might be appropriate let parent = canvas.parentElement; // Search up to 5 levels up for (let i = 0; i < 5 && parent; i++) { if (parent.classList.contains('sk-app') || parent.classList.contains('editor') || parent.id === 'skin-editor' || parent.classList.contains('skin-editor')) { return parent; } // Check if this parent has control-like elements const controlElements = parent.querySelectorAll('button, .color, input, select'); if (controlElements.length > 3) { return parent; } parent = parent.parentElement; } // Fallback: create a container next to the canvas const canvasParent = canvas.parentElement; const fallbackContainer = document.createElement('div'); fallbackContainer.id = 'skin-editor-controls-fallback'; fallbackContainer.style.marginTop = '10px'; canvasParent.appendChild(fallbackContainer); console.log('Created fallback container for skin editor controls'); return fallbackContainer; } // Create the upload container with all elements function createUploadContainer() { // Create a separate floating div for the uploader const container = document.createElement('div'); container.id = 'custom-image-uploader-container'; container.style.position = 'absolute'; container.style.right = '50px'; container.style.top = '70px';// Positioned at the top-right container.style.width = config.containerWidth; container.style.padding = '15px'; container.style.backgroundColor = config.agarioColors.background; container.style.color = config.agarioColors.text; container.style.borderRadius = '8px'; container.style.boxSizing = 'border-box'; container.style.zIndex = '9999'; container.style.boxShadow = '0 0 15px rgba(0, 0, 0, 0.5)'; container.style.fontFamily = 'Ubuntu, Arial, sans-serif'; container.style.border = '2px solid ' + config.agarioColors.green; // Add header const header = document.createElement('div'); header.style.display = 'flex'; header.style.justifyContent = 'space-between'; header.style.alignItems = 'center'; header.style.marginBottom = '15px'; header.style.borderBottom = '1px solid ' + config.agarioColors.green; header.style.paddingBottom = '8px'; const title = document.createElement('h3'); title.textContent = 'New Jacks 🕹️ Skin Editor'; title.style.margin = '0'; title.style.color = config.agarioColors.blue; title.style.fontSize = '24px'; title.style.fontWeight = 'bold'; // Add minimize/expand button const toggleBtn = document.createElement('button'); toggleBtn.textContent = '−';// Unicode minus sign toggleBtn.style.backgroundColor = config.agarioColors.green; toggleBtn.style.border = 'none'; toggleBtn.style.color = '#ccc'; toggleBtn.style.fontSize = '18px'; toggleBtn.style.cursor = 'pointer'; toggleBtn.style.width = '24px'; toggleBtn.style.height = '24px'; toggleBtn.style.display = 'flex'; toggleBtn.style.justifyContent = 'center'; toggleBtn.style.alignItems = 'center'; toggleBtn.style.borderRadius = '4px'; // Content container (for collapse/expand) const contentContainer = document.createElement('div'); contentContainer.id = 'image-uploader-content'; // Toggle expand/collapse toggleBtn.addEventListener('click', () => { if (contentContainer.style.display === 'none') { contentContainer.style.display = 'block'; toggleBtn.textContent = '−'; // Unicode minus sign } else { contentContainer.style.display = 'none'; toggleBtn.textContent = '+';// Plus sign } }); header.appendChild(title); header.appendChild(toggleBtn); container.appendChild(header); container.appendChild(contentContainer); // Add URL input const urlContainer = document.createElement('div'); urlContainer.style.marginBottom = '12px'; urlContainer.style.display = 'flex'; const urlInput = document.createElement('input'); urlInput.type = 'text'; urlInput.placeholder = 'Enter image URL... ibb.co best'; urlInput.style.flex = '1'; urlInput.style.padding = '10px'; urlInput.style.border = '1px solid #444'; urlInput.style.backgroundColor = 'rgba (135, 135, 135, 0.3)'; urlInput.style.color = '#000'; urlInput.style.borderRadius = '4px'; urlInput.style.marginRight = '5px'; urlInput.style.fontSize = '18px'; const urlButton = document.createElement('button'); urlButton.textContent = 'Load'; urlButton.style.padding = '10px'; urlButton.style.backgroundColor = config.agarioColors.green; urlButton.style.color = 'black'; urlButton.style.border = 'none'; urlButton.style.borderRadius = '4px'; urlButton.style.cursor = 'pointer'; urlButton.style.fontWeight = 'bold'; urlContainer.appendChild(urlInput); urlContainer.appendChild(urlButton); contentContainer.appendChild(urlContainer); // Upload buttons row const uploadButtons = document.createElement('div'); uploadButtons.style.display = 'flex'; uploadButtons.style.gap = '5px'; uploadButtons.style.marginBottom = '12px'; // File upload button const fileInput = document.createElement('input'); fileInput.type = 'file'; fileInput.id = 'custom-skin-file'; fileInput.accept = 'image/*'; fileInput.style.display = 'none'; // Hidden, triggered by button const fileButton = document.createElement('button'); fileButton.textContent = 'Upload From Computer'; fileButton.style.flex = '1'; fileButton.style.padding = '10px'; fileButton.style.backgroundColor = config.agarioColors.blue; fileButton.style.color = 'white'; fileButton.style.border = 'none'; fileButton.style.borderRadius = '4px'; fileButton.style.cursor = 'pointer'; fileButton.style.fontWeight = 'bold'; uploadButtons.appendChild(fileInput); uploadButtons.appendChild(fileButton); contentContainer.appendChild(uploadButtons); // Drop zone const dropZone = document.createElement('div'); dropZone.id = 'custom-skin-drop-zone'; dropZone.textContent = 'Drop Image Here'; dropZone.style.height = config.dropZoneHeight; dropZone.style.border = `2px dashed ${config.agarioColors.yellow}`; dropZone.style.borderRadius = '4px'; dropZone.style.display = 'flex'; dropZone.style.flexDirection = 'column'; dropZone.style.alignItems = 'center'; dropZone.style.justifyContent = 'center'; dropZone.style.color = '#ccc'; dropZone.style.marginBottom = '12px'; dropZone.style.fontSize = '16px'; dropZone.style.backgroundColor = 'rgba(255, 255, 255, 0.5)'; // Add icon to drop zone const dropIcon = document.createElement('div'); dropIcon.innerHTML = '⬇️'; dropIcon.style.fontSize = '24px'; dropIcon.style.marginBottom = '8px'; dropZone.appendChild(dropIcon); dropZone.appendChild(document.createTextNode('Drag & Drop Image Here')); contentContainer.appendChild(dropZone); // Image preview const previewContainer = document.createElement('div'); previewContainer.style.textAlign = 'center'; previewContainer.style.marginTop = '12px'; previewContainer.style.display = 'none'; previewContainer.style.backgroundColor = 'rgba(255, 255, 255, 0.1)'; previewContainer.style.padding = '10px'; previewContainer.style.borderRadius = '4px'; const previewLabel = document.createElement('div'); previewLabel.textContent = 'Preview:'; previewLabel.style.marginBottom = '8px'; previewLabel.style.color = config.agarioColors.yellow; previewLabel.style.fontSize = '14px'; previewLabel.style.fontWeight = 'bold'; const previewImg = document.createElement('img'); previewImg.id = 'custom-skin-preview'; previewImg.style.maxWidth = '100%'; previewImg.style.maxHeight = `${config.maxPreviewSize}px`; previewImg.style.border = '1px solid #444'; previewImg.style.borderRadius = '50%'; // Make preview circular like Agar.io skins previewContainer.appendChild(previewLabel); previewContainer.appendChild(previewImg); contentContainer.appendChild(previewContainer); // Help text with tips const helpText = document.createElement('div'); helpText.style.fontSize = '20px'; helpText.style.color = '#000'; helpText.style.textShadow = '1px 1px 1px #444'; helpText.style.marginTop = '16px'; helpText.style.lineHeight = '1.4'; helpText.style.padding = '8px'; helpText.style.backgroundColor = 'rgba(0, 0, 0, 0.3)'; helpText.style.borderRadius = '4px'; helpText.style.borderLeft = '3px solid ' + config.agarioColors.yellow; helpText.innerHTML = ` <b style="color:${config.agarioColors.blue}">Tips:</b><br> • If image doesn't appear clearly, try <a href="https://picwish.com/unblur-image-portrait" target="_blank" style="color:${config.agarioColors.blue};">unblurring it PicWish.com</a><br> • Use <a href="https://crop-circle.imageonline.co/" target="_blank" style="color:${config.agarioColors.blue};">Crop Circle Tool</a> for best results<br> • Simple designs with few colors work best<br> • The image will be centered and scaled `; contentContainer.appendChild(helpText); // Set up event listeners // URL input urlInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { loadImageFromUrl(urlInput.value); } }); urlButton.addEventListener('click', () => { loadImageFromUrl(urlInput.value); }); // File upload fileButton.addEventListener('click', () => { fileInput.click(); }); fileInput.addEventListener('change', () => { if (fileInput.files && fileInput.files[0]) { handleFileUpload(fileInput.files[0]); } }); // Drag and drop dropZone.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.style.borderColor = config.agarioColors.green; dropZone.style.backgroundColor = 'rgba(84, 200, 0, 0.1)'; }); dropZone.addEventListener('dragleave', () => { dropZone.style.borderColor = config.agarioColors.yellow; dropZone.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'; }); dropZone.addEventListener('drop', (e) => { e.preventDefault(); dropZone.style.borderColor = config.agarioColors.yellow; dropZone.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'; if (e.dataTransfer.files && e.dataTransfer.files[0]) { handleFileUpload(e.dataTransfer.files[0]); } }); // Hover effects for buttons [fileButton, urlButton].forEach(button => { button.addEventListener('mouseover', () => { const originalColor = button.style.backgroundColor; const darkerColor = originalColor === config.agarioColors.green ? config.buttonHoverColor : (originalColor === config.agarioColors.blue ? '#0060cc' : originalColor); button.style.backgroundColor = darkerColor; }); button.addEventListener('mouseout', () => { button.style.backgroundColor = button === fileButton ? config.agarioColors.blue : config.agarioColors.green; }); }); // Make container draggable makeDraggable(container, header); return container; } // Make an element draggable function makeDraggable(element, handle) { let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; handle.style.cursor = 'move'; handle.onmousedown = dragMouseDown; function dragMouseDown(e) { e.preventDefault(); // Get mouse position at startup pos3 = e.clientX; pos4 = e.clientY; document.onmouseup = closeDragElement; // Call function on mouse move document.onmousemove = elementDrag; } function elementDrag(e) { e.preventDefault(); // Calculate new position pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; // Set element's new position element.style.top = (element.offsetTop - pos2) + "px"; element.style.left = (element.offsetLeft - pos1) + "px"; // If we're moving it, remove the right positioning element.style.right = 'auto'; } function closeDragElement() { // Stop moving when mouse button is released document.onmouseup = null; document.onmousemove = null; } } // Remove the image uploader function removeImageUploader() { const uploader = document.getElementById('custom-image-uploader-container'); if (uploader) { uploader.remove(); console.log('Image uploader removed'); } } // Check if editor is closed by looking for the canvas function checkIfEditorClosed() { const canvas = document.getElementById('skin-editor-canvas'); if (!canvas) { removeImageUploader(); } } // Helper function to position the uploader next to the skin editor function positionUploaderNextToEditor(uploader) { const canvas = document.getElementById('skin-editor-canvas'); if (!canvas) return; // Get canvas position const canvasRect = canvas.getBoundingClientRect(); const editorWidth = canvas.clientWidth || canvas.offsetWidth; // Position to the right of the canvas uploader.style.top = `${canvasRect.top}px`; uploader.style.left = 'auto'; uploader.style.right = '20px'; } // Load image from URL function loadImageFromUrl(url) { if (!url) return; // Basic URL validation if (!url.match(/^https?:\/\/.+\..+/i)) { alert('Please enter a valid URL'); return; } const img = new Image(); img.crossOrigin = 'Anonymous'; img.onload = () => { updatePreview(img.src); drawImageToCanvas(img); }; img.onerror = () => { alert('Error loading image. The URL might be invalid or the server does not allow cross-origin requests.'); }; img.src = url; } // Handle file upload function handleFileUpload(file) { if (!file || !file.type.startsWith('image/')) { alert('Please select a valid image file'); return; } const reader = new FileReader(); reader.onload = (e) => { const img = new Image(); img.onload = () => { updatePreview(e.target.result); drawImageToCanvas(img); }; img.src = e.target.result; }; reader.readAsDataURL(file); } // Update preview image function updatePreview(src) { const preview = document.getElementById('custom-skin-preview'); const previewContainer = preview.parentElement; preview.src = src; previewContainer.style.display = 'block'; // Add success message const successMsg = document.createElement('div'); successMsg.textContent = 'Image loaded successfully!'; successMsg.style.color = config.agarioColors.green; successMsg.style.fontWeight = 'bold'; successMsg.style.marginTop = '5px'; successMsg.style.fontSize = '12px'; // Remove any existing success message const existingMsg = previewContainer.querySelector('.success-msg'); if (existingMsg) { previewContainer.removeChild(existingMsg); } successMsg.className = 'success-msg'; previewContainer.appendChild(successMsg); // Make success message fade out after 3 seconds setTimeout(() => { successMsg.style.transition = 'opacity 1s'; successMsg.style.opacity = '0'; }, 3000); } // Draw image to canvas function drawImageToCanvas(img) { const canvas = document.getElementById('skin-editor-canvas'); if (!canvas) { console.error('Skin editor canvas not found'); return; } const ctx = canvas.getContext('2d'); // Preserve original dimensions const originalWidth = canvas.width; const originalHeight = canvas.height; // Clear existing content ctx.clearRect(0, 0, originalWidth, originalHeight); // Draw the image, centered and scaled to fit const scale = Math.min( originalWidth / img.width, originalHeight / img.height ); const x = (originalWidth - img.width * scale) / 2; const y = (originalHeight - img.height * scale) / 2; const width = img.width * scale; const height = img.height * scale; ctx.drawImage(img, x, y, width, height); // Trigger canvas change event if needed const changeEvent = new Event('change', { bubbles: true }); canvas.dispatchEvent(changeEvent); // Attempt to trigger any internal state updates by simulating a draw action try { if (window.drawApp && typeof window.drawApp.render === 'function') { window.drawApp.render(true); } } catch (e) { console.log('Internal draw method not available:', e); } } })();