Laffer Mod Menu

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;');