您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Customize store
当前为
// ==UserScript== // @name MooMoo.io Custom Store // @description Customize store // @author WEIRD // @match *://*.moomoo.io/* // @icon https://moomoo.io/img/favicon.png?v=1 // @require https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.10.2/Sortable.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/msgpack-lite/0.1.26/msgpack.min.js // @run-at document-start // @grant unsafeWindow // @license MIT // @version 0.2.2 // @namespace https://gf.qytechs.cn/users/999838 // ==/UserScript== /* - Right-click the Store Button to access the editing options - Press "B" to toggle store menu - To change the order of your hats and accessories, simply drag and drop them to the desired position - Add a blank space to give your collection some extra style - Don't need a particular hat or accessory? Delete it with just a click - Export your changes or import customizations */ (async () => { unsafeWindow.customStore = true const elementID = id => { return document.getElementById(id) } var inGame = false await new Promise(async resolve => { let { send } = WebSocket.prototype WebSocket.prototype.send = function (...x) { send.apply(this, x) this.send = send this.addEventListener("message", e => { const [packet, data] = msgpack.decode(new Uint8Array(e.data)) switch (packet) { case "us": if (elementID("storeMenu").style.display == "block") { generateStoreList() } break case "1": myPlayer.sid = data[0] inGame = true break case "11": inGame = false break } }) resolve(this) } }) const myPlayer = { sid: null, playerObject: null } const symbol = Symbol("lockDir") Object.defineProperty(Object.prototype, "lockDir", { get() { return this[symbol] }, set(value) { this[symbol] = value if (this.isPlayer === true && this.sid === myPlayer.sid) { myPlayer.playerObject = this } }, configurable: true }) function waitForElm(selector) { return new Promise(resolve => { if (document.querySelector(selector)) { return resolve(document.querySelector(selector)) } const observer = new MutationObserver(mutations => { if (document.querySelector(selector)) { resolve(document.querySelector(selector)) observer.disconnect() } }) observer.observe(document.body, { childList: true, subtree: true }) }) } const customStoreHolder = document.createElement("div") customStoreHolder.id = "customStoreHolder" waitForElm("#storeHolder").then(storeHolder => { const style = document.createElement("style") style.innerHTML = ` #customStoreHolder { pointer-events: all; width: 400px; display: inline-block; background-color: rgba(0, 0, 0, 0.25); -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; color: #fff; padding: 10px; height: 200px; max-height: calc(100vh - 200px); overflow-y: scroll; -webkit-overflow-scrolling: touch; } ` document.head.appendChild(style) storeHolder.parentNode.insertBefore(customStoreHolder, storeHolder.nextSibling) storeHolder.style.display = "none" }) var currentStoreIndex = 0 var store = { hats: [{ id: 51, name: "Moo Cap", price: 0, scale: 120, desc: "coolest mooer around" }, { id: 50, name: "Apple Cap", price: 0, scale: 120, desc: "apple farms remembers" }, { id: 28, name: "Moo Head", price: 0, scale: 120, desc: "no effect" }, { id: 29, name: "Pig Head", price: 0, scale: 120, desc: "no effect" }, { id: 30, name: "Fluff Head", price: 0, scale: 120, desc: "no effect" }, { id: 36, name: "Pandou Head", price: 0, scale: 120, desc: "no effect" }, { id: 37, name: "Bear Head", price: 0, scale: 120, desc: "no effect" }, { id: 38, name: "Monkey Head", price: 0, scale: 120, desc: "no effect" }, { id: 44, name: "Polar Head", price: 0, scale: 120, desc: "no effect" }, { id: 35, name: "Fez Hat", price: 0, scale: 120, desc: "no effect" }, { id: 42, name: "Enigma Hat", price: 0, scale: 120, desc: "join the enigma army" }, { id: 43, name: "Blitz Hat", price: 0, scale: 120, desc: "hey everybody i'm blitz" }, { id: 49, name: "Bob XIII Hat", price: 0, scale: 120, desc: "like and subscribe" }, { id: 57, name: "Pumpkin", price: 50, scale: 120, desc: "Spooooky" }, { id: 8, name: "Bummle Hat", price: 100, scale: 120, desc: "no effect" }, { id: 2, name: "Straw Hat", price: 500, scale: 120, desc: "no effect" }, { id: 15, name: "Winter Cap", price: 600, scale: 120, desc: "allows you to move at normal speed in snow", coldM: 1 }, { id: 5, name: "Cowboy Hat", price: 1000, scale: 120, desc: "no effect" }, { id: 4, name: "Ranger Hat", price: 2000, scale: 120, desc: "no effect" }, { id: 18, name: "Explorer Hat", price: 2000, scale: 120, desc: "no effect" }, { id: 31, name: "Flipper Hat", price: 2500, scale: 120, desc: "have more control while in water", watrImm: true }, { id: 1, name: "Marksman Cap", price: 3000, scale: 120, desc: "increases arrow speed and range", aMlt: 1.3 }, { id: 10, name: "Bush Gear", price: 3000, scale: 160, desc: "allows you to disguise yourself as a bush" }, { id: 48, name: "Halo", price: 3000, scale: 120, desc: "no effect" }, { id: 6, name: "Soldier Helmet", price: 4000, scale: 120, desc: "reduces damage taken but slows movement", spdMult: 0.94, dmgMult: 0.75 }, { id: 23, name: "Anti Venom Gear", price: 4000, scale: 120, desc: "makes you immune to poison", poisonRes: 1 }, { id: 13, name: "Medic Gear", price: 5000, scale: 110, desc: "slowly regenerates health over time", healthRegen: 3 }, { id: 9, name: "Miners Helmet", price: 5000, scale: 120, desc: "earn 1 extra gold per resource", extraGold: 1 }, { id: 32, name: "Musketeer Hat", price: 5000, scale: 120, desc: "reduces cost of projectiles", projCost: 0.5 }, { id: 7, name: "Bull Helmet", price: 6000, scale: 120, desc: "increases damage done but drains health", healthRegen: -5, dmgMultO: 1.5, spdMult: 0.96 }, { id: 22, name: "Emp Helmet", price: 6000, scale: 120, desc: "turrets won't attack but you move slower", antiTurret: 1, spdMult: 0.7 }, { id: 12, name: "Booster Hat", price: 6000, scale: 120, desc: "increases your movement speed", spdMult: 1.16 }, { id: 26, name: "Barbarian Armor", price: 8000, scale: 120, desc: "knocks back enemies that attack you", dmgK: 0.6 }, { id: 21, name: "Plague Mask", price: 10000, scale: 120, desc: "melee attacks deal poison damage", poisonDmg: 5, poisonTime: 6 }, { id: 46, name: "Bull Mask", price: 10000, scale: 120, desc: "bulls won't target you unless you attack them", bullRepel: 1 }, { id: 14, name: "Windmill Hat", topSprite: true, price: 10000, scale: 120, desc: "generates points while worn", pps: 1.5 }, { id: 11, name: "Spike Gear", topSprite: true, price: 10000, scale: 120, desc: "deal damage to players that damage you", dmg: 0.45 }, { id: 53, name: "Turret Gear", topSprite: true, price: 10000, scale: 120, desc: "you become a walking turret", turret: { proj: 1, range: 700, rate: 2500 }, spdMult: 0.7 }, { id: 20, name: "Samurai Armor", price: 12000, scale: 120, desc: "increased attack speed and fire rate", atkSpd: 0.78 }, { id: 58, name: "Dark Knight", price: 12000, scale: 120, desc: "restores health when you deal damage", healD: 0.4 }, { id: 27, name: "Scavenger Gear", price: 15000, scale: 120, desc: "earn double points for each kill", kScrM: 2 }, { id: 40, name: "Tank Gear", price: 15000, scale: 120, desc: "increased damage to buildings but slower movement", spdMult: 0.3, bDmg: 3.3 }, { id: 52, name: "Thief Gear", price: 15000, scale: 120, desc: "steal half of a players gold when you kill them", goldSteal: 0.5 }, { id: 55, name: "Bloodthirster", price: 20000, scale: 120, desc: "Restore Health when dealing damage. And increased damage", healD: 0.25, dmgMultO: 1.2, }, { id: 56, name: "Assassin Gear", price: 20000, scale: 120, desc: "Go invisible when not moving. Can't eat. Increased speed", noEat: true, spdMult: 1.1, invisTimer: 1000 }], accessories: [{ id: 12, name: "Snowball", price: 1000, scale: 105, xOff: 18, desc: "no effect" }, { id: 9, name: "Tree Cape", price: 1000, scale: 90, desc: "no effect" }, { id: 10, name: "Stone Cape", price: 1000, scale: 90, desc: "no effect" }, { id: 3, name: "Cookie Cape", price: 1500, scale: 90, desc: "no effect" }, { id: 8, name: "Cow Cape", price: 2000, scale: 90, desc: "no effect" }, { id: 11, name: "Monkey Tail", price: 2000, scale: 97, xOff: 25, desc: "Super speed but reduced damage", spdMult: 1.35, dmgMultO: 0.2 }, { id: 17, name: "Apple Basket", price: 3000, scale: 80, xOff: 12, desc: "slowly regenerates health over time", healthRegen: 1 }, { id: 6, name: "Winter Cape", price: 3000, scale: 90, desc: "no effect" }, { id: 4, name: "Skull Cape", price: 4000, scale: 90, desc: "no effect" }, { id: 5, name: "Dash Cape", price: 5000, scale: 90, desc: "no effect" }, { id: 2, name: "Dragon Cape", price: 6000, scale: 90, desc: "no effect" }, { id: 1, name: "Super Cape", price: 8000, scale: 90, desc: "no effect" }, { id: 7, name: "Troll Cape", price: 8000, scale: 90, desc: "no effect" }, { id: 14, name: "Thorns", price: 10000, scale: 115, xOff: 20, desc: "no effect" }, { id: 15, name: "Blockades", price: 10000, scale: 95, xOff: 15, desc: "no effect" }, { id: 20, name: "Devils Tail", price: 10000, scale: 95, xOff: 20, desc: "no effect" }, { id: 16, name: "Sawblade", price: 12000, scale: 90, spin: true, xOff: 0, desc: "deal damage to players that damage you", dmg: 0.15 }, { id: 13, name: "Angel Wings", price: 15000, scale: 138, xOff: 22, desc: "slowly regenerates health over time", healthRegen: 3 }, { id: 19, name: "Shadow Wings", price: 15000, scale: 138, xOff: 22, desc: "increased movement speed", spdMult: 1.1 }, { id: 18, name: "Blood Wings", price: 20000, scale: 178, xOff: 26, desc: "restores health when you deal damage", healD: 0.2 }, { id: 21, name: "Corrupt X Wings", price: 20000, scale: 178, xOff: 26, desc: "deal damage to players that damage you", dmg: 0.25 }] } var checkRealStore = JSON.parse(localStorage.getItem('realStore')) if (checkRealStore == null) { localStorage.setItem('realStore', JSON.stringify(store)) } var customStore = JSON.parse(localStorage.getItem('customStore')) if (customStore == null) { customStore = store localStorage.setItem('customStore', JSON.stringify(store)) } var sortable = null function generateStoreList() { if (inGame) { while (customStoreHolder.hasChildNodes()) { customStoreHolder.removeChild(customStoreHolder.lastChild) } var index = currentStoreIndex var tmpArray = index ? customStore.accessories : customStore.hats addEdit.style.display = customStoreButton.style.background == "red" ? null : "none" reloadEdit.style.display = customStoreButton.style.background == "red" ? null : "none" importBut.style.display = customStoreButton.style.background == "red" ? null : "none" exportBut.style.display = customStoreButton.style.background == "red" ? null : "none" Array.from(tmpArray).forEach(ele => { let tmp = document.createElement("div") tmp.id = "storeDisplay" + ele.id tmp.className = "storeItem" customStoreHolder.appendChild(tmp) let childtmp if (!ele.blank) { tmp.onmouseout = () => { unsafeWindow.showItemInfo() } tmp.onmouseover = () => { unsafeWindow.showItemInfo(ele, false, true) } childtmp = document.createElement("img") childtmp.className = "hatPreview" childtmp.src = "../img/" + (index ? "accessories/access_" : "hats/hat_") + ele.id + (ele.topSprite ? "_p" : "") + ".png" tmp.appendChild(childtmp) childtmp = document.createElement("span") childtmp.textContent = ele.name tmp.appendChild(childtmp) } else { childtmp = document.createElement("div") childtmp.className = "hatPreview" tmp.appendChild(childtmp) } if (customStoreButton.style.background == "red") { childtmp = document.createElement("div") childtmp.className = "joinAlBtn" childtmp.style = "margin-top: 5px" childtmp.textContent = "Delete" tmp.appendChild(childtmp) childtmp.onclick = () => { let arr = index ? customStore.accessories : customStore.hats const objWithIdIndex = arr.findIndex(obj => obj.id === ele.id) if (objWithIdIndex > -1) { arr.splice(objWithIdIndex, 1) } localStorage.setItem('customStore', JSON.stringify(customStore)) generateStoreList() } } else if (!ele.blank) { if (index ? (!myPlayer.playerObject.tails[ele.id]) : (!myPlayer.playerObject.skins[ele.id])) { childtmp = document.createElement("div") childtmp.className = "joinAlBtn" childtmp.style = "margin-top: 5px" childtmp.textContent = "Buy" childtmp.onclick = () => { unsafeWindow.storeBuy(ele.id, index) } tmp.appendChild(childtmp) childtmp = document.createElement("span") childtmp.className = "itemPrice" childtmp.textContent = ele.price tmp.appendChild(childtmp) } else if ((index ? myPlayer.playerObject.tailIndex : myPlayer.playerObject.skinIndex) == ele.id) { childtmp = document.createElement("div") childtmp.className = "joinAlBtn" childtmp.style = "margin-top: 5px" childtmp.textContent = "Unequip" childtmp.onclick = () => { unsafeWindow.storeEquip(0, index) } tmp.appendChild(childtmp) } else { childtmp = document.createElement("div") childtmp.className = "joinAlBtn" childtmp.style = "margin-top: 5px" childtmp.textContent = "Equip" childtmp.onclick = () => { unsafeWindow.storeEquip(ele.id, index) } tmp.appendChild(childtmp) } } }) if (customStoreButton.style.background == "red") { if (sortable != null) { sortable.destroy() } sortable = new Sortable.create(customStoreHolder, { animation: 150, onUpdate: event => { let arr = index ? customStore.accessories : customStore.hats if (event.newIndex >= arr.length) { var k = event.newIndex - arr.length + 1 while (k--) { arr.push(undefined) } } arr.splice(event.newIndex, 0, arr.splice(event.oldIndex, 1)[0]) localStorage.setItem('customStore', JSON.stringify(customStore)) } }) } else { if (sortable != null) { sortable.destroy() sortable = null } } } } const customStoreButton = document.createElement("div") customStoreButton.id = "customStoreButton" customStoreButton.className = "uiElement gameButton" customStoreButton.innerHTML = `<i class="material-icons" style="font-size:40px; vertical-align:middle"></i>` customStoreButton.onclick = () => { if (elementID("storeMenu").style.display != "block") { elementID("storeMenu").style.display = "block" elementID("allianceMenu").style.display = "none" elementID("chatBox").value = "" elementID("chatHolder").style.display = "none" generateStoreList() } else { elementID("storeMenu").style.display = "none" customStoreButton.style.background = null } } customStoreButton.oncontextmenu = event => { event.preventDefault() if (elementID("storeMenu").style.display != "block") { elementID("storeMenu").style.display = "block" elementID("allianceMenu").style.display = "none" elementID("chatBox").value = "" elementID("chatHolder").style.display = "none" if (customStoreButton.style.background != "red") { customStoreButton.style.background = "red" } generateStoreList() } else { elementID("storeMenu").style.display = "none" customStoreButton.style.background = null } } waitForElm("#storeButton").then(storeButton => { const style = document.createElement("style") style.innerHTML = ` #customStoreButton { right: 330px; } @media only screen and (max-width: 896px) { #customStoreButton { top: inherit; right: 60px; } } ` document.head.appendChild(style) storeButton.parentNode.insertBefore(customStoreButton, storeButton.nextSibling) storeButton.hidden = true }) waitForElm("#storeMenu > div:nth-child(1) > div:nth-child(1)").then(storeTab1 => { storeTab1.addEventListener("click", () => { currentStoreIndex = 0 generateStoreList() }) }) const addEdit = document.createElement("div") addEdit.className = "storeTab" addEdit.textContent = "Add Blank" addEdit.style.display = "none" addEdit.style.marginLeft = "10px" const reloadEdit = document.createElement("div") reloadEdit.className = "storeTab" reloadEdit.textContent = "Reload" reloadEdit.style.display = "none" reloadEdit.style.marginLeft = "10px" const importBut = document.createElement("div") importBut.className = "storeTab" importBut.textContent = "Import" importBut.style.marginLeft = "10px" const exportBut = document.createElement("div") exportBut.className = "storeTab" exportBut.textContent = "Export" exportBut.style.marginLeft = "10px" waitForElm("#storeMenu > div:nth-child(1) > div:nth-child(2)").then(storeTab2 => { storeTab2.addEventListener("click", () => { currentStoreIndex = 1 generateStoreList() }) storeTab2.parentNode.appendChild(addEdit) addEdit.onclick = () => { let arr = currentStoreIndex ? customStore.accessories : customStore.hats let id = Math.max(...arr.map(el => el.id)) + 1001 let min = customStoreHolder.getBoundingClientRect().top + 10 let top, index = 0 let childrens = customStoreHolder.childNodes for (var i = 0; i < childrens.length; i++) { top = Math.abs(childrens[i].getBoundingClientRect().top) if (top <= min) { index = i + 1 } } arr.splice(index, 0, { id: id, blank: true }) localStorage.setItem('customStore', JSON.stringify(customStore)) generateStoreList() } storeTab2.parentNode.appendChild(reloadEdit) reloadEdit.onclick = () => { let realStore = JSON.parse(localStorage.getItem('realStore')) currentStoreIndex ? customStore.accessories = realStore.accessories : customStore.hats = realStore.hats localStorage.setItem('customStore', JSON.stringify(customStore)) generateStoreList() } storeTab2.parentNode.appendChild(importBut) importBut.onclick = () => { const tmpEle = document.createElement("input") tmpEle.type = "file" tmpEle.style.display = "none" document.body.appendChild(tmpEle) tmpEle.addEventListener("change", async () => { let data = await new Response(tmpEle.files[0]).json() customStore = data localStorage.setItem('customStore', JSON.stringify(data)) tmpEle.remove() generateStoreList() }) tmpEle.click() } storeTab2.parentNode.appendChild(exportBut) exportBut.onclick = () => { let dataStr = JSON.stringify(customStore) let dataUri = 'data:application/jsoncharset=utf-8,' + encodeURIComponent(dataStr) let exportFileDefaultName = `customStore_${Date.now()}.json` let linkElement = document.createElement('a') linkElement.setAttribute('href', dataUri) linkElement.setAttribute('download', exportFileDefaultName) linkElement.click() } }) document.addEventListener("keydown", event => { if (event.code == "Escape") { customStoreButton.style.background = null } else if (event.code == "KeyB" && document.activeElement.tagName != "INPUT" && inGame) { if (elementID("storeMenu").style.display != "block") { elementID("storeMenu").style.display = "block" elementID("allianceMenu").style.display = "none" elementID("chatBox").value = "" elementID("chatHolder").style.display = "none" generateStoreList() } else { elementID("storeMenu").style.display = "none" customStoreButton.style.background = null } } }) })()
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址