// ==UserScript==
// @name Moomoo.io 1.8.0 JS-AutoHeal & Interactive Menu
// @version 2
// @description Toggle Autoheal using "P", open the menu with "Esc" to adjust speed, multiplier, or HP Umbral.
// @author Seryo
// @match *://*.moomoo.io/*
// @namespace https://greasyfork.org/users/1190411
// @icon https://cdn.glitch.com/82ae8945-dcc6-4276-98a9-665381b4cd2b/cursor12.png
// @grant none
// @license MIT
// @require https://greasyfork.org/scripts/440839-moomoo-items/code/MooMoo%20Items.js?version=1023778
// @require https://greasyfork.org/scripts/423602-msgpack/code/msgpack.js?version=1005014
// ==/UserScript==
let autoHealEnabled = true;
let menuVisible = false;
let speed = { hotKey: "" };
let hp = { hotKey: "" };
let multiplier = { hotKey: "" };
function restoreMenuValues() {
document.getElementById('hpInput').value = this.hotkeys.settings.heal.hp !== undefined ? this.hotkeys.settings.heal.hp : '86';
document.getElementById('speedInput').value = this.hotkeys.settings.heal.speed !== undefined ? this.hotkeys.settings.heal.speed : '125';
document.getElementById('multiplierInput').value = this.hotkeys.settings.heal.multiplier !== undefined ? this.hotkeys.settings.heal.multiplier : '2';
}
function hideElements() {
const leaderboard = document.getElementById('leaderboard');
const killCounter = document.getElementById('killCounter');
if (leaderboard) {
leaderboard.style.display = 'none';
}
if (killCounter) {
killCounter.style.display = 'none';
}
}
document.addEventListener('DOMContentLoaded', () => {
hideElements();
MooMoo.appendMenu();
MooMoo.restoreMenuValues();
});
function isChatOpen() {
return document.activeElement.id.toLowerCase() === 'chatbox';
}
function isAllianceInputActive() {
return document.activeElement.id.toLowerCase() === 'allianceinput';
}
function shouldHandleHotkeys() {
return !isChatOpen() && !isAllianceInputActive();
}
function updateAutoHealStateText() {
const stateText = document.getElementById('autoHealState');
if (stateText) {
stateText.textContent = autoHealEnabled ? 'On' : 'Off';
}
}
class MooMoo {
static updateSettings() {
const hp = parseInt(document.getElementById('hpInput').value);
const speed = parseInt(document.getElementById('speedInput').value);
const multiplier = parseInt(document.getElementById('multiplierInput').value);
this.hotkeys.settings.heal.hp = hp;
this.hotkeys.settings.heal.speed = speed;
this.hotkeys.settings.heal.multiplier = multiplier;
localStorage.setItem('moomoo_settings', JSON.stringify(this.hotkeys.settings));
document.getElementById('hpValue').textContent = `${hp}`;
document.getElementById('speedValue').textContent = `${speed}`;
document.getElementById('multiplierValue').textContent = `${multiplier}`;
}
static loadSettings() {
const savedSettings = localStorage.getItem('moomoo_settings');
if (savedSettings) {
this.hotkeys.settings = JSON.parse(savedSettings);
this.restoreMenuValues();
}
document.getElementById('hpInput').value = this.hotkeys.settings.heal.hp !== undefined ? this.hotkeys.settings.heal.hp : 'none';
document.getElementById('speedInput').value = this.hotkeys.settings.heal.speed !== undefined ? this.hotkeys.settings.heal.speed : 'none';
document.getElementById('multiplierInput').value = this.hotkeys.settings.heal.multiplier !== undefined ? this.hotkeys.settings.heal.multiplier : 'none';
}
static appendMenu() {
const menuDiv = document.createElement('div');
menuDiv.id = 'moomooMenu';
menuDiv.innerHTML = `
<h2 style="text-align: center; font-size: 28px;">Autoheal <span id="autoHealState">On</span></h2>
<hr>
<label for="hpInput">HP Umbral</label>
<input type="number" id="hpInput" oninput="this.value = this.value.slice(0, 3)" value="86">
<span id="hpValue"></span>
<hr>
<label for="speedInput">Speed</label>
<input type="number" id="speedInput" oninput="this.value = this.value.slice(0, 4)" value="125">
<span id="speedValue"></span>
<hr>
<label for="multiplierInput">Multiplier</label>
<input type="number" id="multiplierInput" oninput="this.value = this.value.slice(0, 2)" value="2">
<span id="multiplierValue"></span>
`;
menuDiv.style.display = 'none';
menuDiv.style.background = 'rgba(0, 0, 0, 0.8';
menuDiv.style.fontFamily = 'Hammersmith One, sans-serif';
menuDiv.style.position = 'fixed';
menuDiv.style.top = '20px';
menuDiv.style.right = '20px';
menuDiv.style.border = '1px solid #000';
menuDiv.style.borderRadius = '8px';
menuDiv.style.boxShadow = '0px 0px 10px rgba(0, 0, 0, 0.25)';
menuDiv.style.boxShadow = '5px 5px 10px rgba(0, 0, 0, 0.4)';
menuDiv.style.width = '216px';
menuDiv.style.color = '#fff';
menuDiv.style.fontSize = '17px';
menuDiv.style.zIndex = '1000';
menuDiv.style.overflowY = 'auto';
menuDiv.style.padding = '10px';
document.body.appendChild(menuDiv);
document.getElementById('hpInput').classList.add('menu-input');
document.getElementById('speedInput').classList.add('menu-input');
document.getElementById('multiplierInput').classList.add('menu-input');
document.querySelectorAll('.menu-input').forEach((input) => {
input.addEventListener('focus', () => {
input.addEventListener('input', handleNumericInput);
});
input.addEventListener('blur', () => {
input.removeEventListener('input', handleNumericInput);
});
});
document.getElementById('hpInput').style.width = "41px";
document.getElementById('speedInput').style.width = "49px";
document.getElementById('multiplierInput').style.width = "33px";
}
static saveSettings() {
this.updateSettings();
// Hide the menu after saving settings
const menu = document.getElementById('moomooMenu');
if (menu) {
menu.style.display = 'none';
}
// Show the hidden elements
const leaderboard = document.getElementById('leaderboard');
const killCounter = document.getElementById('killCounter');
if (leaderboard) {
leaderboard.style.display = 'block';
}
if (killCounter) {
killCounter.style.display = 'block';
}
}
static get hotkeys() {
return {
settings: {
heal: {
speed: speed.hotKey,
hp: hp.hotKey,
multiplier: multiplier.hotKey
}
}
};
}
static set forcedisablecps(arg) {
this.forcedisable = arg
}
static fixweaponswap() {
let keys = ['1', '2']
let local = this;
let items = window.items
let spammers = this.spammers
for(let i in keys) {
document.addEventListener('keydown', e => {
if(document.activeElement.type == "text") return;
if(e.key == keys[i]) {
switch(keys[i]) {
case '1':
for(let i = 0; i < 10; i++) {
setTimeout(() => {
local.sendws(["G", [items.primary, true]])
}, i*2)
}
break;
case '2':
for(let i = 0; i < 10; i++) {
setTimeout(() => {
local.sendws(["G", [items.secondary, true]])
}, i*2)
}
}
}
})
}
}
static init(arg) {
this.fixweaponswap()
this.antiinvis();
this.canvas = document.getElementById("gameCanvas");
this.initplayer();
this.getkeys();
this.setmouse()
this.initspammer();
this.spammers = {};
this.result = "";
this.initcps();
this.cps = 0;
this.doc = document;
this.initlisteners;
this.id = `#${arg.match(/d="?g(.*)?I/g)[0].match(/(?=g).*(?=)/)[0]}`
window.addEventListener("load", function(event) {
MooMoo.initHTML;
})
}
static get getalpha() {
this.alpha = Array.from(Array(26)).map((e, i) => i + 65).map((x) => String.fromCharCode(x));
for(let i in this.alpha) {
this.result += this.alpha[i]
}
return this.result.toLocaleLowerCase();
}
static getkeys() {
this.lts = new Array();
this.lts.push(this.getalpha.match(/v([\s\S]*)w/g)[0].split("v")[1])
this.lts.push(this.getalpha.match(/(.+(?=[b])|(?<=str).+)/g)[0].split('d')[2].split('a')[0])
this.lts.push(this.getalpha.match(/\m(.*?)\o/))[0]
this.lts.push(this.getalpha.match(/(?=d).*(?=e)/g)[0].split("c")[1].split('')[0])
}
static get initlisteners() {
this.doc.onkeydown = function(e) {
if(document.activeElement.type == "text") return;
MooMoo.handleKeyDown(e)
};
this.doc.onkeyup = function(e) {
if(document.activeElement.type == "text") return;
MooMoo.handleKeyUp(e)
}
}
static antiinvis() {
CanvasRenderingContext2D.prototype.rotatef = CanvasRenderingContext2D.prototype.rotate
CanvasRenderingContext2D.prototype.rotate = function(e){
if(Math.abs(e) > 1e300){
e = Math.atan2(Math.cos(e), Math.sin(e));
this.globalAlpha = 0.5;
this.rotatef(e);
}else{
this.rotatef(e);
}
};
}
static get() {
return new Promise(resolve => {
fetch(arguments[0]).then(res => res.text()).then(res => {
return resolve(res);
});
});
}
static ioinit() {
this.width = this.canvas.clientWidth;
this.height = this.canvas.clientHeight;
this.canvas.addEventListener("mousemove", e => {
this.mouse.x = e.clientX;
this.mouse.y = e.clientY;
});
}
static setws (args) {
this.ws = args
}
static get initHTML() {
this.appendMenu();
}
static initplayer() {
this.player = {
id: null,
weapon: null
}
}
static setmouse() {
this.mouse = {
x: null,
y: null
}
}
static checkelement(e) {
return (e.offsetParent !== null);
}
static handleHit(arg) {
switch(this.decode(arg)[1][0]) {
case 1:
this.handleCPS()
}
}
static handleCPS() {
this.initcps();
this.cps++
setTimeout(() => {
this.initcps();
this.cps--
}, 1000)
}
static sendws(sender) {
this.ws.send(new Uint8Array(Array.from(msgpack.encode(sender))));
}
static getnormalangle() {
return Math.atan2(this.mouse.y - this.height / 2, this.mouse.x - this.width / 2)
}
static hit(angle) {
this.sendws(["d", [1, angle]]);
this.sendws(["d", [0, angle]]);
}
static placeitem(id, angle = this.getnormalangle()) {
this.sendws(["G", [id, null]]);
this.hit(angle)
this.createfakeclick()
this.sendws(["G", [this.player.weapon, true]]);
}
static placefood(id) {
this.sendws(["G", [id, null]]);
this.hit(this.getnormalangle())
this.createfoodpress();
this.sendws(["G", [this.player.weapon, true]]);
}
static item1 (data) {
if(!this.player.id) {
this.player.id = data[1];
console.log(this.player)
}
}
static updateplayer(data) {
this.rndata = data
for (let i = 0; i < this.rndata[1].length / 13; i++) {
this.playerInfo = this.rndata[1].slice(13 * i, 13 * i + 13);
if (this.playerInfo[0] == this.player.id) {
this.player.weapon = this.playerInfo[5];
}
}
}
static doautoheal(data) {
let items = window.items;
if (autoHealEnabled) {
if (data[2] < 60) {
return;
} else if (data[2] >= 60 && data[2] <= 85) {
setTimeout(() => {
for (let i = 0; i < 1; i++) {
this.placefood(items.food);
}
}, 350);
} else if (data[2] > 85) {
return;
}
}
}
static getwsmessage(message) {
let temp = this.decode(new Uint8Array(message.data));
let data;
if (temp.length > 1) {
data = [temp[0], ...temp[1]];
if (data[1] instanceof Array) {
data = data;
}
} else {
data = temp;
}
let item = data[0];
if (!data) {
return;
}
if (item === "io-init") {
this.ioinit();
}
if (item == "C") {
this.item1(data);
}
if (item == "a") {
this.updateplayer(data);
}
switch (item) {
case '8':
console.log(data);
break;
case 'O':
if (data[1] == this.player.id) {
if (data[2] === 'autoheal: on') {
autoHealEnabled = true;
console.log("AutoHeal is now ON");
} else if (data[2] === 'autoheal: off') {
autoHealEnabled = false;
console.log("AutoHeal is now OFF");
} else {
this.doautoheal(data);
}
}
break;
}
}
static doautoheal(data) {
let items = window.items;
if (autoHealEnabled) {
const hpThreshold = parseInt(document.getElementById('hpInput').value);
const healSpeed = parseInt(document.getElementById('speedInput').value);
const healMultiplier = parseInt(document.getElementById('multiplierInput').value);
if (data[2] < hpThreshold) {
setTimeout(() => {
for (let i = 0; i < healMultiplier; i++) {
this.placefood(items.food);
}
}, healSpeed);
}
}
}
static decode(arg) {
return msgpack.decode(arg)
}
static initspammer() {
this.spammers = {};
let spammers = this.spammers;
document.addEventListener('keydown', (e) => {
if (document.activeElement.id.toLocaleLowerCase() !== 'chatbox' && document.activeElement.id.toLocaleLowerCase() !== 'mainMenu') {
spammers.food.start(e.key);
}
});
document.addEventListener('keyup', (e) => {
if(document.activeElement.type == "text") return;
spammers.food.stop(e.key);
});
}
static append() {
$(this.id).append(arguments[0])
}
static getelement() {
return document.getElementById(arguments[0])
}
static initcps() {
if(!this.getelement("cpsdisplay")) return;
this.getelement("cpsdisplay").textContent = "CPS: " + this.cps
}
static createfakeclick() {
setTimeout(() => {
MooMoo.addAttribute("kdisp-RButton")
setTimeout(() => {
MooMoo.deleteAttribute("kdisp-RButton")
}, 50)
}, 50)
}
static createfakeclick() {
setTimeout(() => {
MooMoo.addAttribute("kdisp-RButton")
setTimeout(() => {
MooMoo.deleteAttribute("kdisp-RButton")
}, 50)
}, 50)
}
static createfoodpress() {
setTimeout(() => {
this.addAttribute("kdisp-food")
setTimeout(() => {
this.deleteAttribute("kdisp-food")
}, 50)
}, 50)
setTimeout(() => {
this.addAttribute("kdisp-RButton")
setTimeout(() => {
this.deleteAttribute("kdisp-RButton")
}, 50)
}, 50)
}
}
document.addEventListener('keydown', (e) => {
if (e.keyCode === 80 && shouldHandleHotkeys()) {
autoHealEnabled = !autoHealEnabled;
document.title = autoHealEnabled ? "𝙷𝚎𝚊𝚕 𝙾𝙽" : "𝙷𝚎𝚊𝚕 𝙾𝙵𝙵";
console.log("AutoHeal is now " + (autoHealEnabled ? "ON" : "OFF"));
updateAutoHealStateText();
}
});
function toggleMenu() {
const menu = document.getElementById('moomooMenu');
if (menu) {
if (menu.style.display === 'none') {
menu.style.display = 'block';
menuVisible = true;
hideElements();
} else {
menu.style.display = 'none';
menuVisible = false;
const leaderboard = document.getElementById('leaderboard');
const killCounter = document.getElementById('killCounter');
if (leaderboard) {
leaderboard.style.display = 'block';
}
if (killCounter) {
killCounter.style.display = 'block';
}
}
if (menuVisible) {
MooMoo.restoreMenuValues();
}
updateAutoHealStateText();
}
}
document.addEventListener('keydown', (e) => {
if (e.keyCode === 27 && shouldHandleHotkeys() && storeMenu.style.display !== 'block') {
toggleMenu();
}
});
(async () => {
const game = await MooMoo.get(document.location.href);
MooMoo.init(game);
var ws;
WebSocket.prototype._send = WebSocket.prototype.send;
WebSocket.prototype.send = function (m) {
if (MooMoo.decode(m)[0] == "d") {
MooMoo.handleHit(m);
}
if (!ws) {
document.ws = this;
ws = this;
this.addEventListener('message', function (message) {
MooMoo.setws(this);
MooMoo.getwsmessage(message);
});
}
this._send(m);
};
})();