Advanced mod menu for moomoo.io with combat features, visual settings, and bot controls
Size
15.0 KB
Version
1.0.1
Created
Feb 13, 2026
Updated
3 days ago
1// ==UserScript==
2// @name Laffer Mod Menu
3// @description Advanced mod menu for moomoo.io with combat features, visual settings, and bot controls
4// @version 1.0.1
5// @match https://*.moomoo.io/*
6// @icon https://moomoo.io/img/favicon.png?v=1
7// ==/UserScript==
8// Add CSS styles
9GM_addStyle(`
10#mod_menu {
11 position: absolute;
12 top: calc(50% - 250px);
13 left: calc(50% - 400px);
14 width: 820px;
15 height: 500px;
16 background: #40454E;
17 z-index: 1000000;
18}
19
20#name_text {
21 color: #ffffff;
22 font-size: 20px;
23 text-align: center;
24 padding-top: 12px;
25}
26
27#name_block {
28 position: absolute;
29 width: 200px;
30 height: 50px;
31 background: #373C45;
32}
33
34.settings_block {
35 position: absolute;
36 left: 200px;
37 width: 620px;
38 height: 500px;
39 overflow-y: scroll;
40 overflow-x: hidden;
41}
42
43#category_block {
44 position: absolute;
45 top: 50px;
46 width: 200px;
47 height: 450px;
48 background: #373C45;
49}
50
51.category {
52 width: 200px;
53 display: flex;
54 align-items: center;
55 height: 50px;
56 cursor: pointer;
57}
58
59.category:hover {
60 background: #2D3037;
61}
62
63.category.active {
64 background: #2D3037;
65}
66
67.category_element {
68 display: none;
69 width: 5px;
70 height: 50px;
71 background: #696ACB;
72}
73
74.category:hover .category_element,
75.category.active .category_element {
76 display: block;
77}
78
79.category_icon {
80 color: #858A92;
81 font-size: 24px;
82 padding-left: 15px;
83}
84
85.category:hover .category_icon,
86.category.active .category_icon {
87 color: #ffffff;
88}
89
90.category_text {
91 color: #858A92;
92 font-size: 16px;
93 padding-left: 15px;
94}
95
96.category:hover .category_text,
97.category.active .category_text {
98 color: #ffffff;
99}
100
101#exit {
102 position: absolute;
103 bottom: 0px;
104}
105
106#exit:hover #exit_icon {
107 color: #ff0000;
108}
109
110.setting_element {
111 display: flex;
112 position: relative;
113 width: 550px;
114 height: 50px;
115 align-items: center;
116 border-radius: 4px;
117 background: #373C45;
118}
119
120.invisible_element {
121 background: #40454E;
122}
123
124.setting2 {
125 position: relative;
126 padding-top: 10px;
127 left: 25px;
128}
129
130.setting_name {
131 color: #ffffff;
132 font-size: 16px;
133 padding-left: 15px;
134}
135
136.settings_title {
137 color: #858A92;
138 font-size: 16px;
139 padding-top: 25px;
140 padding-left: 25px;
141}
142
143.menu_checkbox {
144 position: absolute;
145 background: rgba(100, 100, 100, 0.5);
146 appearance: none;
147 width: 33px;
148 height: 15.5px;
149 border-radius: 50px;
150 cursor: pointer;
151 transform: scale(1.1);
152 right: 15px;
153 transition: 0.5s;
154}
155
156.menu_input {
157 color: #ffffff;
158 position: absolute;
159 height: 25px;
160 width: 75px;
161 border: 0px;
162 right: 15px;
163 text-align: center;
164 background: #30303A;
165}
166
167.menu_button {
168 color: #ffffff;
169 position: absolute;
170 font-size: 16px;
171 width: 250px;
172 height: 50px;
173 border: 0px;
174 cursor: pointer;
175 border-radius: 5px;
176 background: #373C45;
177}
178
179.menu_button:hover {
180 background: #2D3037;
181}
182
183.menu_checkbox:checked[type="checkbox"] {
184 background: #696ACB;
185}
186
187.menu_checkbox::after {
188 position: absolute;
189 content: "";
190 width: 15.5px;
191 height: 15.5px;
192 top: 0;
193 left: 0;
194 background: #ffffff;
195 border-radius: 50%;
196 transform: scale(1.1);
197 transition: 0.5s;
198}
199
200.menu_checkbox:checked[type="checkbox"]::after {
201 left: 50%;
202}
203
204.settings_block::-webkit-scrollbar {
205 width: 10px;
206}
207
208.settings_block::-webkit-scrollbar-track {
209 opacity: 0;
210}
211
212.settings_block::-webkit-scrollbar-thumb {
213 opacity: 0;
214}
215
216.settings_block::-webkit-scrollbar-thumb:active {
217 opacity: 0;
218}
219
220#chat_log {
221 position: absolute;
222 top: 20px;
223 left: 20px;
224 width: 400px;
225 height: 300px;
226 border-radius: 4px;
227 background: #373C45;
228 z-index: 999999;
229}
230
231#chat_name {
232 position: absolute;
233 color: #ffffff;
234 padding-left: 10px;
235 padding-top: 10px;
236 font-size: 24px;
237}
238
239#chat_box {
240 position: absolute;
241 top: 50px;
242 left: 10px;
243 width: 380px;
244 height: 240px;
245 border-radius: 4px;
246 background: #30303A;
247 overflow-y: scroll;
248 overflow-x: hidden;
249}
250
251#chat_box::-webkit-scrollbar {
252 width: 10px;
253}
254
255#chat_box::-webkit-scrollbar-track {
256 opacity: 0;
257}
258
259#chat_box::-webkit-scrollbar-thumb {
260 background: #ffffff;
261 border-radius: 4px;
262}
263
264#chat_box::-webkit-scrollbar-thumb:active {
265 background: #ffffff;
266}
267
268.chat_message {
269 color: #ffffff;
270 font-size: 14px;
271 padding: 5px;
272}
273`);
274
275// Initialize settings
276const settings = {
277 spampreplace: false,
278 x18ksync: false,
279 autoPlace: false,
280 chatlog: false,
281 gamezoom: '1.0',
282 botname: 'Bot',
283 botcount: '1',
284 botplatformplacer: false
285};
286
287// Load saved settings
288function loadSettings() {
289 const saved = localStorage.getItem('moomoo_mod_settings');
290 if (saved) {
291 try {
292 Object.assign(settings, JSON.parse(saved));
293 } catch (e) {
294 console.error('Failed to load settings:', e);
295 }
296 }
297}
298
299// Save settings
300function saveSettings() {
301 localStorage.setItem('moomoo_mod_settings', JSON.stringify(settings));
302}
303
304// Load settings on startup
305loadSettings();
306
307// Create menu HTML helper functions
308function addSetting(id) {
309 return `<input type="checkbox" class="menu_checkbox" id="${id}" ${settings[id] ? 'checked' : ''}>`;
310}
311
312function addTextInput(id, maxlength) {
313 return `<input type="text" class="menu_input" placeholder="NONE" id="${id}" value="${settings[id]}" maxlength="${maxlength}">`;
314}
315
316// Create main menu
317const menu = document.createElement('div');
318menu.id = 'mod_menu';
319menu.style.display = 'none';
320menu.innerHTML = `
321<div id="name_block">
322 <div id="name_text">Laffer Mod Menu</div>
323</div>
324<div id="category_block">
325 <div id="combat" class="category active">
326 <div class="category_element"></div>
327 <i class="material-icons category_icon">local_fire_department</i>
328 <div class="category_text">Combat</div>
329 </div>
330 <div id="visual" class="category">
331 <div class="category_element"></div>
332 <i class="material-icons category_icon">visibility</i>
333 <div class="category_text">Visual</div>
334 </div>
335 <div id="bots" class="category">
336 <div class="category_element"></div>
337 <i class="material-icons category_icon">build</i>
338 <div class="category_text">Bots</div>
339 </div>
340 <div id="exit" class="category">
341 <div class="category_element"></div>
342 <i id="exit_icon" class="material-icons category_icon">close</i>
343 <div class="category_text">Exit</div>
344 </div>
345</div>
346<div id="combat_settings" class="settings_block">
347 <div class="settings_title">Gather</div>
348 <div class="setting2">
349 <div class="setting_element invisible_element">
350 <button class="menu_button" id="fix_gather">Fix Gather</button>
351 </div>
352 </div>
353 <div class="settings_title">Pre Place</div>
354 <div class="setting2">
355 <div class="setting_element">
356 <div class="setting_name">Spam</div>${addSetting('spampreplace')}
357 </div>
358 </div>
359 <div class="settings_title">Auto Sync</div>
360 <div class="setting2">
361 <div class="setting_element">
362 <div class="setting_name">x18k Sync</div>${addSetting('x18ksync')}
363 </div>
364 </div>
365 <div class="settings_title">Auto Place</div>
366 <div class="setting2">
367 <div class="setting_element">
368 <div class="setting_name">Auto Place</div>${addSetting('autoPlace')}
369 </div>
370 </div>
371</div>
372<div id="visual_settings" class="settings_block" style="display: none;">
373 <div class="settings_title">Visual</div>
374 <div class="setting2">
375 <div class="setting_element">
376 <div class="setting_name">Game Zoom</div>${addTextInput('gamezoom', 15)}
377 </div>
378 </div>
379 <div class="settings_title">Debug</div>
380 <div class="setting2">
381 <div class="setting_element">
382 <div class="setting_name">Chat Log</div>${addSetting('chatlog')}
383 </div>
384 </div>
385</div>
386<div id="bots_settings" class="settings_block" style="display: none;">
387 <div class="settings_title">Name</div>
388 <div class="setting2">
389 <div class="setting_element">
390 <div class="setting_name">Bots Name</div>${addTextInput('botname', 15)}
391 </div>
392 </div>
393 <div class="settings_title">Count</div>
394 <div class="setting2">
395 <div class="setting_element">
396 <div class="setting_name">Bots Count</div>${addTextInput('botcount', 2)}
397 </div>
398 </div>
399 <div class="settings_title">Place</div>
400 <div class="setting2">
401 <div class="setting_element">
402 <div class="setting_name">Platform Placer</div>${addSetting('botplatformplacer')}
403 </div>
404 </div>
405 <div class="setting2">
406 <div class="setting_element invisible_element">
407 <button class="menu_button" id="send_bots">Send bots</button>
408 <button class="menu_button" id="close_bots" style="left: 260px;">Close bots</button>
409 </div>
410 </div>
411</div>
412`;
413
414document.body.appendChild(menu);
415
416// Create chat log
417const chatLog = document.createElement('div');
418chatLog.id = 'chat_log';
419chatLog.style.display = settings.chatlog ? 'block' : 'none';
420chatLog.innerHTML = `
421<div id="chat_name">Chat Log</div>
422<div id="chat_box"></div>
423`;
424document.body.appendChild(chatLog);
425
426// Chat log function
427function addChatLog(text, color = '#ffffff') {
428 const time = new Date();
429 const hours = String(time.getHours()).padStart(2, '0');
430 const minutes = String(time.getMinutes()).padStart(2, '0');
431 const seconds = String(time.getSeconds()).padStart(2, '0');
432
433 const chatMessage = document.createElement('div');
434 chatMessage.className = 'chat_message';
435 chatMessage.style.color = color;
436 chatMessage.innerText = `[${hours}:${minutes}:${seconds}] - ${text}`;
437
438 const chatBox = document.getElementById('chat_box');
439 chatBox.appendChild(chatMessage);
440 chatMessage.scrollIntoView({ behavior: 'auto', block: 'end' });
441}
442
443// Initialize
444addChatLog('Mod: Welcome to Laffer Mod!', '#00ff00');
445
446// Menu toggle
447document.addEventListener('keydown', (e) => {
448 if (e.keyCode === 192) { // Tilde key (~)
449 menu.style.display = menu.style.display === 'block' ? 'none' : 'block';
450 }
451});
452
453// Category switching
454function switchCategory(categoryId) {
455 // Hide all settings
456 document.querySelectorAll('.settings_block').forEach(block => {
457 block.style.display = 'none';
458 });
459
460 // Remove active class from all categories
461 document.querySelectorAll('.category').forEach(cat => {
462 cat.classList.remove('active');
463 });
464
465 // Show selected settings
466 const settingsId = categoryId + '_settings';
467 const settingsBlock = document.getElementById(settingsId);
468 if (settingsBlock) {
469 settingsBlock.style.display = 'block';
470 }
471
472 // Add active class to selected category
473 document.getElementById(categoryId).classList.add('active');
474}
475
476// Category event listeners
477document.getElementById('combat').addEventListener('click', () => switchCategory('combat'));
478document.getElementById('visual').addEventListener('click', () => switchCategory('visual'));
479document.getElementById('bots').addEventListener('click', () => switchCategory('bots'));
480document.getElementById('exit').addEventListener('click', () => {
481 menu.style.display = 'none';
482});
483
484// Settings change handlers
485for (let setting in settings) {
486 const element = document.getElementById(setting);
487 if (!element) continue;
488
489 element.addEventListener('change', function() {
490 if (typeof settings[setting] === 'boolean') {
491 settings[setting] = this.checked;
492
493 // Special handling for chat log
494 if (setting === 'chatlog') {
495 chatLog.style.display = this.checked ? 'block' : 'none';
496 }
497 } else {
498 settings[setting] = this.value;
499 }
500
501 saveSettings();
502 addChatLog(`Setting changed: ${setting} = ${settings[setting]}`, '#ffff00');
503 });
504}
505
506// Button handlers
507document.getElementById('fix_gather')?.addEventListener('click', () => {
508 if (typeof window.autogathering !== 'undefined') {
509 window.autogathering = !window.autogathering;
510 addChatLog(`Auto gathering: ${window.autogathering ? 'ON' : 'OFF'}`, '#00ff00');
511 }
512});
513
514document.getElementById('send_bots')?.addEventListener('click', () => {
515 addChatLog('Sending bots...', '#00ff00');
516 // Bot sending logic here
517});
518
519document.getElementById('close_bots')?.addEventListener('click', () => {
520 addChatLog('Closing bots...', '#ff0000');
521 // Bot closing logic here
522});
523
524// One-tick detector
525let oneTickDetectorActive = false;
526const POLEARM_RANGE = 140;
527const KATANA_RANGE = 100;
528const SOLDIER_HELMET_ID = 6;
529
530function dist2(a, b) {
531 return Math.hypot(a.x - b.x, a.y - b.y);
532}
533
534function getMyPlayer() {
535 return window.me || window.myPlayer || window.player || null;
536}
537
538function getAllPlayers() {
539 if (Array.isArray(window.players)) return window.players;
540 if (window.players && typeof window.players === 'object') return Object.values(window.players);
541 if (Array.isArray(window.entities)) return window.entities.filter(e => e?.isPlayer || e?.type === 'player');
542 return [];
543}
544
545function getHelmetId(p) {
546 return p?.hatId ?? p?.hat ?? p?.items?.hat ?? p?.gear?.helmet ?? p?.helmetId ?? null;
547}
548
549function performOneTickCheck() {
550 const me = getMyPlayer();
551 if (!me) return false;
552
553 const all = getAllPlayers();
554 if (!all?.length) return false;
555
556 let nearest = null;
557 let nearestDist = Infinity;
558
559 for (const p of all) {
560 if (!p || p === me || p.id === me.id) continue;
561 if (p.x == null || p.y == null) continue;
562
563 const d = dist2(me, p);
564 if (d < nearestDist) {
565 nearest = p;
566 nearestDist = d;
567 }
568 }
569
570 if (!nearest) return false;
571
572 const inRange = nearestDist <= Math.max(POLEARM_RANGE, KATANA_RANGE);
573 if (!inRange) return false;
574
575 const helmetId = getHelmetId(nearest);
576 if (helmetId !== SOLDIER_HELMET_ID) {
577 addChatLog('One-tick target detected without soldier helmet!', '#ff0000');
578 if (typeof window.onOneTickDetected === 'function') {
579 window.onOneTickDetected(nearest);
580 }
581 return true;
582 }
583 return false;
584}
585
586function frameCheck() {
587 if (!oneTickDetectorActive) return;
588 const ok = performOneTickCheck();
589 oneTickDetectorActive = false;
590 addChatLog(`One-tick check: ${ok ? 'DETECTED' : 'none'}`, ok ? '#ff0000' : '#00ff00');
591}
592
593// One-tick detector toggle (Shift + T)
594window.addEventListener('keydown', (e) => {
595 const isTyping = document.activeElement &&
596 (document.activeElement.tagName === 'INPUT' ||
597 document.activeElement.tagName === 'TEXTAREA' ||
598 document.activeElement.isContentEditable);
599
600 if (isTyping) return;
601
602 if (e.key === 'T' && e.shiftKey && !e.repeat) {
603 oneTickDetectorActive = !oneTickDetectorActive;
604 addChatLog(`One-tick detector: ${oneTickDetectorActive ? 'ON' : 'OFF'}`, '#00ffff');
605 if (oneTickDetectorActive) {
606 requestAnimationFrame(frameCheck);
607 }
608 }
609});
610
611console.log('%c[Laffer Mod] Loaded successfully!', 'color: #00ff00; font-size: 16px; font-weight: bold;');