Greasy Fork is available in English.
A low-key pro-style MooMoo mod: scroll zoom (75% start, 15% minimum), autoheal, food spam, quick builds, and weapon controls. Hotkeys: P autoheal, Q food, F trap, V spike, H selected deployable; hold Q/F/V/H to spam. Left click selects primary; right click uses secondary.
// ==UserScript==
// @name Legit OP hack
// @namespace https://eclipse-mod.local/
// @version 3.5.0
// @description A low-key pro-style MooMoo mod: scroll zoom (75% start, 15% minimum), autoheal, food spam, quick builds, and weapon controls. Hotkeys: P autoheal, Q food, F trap, V spike, H selected deployable; hold Q/F/V/H to spam. Left click selects primary; right click uses secondary.
// @match *://moomoo.io/*
// @match *://*.moomoo.io/*
// @grant none
// @run-at document-start
// @license MIT
// ==/UserScript==
(() => {
"use strict";
const MIN_VIEW_MULTIPLIER = 0.5;
const MAX_VIEW_MULTIPLIER = 1 / 0.15;
const ZOOM_STEP = 1.1;
const INDICATOR_ID = "moomoo-scroll-zoom-indicator";
const GAME_BUNDLE = /\/assets\/index-[\w-]+\.js(?:\?.*)?$/;
const VIEWPORT_MARKER = "const _=y.maxScreenWidth,L=y.maxScreenHeight;";
const HOTKEY_MARKER = "t==69?wl():t==67?tl():t==88?gl():";
const FOOD_HOTKEY_MARKER = "t==81?je(v.items[0]):";
const FOOD_KEYUP_MARKER = "function pl(e){if(v&&v.alive){const t=e.which||e.keyCode||0;";
const BUNDLE_RETRY_LIMIT = 3;
const BUNDLE_RETRY_DELAY_MS = 400;
let viewMultiplier = 1 / 0.75;
let hideIndicatorTimer = 0;
let gameScriptHijacked = false;
let originalBundleLoaded = false;
window.__MooMooScrollZoomMultiplier = viewMultiplier;
function showZoomIndicator(message) {
if (!document.body) return;
let indicator = document.getElementById(INDICATOR_ID);
if (!indicator) {
indicator = document.createElement("div");
indicator.id = INDICATOR_ID;
indicator.style.cssText = [
"position:fixed",
"top:16px",
"left:50%",
"z-index:2147483647",
"transform:translateX(-50%)",
"padding:6px 10px",
"border-radius:6px",
"background:rgba(0,0,0,.65)",
"color:#fff",
"font:700 14px Arial,sans-serif",
"pointer-events:none",
"transition:opacity .2s"
].join(";");
document.body.appendChild(indicator);
}
// A larger viewport multiplier means more of the map is visible.
indicator.textContent = message || `Zoom: ${Math.round((1 / viewMultiplier) * 100)}%`;
indicator.style.opacity = "1";
clearTimeout(hideIndicatorTimer);
hideIndicatorTimer = window.setTimeout(() => {
indicator.style.opacity = "0";
}, 900);
}
function applyViewportSize() {
window.__MooMooScrollZoomMultiplier = viewMultiplier;
if (typeof window.__MooMooScrollZoomSetViewport === "function") {
window.__MooMooScrollZoomSetViewport(viewMultiplier);
}
}
function isGameSurface(target) {
return target instanceof Element && Boolean(target.closest("#gameCanvas, #touch-controls-fullscreen"));
}
document.addEventListener("wheel", (event) => {
if (!isGameSurface(event.target) || event.ctrlKey || event.deltaY === 0) return;
event.preventDefault();
event.stopImmediatePropagation();
viewMultiplier = Math.min(
MAX_VIEW_MULTIPLIER,
Math.max(MIN_VIEW_MULTIPLIER, viewMultiplier * (event.deltaY > 0 ? ZOOM_STEP : 1 / ZOOM_STEP))
);
applyViewportSize();
showZoomIndicator();
}, { capture: true, passive: false });
window.addEventListener("MooMooScrollZoomAutoheal", (event) => {
showZoomIndicator(`Autoheal: ${event.detail ? "On" : "Off"}`);
});
function patchedViewportCode() {
return [
"const __mmZoomBaseWidth=y.maxScreenWidth,__mmZoomBaseHeight=y.maxScreenHeight;",
"let _=y.maxScreenWidth,L=y.maxScreenHeight;",
"let __mmFoodSpamTimer=0;",
"let __mmAutoHealTimer=0,__mmAutoHealEnabled=!0,__mmAutoHealWasHealing=!1,__mmLastWeapon=null,__mmAutoHealWeapon=null;",
"let __mmBuildSpamTimer=0,__mmBuildSpamKey=0;",
"let __mmSecondaryHeld=!1;",
"const __mmOriginalSelect=je;je=function(__mmItem,__mmIsWeapon){return __mmIsWeapon&&(__mmLastWeapon=__mmItem),__mmOriginalSelect(__mmItem,__mmIsWeapon)};",
"function __mmUseFood(){if(v&&v.alive&&v.items[0]!=null){je(v.items[0]),O.send(\"F\",1,Ci()),O.send(\"F\",0,Ci())}}",
"function __mmAtFullHealth(){return v&&v.alive&&v.health>=v.maxHealth}",
"function __mmRestorePrimary(){v&&v.alive&&v.weapons[0]!=null&&je(v.weapons[0],!0)}",
"function __mmRestoreAutoHealWeapon(){if(!v||!v.alive)return;const __mmWeapon=v.weapons.includes(__mmAutoHealWeapon)?__mmAutoHealWeapon:v.weapons.includes(v.weaponIndex)?v.weaponIndex:v.weapons[0];__mmWeapon!=null&&je(__mmWeapon,!0),__mmAutoHealWeapon=null}",
"function __mmAutoHeal(){if(!__mmAutoHealEnabled||!v||!v.alive)return;if(v.health<v.maxHealth){__mmAutoHealWasHealing||(__mmAutoHealWasHealing=!0,__mmAutoHealWeapon=__mmLastWeapon),__mmUseFood()}else __mmAutoHealWasHealing&&(__mmAutoHealWasHealing=!1,__mmRestoreAutoHealWeapon())}",
"function __mmToggleAutoHeal(){__mmAutoHealEnabled=!__mmAutoHealEnabled,!__mmAutoHealEnabled&&__mmAutoHealWasHealing&&(__mmAutoHealWasHealing=!1,__mmRestoreAutoHealWeapon()),window.dispatchEvent(new CustomEvent(\"MooMooScrollZoomAutoheal\",{detail:__mmAutoHealEnabled}))}",
"function __mmStartAutoHeal(){__mmAutoHealTimer||(__mmAutoHealTimer=setInterval(__mmAutoHeal,1e3/y.serverUpdateRate))}",
"function __mmStartFoodSpam(){if(__mmFoodSpamTimer)return;__mmUseFood(),__mmFoodSpamTimer=setInterval(__mmUseFood,1e3/y.serverUpdateRate)}",
"function __mmStopFoodSpam(){__mmFoodSpamTimer&&(clearInterval(__mmFoodSpamTimer),__mmFoodSpamTimer=0)}",
"function __mmUseBuild(__mmItemSlot){if(!v||!v.alive)return;const __mmItem=__mmItemSlot<0?v.buildIndex:v.items[__mmItemSlot];if(__mmItem==null||__mmItem<0||__mmItemSlot<0&&![17,18,19,20,21,22].includes(__mmItem))return;__mmItemSlot>=0&&je(__mmItem),O.send(\"F\",1,Ci()),O.send(\"F\",0,Ci()),__mmRestorePrimary()}",
"function __mmStopBuildSpam(__mmKey){(!__mmKey||__mmKey==__mmBuildSpamKey)&&(__mmBuildSpamTimer&&clearInterval(__mmBuildSpamTimer),__mmBuildSpamTimer=0,__mmBuildSpamKey=0)}",
"function __mmStartBuildSpam(__mmItemSlot,__mmKey){if(__mmBuildSpamTimer&&__mmBuildSpamKey==__mmKey)return;__mmStopBuildSpam(),__mmBuildSpamKey=__mmKey,__mmUseBuild(__mmItemSlot),__mmBuildSpamTimer=setInterval(function(){__mmUseBuild(__mmItemSlot)},1e3/y.serverUpdateRate)}",
"window.addEventListener(\"blur\",__mmStopFoodSpam);",
"window.addEventListener(\"blur\",function(){__mmStopBuildSpam()});",
"function __mmIsGameClick(__mmEvent){return __mmEvent.target instanceof Element&&__mmEvent.target.closest(\"#gameCanvas,#touch-controls-fullscreen\")}",
"document.addEventListener(\"mousedown\",function(__mmEvent){if(!__mmIsGameClick(__mmEvent)||__mmEvent.button!==0&&__mmEvent.button!==2)return;__mmEvent.button===0&&v&&v.alive&&v.weapons[0]!=null&&je(v.weapons[0],!0),__mmAtFullHealth()&&__mmStopFoodSpam()},!0);",
"function __mmStopSecondary(){__mmSecondaryHeld&&(O.send(\"F\",0,Ci()),__mmSecondaryHeld=!1)}",
"document.addEventListener(\"mousedown\",function(__mmEvent){if(__mmEvent.button!==2||!__mmIsGameClick(__mmEvent)||!v||!v.alive||v.weapons[1]==null)return;__mmEvent.preventDefault(),__mmEvent.stopImmediatePropagation(),je(v.weapons[1],!0),O.send(\"F\",1,Ci()),__mmSecondaryHeld=!0},!0);",
"document.addEventListener(\"mouseup\",function(__mmEvent){__mmEvent.button===2&&__mmSecondaryHeld&&(__mmEvent.preventDefault(),__mmEvent.stopImmediatePropagation(),__mmStopSecondary())},!0);",
"document.addEventListener(\"contextmenu\",function(__mmEvent){__mmIsGameClick(__mmEvent)&&__mmEvent.preventDefault()},!0);",
"window.addEventListener(\"blur\",__mmStopSecondary);",
"__mmStartAutoHeal();",
"window.__MooMooScrollZoomSetViewport=function(__mmZoomMultiplier){",
"const __mmMultiplier=Math.max(" + MIN_VIEW_MULTIPLIER + ",Math.min(" + MAX_VIEW_MULTIPLIER + ",Number(__mmZoomMultiplier)||1));",
"_=y.maxScreenWidth=__mmZoomBaseWidth*__mmMultiplier;",
"L=y.maxScreenHeight=__mmZoomBaseHeight*__mmMultiplier;",
"bi();",
"};",
"setTimeout(function(){window.__MooMooScrollZoomSetViewport(window.__MooMooScrollZoomMultiplier||1)},0);"
].join("");
}
function patchedHotkeyCode() {
// Item slots 2 and 4 are the current spike and pit-trap upgrades.
return "t==80?__mmToggleAutoHeal():t==72?__mmStartBuildSpam(-1,72):t==70&&v.items[4]!=null?__mmStartBuildSpam(4,70):t==86&&v.items[2]!=null?__mmStartBuildSpam(2,86):" + HOTKEY_MARKER;
}
function patchedFoodHotkeyCode() {
return "t==81?__mmStartFoodSpam():";
}
function patchedFoodKeyupCode() {
return "function pl(e){const __mmFoodKey=e.which||e.keyCode||0;__mmFoodKey==81&&__mmStopFoodSpam();(__mmFoodKey==70||__mmFoodKey==72||__mmFoodKey==86)&&__mmStopBuildSpam(__mmFoodKey);if(v&&v.alive){const t=e.which||e.keyCode||0;";
}
function wait(milliseconds) {
return new Promise((resolve) => window.setTimeout(resolve, milliseconds));
}
function loadOriginalBundle(originalUrl) {
if (originalBundleLoaded) return;
originalBundleLoaded = true;
const fallbackScript = document.createElement("script");
fallbackScript.type = "module";
fallbackScript.src = originalUrl;
(document.head || document.documentElement).appendChild(fallbackScript);
}
async function fetchBundleSource(originalUrl) {
let lastError;
for (let attempt = 1; attempt <= BUNDLE_RETRY_LIMIT; attempt += 1) {
try {
const response = await fetch(originalUrl, { cache: "force-cache" });
if (!response.ok) throw new Error(`bundle request failed (${response.status})`);
return await response.text();
} catch (error) {
lastError = error;
if (attempt < BUNDLE_RETRY_LIMIT) {
console.warn(`[MooMoo Scroll Zoom] bundle attempt ${attempt} failed; retrying.`);
await wait(BUNDLE_RETRY_DELAY_MS * attempt);
}
}
}
throw lastError || new Error("bundle request failed");
}
async function loadPatchedBundle(originalUrl) {
try {
const originalSource = await fetchBundleSource(originalUrl);
if (!originalSource.includes(VIEWPORT_MARKER) || !originalSource.includes(HOTKEY_MARKER) || !originalSource.includes(FOOD_HOTKEY_MARKER) || !originalSource.includes(FOOD_KEYUP_MARKER)) {
throw new Error("the game client changed; a required patch marker was not found");
}
const bundleUrl = new URL(originalUrl, location.href);
const patchedSource = originalSource
.replace(VIEWPORT_MARKER, patchedViewportCode())
.replace(HOTKEY_MARKER, patchedHotkeyCode())
.replace(FOOD_HOTKEY_MARKER, patchedFoodHotkeyCode())
.replace(FOOD_KEYUP_MARKER, patchedFoodKeyupCode())
.replace(/from"\.\/vendor-[^"]+\.js"/, (specifier) => {
const path = specifier.slice(5, -1);
return `from"${new URL(path, bundleUrl).href}"`;
});
const blobUrl = URL.createObjectURL(new Blob([patchedSource], { type: "text/javascript" }));
const patchedScript = document.createElement("script");
patchedScript.type = "module";
patchedScript.src = blobUrl;
patchedScript.onload = () => URL.revokeObjectURL(blobUrl);
patchedScript.onerror = () => {
URL.revokeObjectURL(blobUrl);
console.error("[MooMoo Scroll Zoom] patched game bundle could not load; loading the original bundle.");
loadOriginalBundle(originalUrl);
};
(document.head || document.documentElement).appendChild(patchedScript);
} catch (error) {
console.error("[MooMoo Scroll Zoom] could not patch the game bundle; loading the original bundle.", error);
loadOriginalBundle(originalUrl);
}
}
function interceptGameBundle(script) {
if (gameScriptHijacked || !script.src || !GAME_BUNDLE.test(new URL(script.src, location.href).pathname)) return;
gameScriptHijacked = true;
const originalUrl = script.src;
script.type = "application/x-moomoo-scroll-zoom-blocked";
script.removeAttribute("src");
script.remove();
loadPatchedBundle(originalUrl);
}
const observer = new MutationObserver((records) => {
for (const record of records) {
for (const node of record.addedNodes) {
if (node.nodeType === Node.ELEMENT_NODE && node.tagName === "SCRIPT") {
interceptGameBundle(node);
}
}
}
});
observer.observe(document, { childList: true, subtree: true });
document.querySelectorAll("script[src]").forEach(interceptGameBundle);
})();