// Name: Generate Agar.io AutoFarm Userscript // Description: Create a Tampermonkey userscript for Agar.io autofarming (autorespawn, autosplit, autofeed) and open it for editing. // Author: vvar10 // GitHub: vvar10 import "@johnlindquist/kit" const draftsDir = kenvPath("drafts", "agario") await ensureDir(draftsDir) const fileName = "agario-autofarm.user.js" const draftPath = path.join(draftsDir, fileName) const userscript = `// ==UserScript== // @name Agar.io AutoFarm // @namespace https://agario-autofarm.example // @version 0.1.0 // @description Autorespawn, autosplit on spawn, and autofeed helper for Agar.io. Configure via Tampermonkey menu. // @author vvar10 // @match https://agar.io/* // @run-at document-idle // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // ==/UserScript== (function () { 'use strict'; // Default config const DEFAULTS = { enabled: true, autoRespawn: true, splitOnSpawn: true, splitsOnSpawn: 4, // Typically 4 for "16-split" burst splitDelayMs: 60, // Delay between split taps postSpawnDelayMs: 220, // Wait before split burst after respawn click autoFeed: true, feedIntervalMs: 140, // Interval for feed key presses showHUD: true }; // Load config const load = () => { try { const saved = JSON.parse(GM_getValue('agario_autofarm_cfg', '{}')); return Object.assign({}, DEFAULTS, saved || {}); } catch { return { ...DEFAULTS }; } }; const save = () => GM_setValue('agario_autofarm_cfg', JSON.stringify(cfg)); let cfg = load(); // Menu commands GM_registerMenuCommand(\`[\${cfg.enabled ? 'ON' : 'OFF'}] Toggle AutoFarm\`, () => { cfg.enabled = !cfg.enabled; save(); location.reload(); }); GM_registerMenuCommand(\`[\${cfg.autoRespawn ? 'ON' : 'OFF'}] Toggle Auto Respawn\`, () => { cfg.autoRespawn = !cfg.autoRespawn; save(); notify('Auto Respawn: ' + (cfg.autoRespawn ? 'ON' : 'OFF')); }); GM_registerMenuCommand(\`[\${cfg.autoFeed ? 'ON' : 'OFF'}] Toggle Auto Feed\`, () => { cfg.autoFeed = !cfg.autoFeed; save(); notify('Auto Feed: ' + (cfg.autoFeed ? 'ON' : 'OFF')); }); GM_registerMenuCommand(\`Set Feed Interval (ms) [\${cfg.feedIntervalMs}]\`, () => { const v = prompt('Feed interval in milliseconds', String(cfg.feedIntervalMs)); if (v != null) { const n = Math.max(0, Number(v) || cfg.feedIntervalMs); cfg.feedIntervalMs = n; save(); notify('Feed Interval set to ' + n + ' ms'); } }); GM_registerMenuCommand(\`[\${cfg.splitOnSpawn ? 'ON' : 'OFF'}] Toggle Split on Spawn\`, () => { cfg.splitOnSpawn = !cfg.splitOnSpawn; save(); notify('Split on Spawn: ' + (cfg.splitOnSpawn ? 'ON' : 'OFF')); }); GM_registerMenuCommand(\`Set Splits on Spawn [\${cfg.splitsOnSpawn}]\`, () => { const v = prompt('Number of splits on spawn (1-4 typical)', String(cfg.splitsOnSpawn)); if (v != null) { const n = Math.max(0, Math.min(8, Number(v) || cfg.splitsOnSpawn)); cfg.splitsOnSpawn = n; save(); notify('Splits on Spawn set to ' + n); } }); GM_registerMenuCommand(\`[\${cfg.showHUD ? 'ON' : 'OFF'}] Toggle HUD\`, () => { cfg.showHUD = !cfg.showHUD; save(); updateHUD(); }); // Simple HUD let hud = null; function updateHUD() { if (!cfg.showHUD) { if (hud && hud.parentNode) hud.parentNode.removeChild(hud); hud = null; return; } if (!hud) { hud = document.createElement('div'); hud.style.position = 'fixed'; hud.style.top = '10px'; hud.style.left = '10px'; hud.style.zIndex = '2147483647'; hud.style.padding = '6px 10px'; hud.style.background = 'rgba(0,0,0,0.6)'; hud.style.color = '#fff'; hud.style.font = '12px/1.4 -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Inter, Helvetica, Arial, sans-serif'; hud.style.borderRadius = '6px'; hud.style.pointerEvents = 'none'; document.body.appendChild(hud); } hud.textContent = \`AutoFarm \${cfg.enabled ? 'ON' : 'OFF'} • Respawn:\${cfg.autoRespawn ? 'ON' : 'OFF'} • Feed:\${cfg.autoFeed ? ('ON@' + cfg.feedIntervalMs + 'ms') : 'OFF'} • SplitOnSpawn:\${cfg.splitOnSpawn ? (cfg.splitsOnSpawn + 'x') : 'OFF'}\`; } function notify(msg) { try { console.log('[AutoFarm]', msg); if (!cfg.showHUD) return; if (!hud) updateHUD(); if (!hud) return; const prev = hud.textContent; hud.textContent = msg; setTimeout(() => { if (hud) hud.textContent = prev; }, 1200); } catch {} } // Key dispatch helpers function keyEvent(type, key, code, keyCode) { const e = new KeyboardEvent(type, { key: key, code: code, keyCode: keyCode, which: keyCode, bubbles: true, cancelable: true, }); Object.defineProperty(e, 'keyCode', { get: () => keyCode }); Object.defineProperty(e, 'which', { get: () => keyCode }); return e; } function tapKey(key, code, keyCode, delay = 20) { window.dispatchEvent(keyEvent('keydown', key, code, keyCode)); setTimeout(() => { window.dispatchEvent(keyEvent('keyup', key, code, keyCode)); }, delay); } function tapSpace() { tapKey(' ', 'Space', 32, 12); } function tapFeed() { tapKey('w', 'KeyW', 87, 12); } function tapRespawn() { // Some clients bind 'r' to respawn, but not guaranteed. Prefer clicking Play/Respawn. tapKey('r', 'KeyR', 82, 12); } // Click "Play/Respawn" buttons if found function tryClickPlay() { const texts = ['play', 'respawn', 'continue', 'play again', 'reconnect']; const isVisible = (el) => !!(el && el.offsetParent !== null); // Common selectors (best-effort) const selectors = [ 'button', '[role="button"]', '.btn', '.btn-play', '#playBtn', '#play', 'a.button', ]; for (const sel of selectors) { const nodes = document.querySelectorAll(sel); for (const el of nodes) { const label = (el.getAttribute('aria-label') || '').toLowerCase(); const text = (el.textContent || '').trim().toLowerCase(); if (!isVisible(el)) continue; if (texts.some(t => label.includes(t) || text.includes(t))) { el.click(); notify('Clicked Play/Respawn'); return true; } } } return false; } // Simple heuristics for "in-game" vs "dead/menu" function likelyDeadOrMenu() { // If play/respawn button present and visible if (tryClickPlay()) return true; // Heuristic: when dead, there's often a modal/overlay with buttons const overlays = document.querySelectorAll('.modal, .overlay, .menu, .hud, .dialog, .popup'); for (const o of overlays) { const txt = (o.textContent || '').toLowerCase(); if (/(play|respawn|continue|reconnect)/.test(txt)) { return true; } } return false; } // Split burst sequence function splitBurst(times, delay) { times = Math.max(0, Math.min(8, times | 0)); for (let i = 0; i < times; i++) { setTimeout(() => tapSpace(), i * delay); } } // State let pendingPostSpawnSplit = false; let feedingIntervalId = 0; function startFeeding() { if (!cfg.autoFeed || !cfg.enabled) return; if (feedingIntervalId) return; feedingIntervalId = setInterval(() => { if (!cfg.enabled || !cfg.autoFeed) return; tapFeed(); }, Math.max(40, cfg.feedIntervalMs)); } function stopFeeding() { if (feedingIntervalId) { clearInterval(feedingIntervalId); feedingIntervalId = 0; } } function onPossibleRespawn() { if (!cfg.enabled) return; if (cfg.splitOnSpawn && cfg.splitsOnSpawn > 0) { pendingPostSpawnSplit = true; setTimeout(() => { if (pendingPostSpawnSplit) { splitBurst(cfg.splitsOnSpawn, Math.max(25, cfg.splitDelayMs)); pendingPostSpawnSplit = false; } }, Math.max(0, cfg.postSpawnDelayMs)); } startFeeding(); } function gameLoop() { if (!cfg.enabled) { stopFeeding(); return; } // If dead/menu detected if (cfg.autoRespawn && likelyDeadOrMenu()) { // Ensure we clicked play (tryClickPlay already attempted) // Backup: try 'r' key if click wasn't available tapRespawn(); // On next tick, assume spawn incoming setTimeout(onPossibleRespawn, 160); } updateHUD(); } // Observe DOM changes to catch "Play" appearing quickly const mo = new MutationObserver(() => { if (!cfg.enabled) return; if (cfg.autoRespawn) { if (tryClickPlay()) { setTimeout(onPossibleRespawn, 160); } } }); function start() { updateHUD(); try { mo.observe(document.documentElement || document.body, { childList: true, subtree: true }); } catch {} // Start feed if already in-game startFeeding(); setInterval(gameLoop, 200); notify('AutoFarm ready'); } if (document.readyState === 'complete' || document.readyState === 'interactive') { start(); } else { window.addEventListener('DOMContentLoaded', start, { once: true }); } })(); ` await writeFile(draftPath, userscript, "utf8") const edited = await editor({ value: userscript, language: "javascript", hint: `Tampermonkey userscript saved to ${draftPath}. Press Cmd/Ctrl+Enter to finish.`, shortcuts: [ { name: "Copy to Clipboard", key: `${cmd}+c`, bar: "right", onPress: async (input: string) => { await copy(input) await toast("Userscript copied to clipboard", { autoClose: 1500 }) }, }, { name: "Reveal Draft", key: `${cmd}+shift+r`, bar: "right", onPress: async () => { await revealFile(draftPath) }, }, ], onSubmit: async (text: string) => { await writeFile(draftPath, text, "utf8") submit(text) }, }) await writeFile(draftPath, edited, "utf8") await copy(edited) await notify(`Saved userscript: ${fileName}`) await revealFile(draftPath)