0% found this document useful (0 votes)
47 views22 pages

Custom

The document is a userscript for customizing the store in the game MooMoo.io, allowing players to edit their store items, change their order, and manage their collection. It includes features like exporting and importing customizations, as well as a detailed setup for handling game events related to alliances and player actions. The script is designed to enhance the gaming experience by providing additional customization options for players.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
47 views22 pages

Custom

The document is a userscript for customizing the store in the game MooMoo.io, allowing players to edit their store items, change their order, and manage their collection. It includes features like exporting and importing customizations, as well as a detailed setup for handling game events related to alliances and player actions. The script is designed to enhance the gaming experience by providing additional customization options for players.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 22

// ==UserScript==

// @name MooMoo.io Custom Store


// @description Customize store
// @author KOOKY WARRIOR
// @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
// @require
https://greasyfork.org/scripts/478839-moomoo-io-packet-code/code/MooMooio%20Packet
%20Code.js
// @run-at document-start
// @grant unsafeWindow
// @license MIT
// @version 1.1.1
// @namespace https://greasyfork.org/users/999838
// @downloadURL https://update.greasyfork.org/scripts/461745/MooMooio%20Custom
%20Store.user.js
// @updateURL https://update.greasyfork.org/scripts/461745/MooMooio%20Custom
%20Store.meta.js
// ==/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)
}
const myPlayer = {
sid: null,
tails: {},
skins: {},
tailIndex: 0,
skinIndex: 0,
team: null
}
var inGame = false
var alliances = []
var alliancePlayers = []
var totalAllianceEle = 0
var currentAllianceEle = 0
let init = false
await new Promise(async (resolve) => {
let { send } = WebSocket.prototype

WebSocket.prototype.send = function (...x) {


send.apply(this, x)
this.send = send
if (!init) {
init = true
this.addEventListener("message", (e) => {
if (!e.origin.includes("moomoo.io") && !
unsafeWindow.privateServer) return
const [packet, data] = msgpack.decode(new
Uint8Array(e.data))
switch (packet) {
case PACKETCODE.RECEIVE.updateStoreItems:
if (data[2]) {
if (!data[0]) {
myPlayer.tails[data[1]] = 1
} else {
myPlayer.tailIndex = data[1]
}
} else {
if (!data[0]) {
myPlayer.skins[data[1]] = 1
} else {
myPlayer.skinIndex = data[1]
}
}
if (elementID("storeMenu").style.display
== "block") {
generateStoreList()
}
break
case PACKETCODE.RECEIVE.setupGame:
myPlayer.sid = data[0]
inGame = true
break
case PACKETCODE.RECEIVE.killPlayer:
inGame = false
break
case PACKETCODE.RECEIVE.addAlliance:
alliances.push(data[0])
totalAllianceEle = myPlayer.team !=
null ? alliancePlayers.length / 2 : alliances.length
currentAllianceEle =
Math.min(totalAllianceEle - 5, currentAllianceEle + 5)
if
(elementID("allianceMenu").style.display == "block") {
showAllianceMenu()
}
break
case PACKETCODE.RECEIVE.setPlayerTeam:
myPlayer.team = data[0]
myPlayer.isOwner = data[1]
currentAllianceEle = 0
totalAllianceEle = myPlayer.team !=
null ? alliancePlayers.length / 2 : alliances.length
if
(elementID("allianceMenu").style.display == "block") {
showAllianceMenu()
}
break
case PACKETCODE.RECEIVE.setAlliancePlayers:
alliancePlayers = data[0]
totalAllianceEle = myPlayer.team !=
null ? alliancePlayers.length / 2 : alliances.length
currentAllianceEle =
Math.min(totalAllianceEle - 5, currentAllianceEle + 5)
if
(elementID("allianceMenu").style.display == "block") {
showAllianceMenu()
}
break
case PACKETCODE.RECEIVE.deleteAlliance:
for (var i = alliances.length - 1; i >=
0; i--) {
if (alliances[i].sid == data[0]) {
alliances.splice(i, 1)
break
}
}
totalAllianceEle = myPlayer.team !=
null ? alliancePlayers.length / 2 : alliances.length
currentAllianceEle =
Math.min(totalAllianceEle - 5, currentAllianceEle + 5)
if
(elementID("allianceMenu").style.display == "block") {
showAllianceMenu()
}
break
case PACKETCODE.RECEIVE.setInitData:
alliances = data[0].teams
totalAllianceEle = myPlayer.team !=
null ? alliancePlayers.length / 2 : alliances.length
break
}
})
}
resolve(this)
}
})

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"
const customStoreScrollBar = document.createElement("div")
customStoreScrollBar.id = "customStoreScrollBar"
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;
}
.storeItem {
font-size: 24px;
}
.hatPreview {
width: 45px;
height: 45px;
}
.joinAlBtn {
font-size: 24px;
}
.itemPrice {
font-size: 24px;
}
#customStoreScrollBar {
display: none;
position: absolute;
width: 3px;
background: white;
left: calc(50% + 210px - 3px);
border-radius: 10px;
}
`
document.head.appendChild(style)
storeHolder.parentNode.insertBefore(customStoreHolder,
storeHolder.nextSibling)
storeHolder.parentNode.insertBefore(customStoreScrollBar,
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
}
]
}
for (let i = 0; i < store.hats.length; ++i) {
if (store.hats[i].price <= 0) {
myPlayer.skins[store.hats[i].id] = 1
}
}
for (let i = 0; i < store.accessories.length; ++i) {
if (store.accessories[i].price <= 0) {
myPlayer.tails[store.accessories[i].id] = 1
}
}
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 totalShopEle = customStore.hats.length


var currentShopEle = 0
function updateScroll() {
if (customStoreButton.style.background == "red") return
const elements = document.querySelectorAll("#customStoreHolder
> .storeItem")
const storeArray = []
for (let i = 0; i < elements.length; i++) {
if (currentShopEle <= i && i < currentShopEle + 4) {
elements[i].style.display = null
storeArray.push(tmpArray[i].blank ? "blank" :
tmpArray[i].id)
} else {
elements[i].style.display = "none"
}
}

const elementHeight = 220 / elements.length


customStoreScrollBar.style.height = `${elementHeight * 4}px`
customStoreScrollBar.style.marginTop = `${elementHeight *
currentShopEle}px`
customStoreScrollBar.style.display = elements.length <= 4 ? "none" :
"block"
if (unsafeWindow.recorder) {
unsafeWindow.updateStoreData = [currentStoreIndex, storeArray,
elements.length, currentShopEle]
unsafeWindow.sendToLocal("addData", [
Date.now().toString(),
{ type: "updateStore", data: [currentStoreIndex,
storeArray, elements.length, currentShopEle] }
])
}
}
customStoreHolder.addEventListener("wheel", (event) => {
if (event.wheelDelta > 0) {
currentShopEle = Math.max(0, currentShopEle - 4)
} else {
currentShopEle = Math.min(totalShopEle - 4, currentShopEle + 4)
}
updateScroll()
})

var sortable = null,


tmpArray
function generateStoreList() {
if (inGame) {
while (customStoreHolder.hasChildNodes()) {
customStoreHolder.removeChild(customStoreHolder.lastChild)
}
var index = currentStoreIndex
tmpArray = index ? customStore.accessories : customStore.hats
totalShopEle = tmpArray.length
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"
customStoreHolder.style.overflowY =
customStoreButton.style.background == "red" ? null : "hidden"
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.tails[ele.id] : !
myPlayer.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.tailIndex :
myPlayer.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)
}
}
})
updateScroll()
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
currentShopEle = 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
currentShopEle = 0
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))
currentShopEle = 0
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()
currentShopEle = 0
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()
}
})

unsafeWindow.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
}
}
})

const customAllianceHolder = document.createElement("div")


customAllianceHolder.id = "customAllianceHolder"
const customAllianceScrollBar = document.createElement("div")
customAllianceScrollBar.id = "customAllianceScrollBar"
waitForElm("#allianceHolder").then((allianceHolder) => {
const style = document.createElement("style")
style.innerHTML = `
#customAllianceHolder {
pointer-events: all;
height: 200px;
max-height: calc(100vh - 260px);
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
width: 350px;
display: inline-block;
text-align: left;
padding: 10px;
background-color: rgba(0, 0, 0, 0.25);
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.allianceItem {
height: 30px;
font-size: 24px;
}
#allianceNoTribe {
height: 30px;
font-size: 24px;
padding: 5px;
color: #fff;
}
#customAllianceScrollBar {
display: none;
position: absolute;
width: 3px;
background: white;
left: calc(50% + 185px - 3px);
border-radius: 10px;
}
`
document.head.appendChild(style)
allianceHolder.parentNode.insertBefore(customAllianceHolder,
allianceHolder.nextSibling)
allianceHolder.parentNode.insertBefore(customAllianceScrollBar,
allianceHolder.nextSibling)
allianceHolder.style.display = "none"
})

customAllianceHolder.addEventListener("wheel", (event) => {


if (event.wheelDelta > 0) {
currentAllianceEle = Math.max(0, currentAllianceEle - 5)
} else {
currentAllianceEle = Math.min(totalAllianceEle - 5,
currentAllianceEle + 5)
}
updateAllianceScroll()
})
function updateAllianceScroll() {
const elements = document.querySelectorAll("#customAllianceHolder
> .allianceItem")
const allianceArray = []
var tmpi = 0
for (let i = 0; i < elements.length; i++) {
if (currentAllianceEle <= i && i < currentAllianceEle + 5) {
elements[i].style.display = null
allianceArray.push({
sid: myPlayer.team ? alliancePlayers[tmpi] : null,
text: myPlayer.team ? alliancePlayers[tmpi + 1] :
alliances[i]
})
} else {
elements[i].style.display = "none"
}

tmpi += 2
}

if (allianceArray.length <= 0 &&


document.getElementById("allianceNoTribe") == null) {
let tmp = document.createElement("div")
tmp.id = "allianceNoTribe"
tmp.textContent = "No Tribes Yet"
customAllianceHolder.appendChild(tmp)
}

const elementHeight = 220 / elements.length


customAllianceScrollBar.style.height = `${elementHeight * 5}px`
customAllianceScrollBar.style.marginTop = `${elementHeight *
currentAllianceEle}px`
customAllianceScrollBar.style.display = elements.length <= 5 ? "none" :
"block"

if (unsafeWindow.recorder) {
unsafeWindow.updateAllianceData = [myPlayer.team, allianceArray,
elements.length, currentAllianceEle]
unsafeWindow.sendToLocal("addData", [
Date.now().toString(),
{ type: "updateAlliance", data: [myPlayer.team,
allianceArray, elements.length, currentAllianceEle] }
])
}
}

waitForElm("#allianceButton").then((ele) => {
ele.addEventListener("click", () => {
showAllianceMenu()
})
})

function showAllianceMenu() {
if (inGame) {
if (unsafeWindow.recorder) {
unsafeWindow.sendToLocal("addData", [Date.now().toString(),
{ type: "changeInputText", data: ["allianceInput", ""] }])
}
while (customAllianceHolder.hasChildNodes()) {

customAllianceHolder.removeChild(customAllianceHolder.lastChild)
}
if (myPlayer.team) {
for (let i = 0; i < alliancePlayers.length; i += 2) {
let tmp = document.createElement("div")
tmp.id = "allianceItem" + alliancePlayers[i]
tmp.className = "allianceItem"
tmp.style = "color:" + (alliancePlayers[i] ==
myPlayer.sid ? "#fff" : "rgba(255,255,255,0.6)")
let tmp2 = document.createElement("span")
tmp2.innerText = alliancePlayers[i + 1]
tmp2.style.position = "absolute"
tmp.appendChild(tmp2)
customAllianceHolder.appendChild(tmp)

if (myPlayer.isOwner && alliancePlayers[i] !=


myPlayer.sid) {
let alliancePlayersArray = alliancePlayers
let childtmp = document.createElement("div")
childtmp.className = "joinAlBtn"
childtmp.textContent = "Kick"
childtmp.onclick = function () {

unsafeWindow.kickFromClan(alliancePlayersArray[i])
}
tmp.appendChild(childtmp)
}
}
} else if (alliances.length) {
for (let i = 0; i < alliances.length; ++i) {
let tmp = document.createElement("div")
tmp.id = "allianceItem" + alliances[i].owner
tmp.className = "allianceItem"
tmp.style = "color:" + (alliances[i].sid ==
myPlayer.team ? "#fff" : "rgba(255,255,255,0.6)")
let tmp2 = document.createElement("span")
tmp2.innerText = alliances[i].sid
tmp2.style.position = "absolute"
tmp.appendChild(tmp2)
customAllianceHolder.appendChild(tmp)

let childtmp = document.createElement("div")


childtmp.className = "joinAlBtn"
childtmp.textContent = "Join"
childtmp.onclick = function () {
unsafeWindow.sendJoin(i)
}
tmp.appendChild(childtmp)
}
}
updateAllianceScroll()
}
}
})()

You might also like