Laffer Mod Menu

Advanced mod menu for moomoo.io with combat features, visual settings, and bot controls

Size

15.1 KB

Version

1.2.1

Created

Nov 8, 2025

Updated

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