MooMoo.io Reload Timer

Helps you determine the reload time of your weapon(s)

  1. // ==UserScript==
  2. // @name MooMoo.io Reload Timer
  3. // @description Helps you determine the reload time of your weapon(s)
  4. // @author KOOKY WARRIOR
  5. // @match *://*.moomoo.io/*
  6. // @icon https://moomoo.io/img/favicon.png?v=1
  7. // @require https://cdnjs.cloudflare.com/ajax/libs/msgpack-lite/0.1.26/msgpack.min.js
  8. // @require https://greasyfork.org/scripts/478839-moomoo-io-packet-code/code/MooMooio%20Packet%20Code.js
  9. // @run-at document-start
  10. // @grant unsafeWindow
  11. // @license MIT
  12. // @version 0.4.1
  13. // @namespace https://greasyfork.org/users/999838
  14. // ==/UserScript==
  15.  
  16. ;(async () => {
  17. unsafeWindow.reloadTimer = true
  18.  
  19. let weaponSpeed = [300, 400, 400, 300, 300, 700, 300, 100, 400, 600, 400, 0, 700, 230, 700, 1500]
  20. let weaponSrc = [
  21. "hammer_1",
  22. "axe_1",
  23. "great_axe_1",
  24. "sword_1",
  25. "samurai_1",
  26. "spear_1",
  27. "bat_1",
  28. "dagger_1",
  29. "stick_1",
  30. "bow_1",
  31. "great_hammer_1",
  32. "shield_1",
  33. "crossbow_1",
  34. "crossbow_2",
  35. "grab_1",
  36. "musket_1"
  37. ]
  38. var myPlayer,
  39. mySID,
  40. inGame = false,
  41. reloads = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  42. var now, delta, lastUpdate
  43. const reloadTimer1 = document.createElement("div")
  44. reloadTimer1.id = "reloadTimer1"
  45. reloadTimer1.className = "resourceDisplay"
  46. reloadTimer1.innerText = "0"
  47.  
  48. const reloadTimer2 = document.createElement("div")
  49. reloadTimer2.id = "reloadTimer2"
  50. reloadTimer2.className = "resourceDisplay"
  51. reloadTimer2.innerText = "-"
  52.  
  53. let init = false
  54. await new Promise(async (resolve) => {
  55. let { send } = WebSocket.prototype
  56.  
  57. WebSocket.prototype.send = function (...x) {
  58. send.apply(this, x)
  59. this.send = send
  60. if (!init) {
  61. init = true
  62. this.addEventListener("message", (e) => {
  63. if (!e.origin.includes("moomoo.io") && !unsafeWindow.privateServer) return
  64. const [packet, data] = msgpack.decode(new Uint8Array(e.data))
  65. switch (packet) {
  66. case PACKETCODE.RECEIVE.setupGame:
  67. inGame = true
  68. mySID = data[0]
  69. break
  70. case PACKETCODE.RECEIVE.killPlayer:
  71. inGame = false
  72. reloads = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  73. break
  74. case PACKETCODE.RECEIVE.gatherAnimation:
  75. if (data[0] == mySID) reloads[data[2]] = weaponSpeed[data[2]]
  76. break
  77. case PACKETCODE.RECEIVE.addProjectile:
  78. if ([1000, 1200, 1400].includes(data[3])) {
  79. let projectileID
  80. switch (data[5]) {
  81. case 0:
  82. projectileID = 9
  83. break
  84. case 2:
  85. projectileID = 12
  86. break
  87. case 3:
  88. projectileID = 13
  89. break
  90. case 5:
  91. projectileID = 15
  92. break
  93. default:
  94. projectileID = null
  95. }
  96. let x = data[0] - Math.cos(data[2]) * 35
  97. let y = data[1] - Math.sin(data[2]) * 35
  98. if (Math.sqrt((x -= myPlayer.x) * x + (y -= myPlayer.y) * y) <= 70) reloads[projectileID] = weaponSpeed[projectileID]
  99. }
  100. break
  101. }
  102. })
  103. }
  104.  
  105. resolve(this)
  106. }
  107. })
  108.  
  109. function updateReload() {
  110. now = Date.now()
  111. delta = now - lastUpdate
  112. lastUpdate = now
  113. if (inGame && myPlayer) {
  114. if (myPlayer.buildIndex == -1) {
  115. reloads[myPlayer.weaponIndex] = Math.max(0, reloads[myPlayer.weaponIndex] - delta)
  116. }
  117. if (myPlayer.weapons[0] != null) {
  118. reloadTimer1.style.backgroundImage = `url(../img/weapons/${weaponSrc[myPlayer.weapons[0]]}.png)`
  119. reloadTimer1.innerText = reloads[myPlayer.weapons[0]]
  120. }
  121. if (myPlayer.weapons[1] != null) {
  122. reloadTimer2.style.backgroundImage = `url(../img/weapons/${weaponSrc[myPlayer.weapons[1]]}.png)`
  123. reloadTimer2.style.backgroundColor = "rgba(0, 0, 0, 0.25)"
  124. reloadTimer2.innerText = reloads[myPlayer.weapons[1]]
  125. } else {
  126. reloadTimer2.style.backgroundImage = null
  127. reloadTimer2.style.backgroundColor = null
  128. reloadTimer2.innerText = "-"
  129. }
  130. }
  131. unsafeWindow.requestAnimationFrame(updateReload)
  132. }
  133. lastUpdate = Date.now()
  134. unsafeWindow.requestAnimationFrame(updateReload)
  135.  
  136. function waitForElm(selector) {
  137. return new Promise((resolve) => {
  138. if (document.querySelector(selector)) {
  139. return resolve(document.querySelector(selector))
  140. }
  141.  
  142. const observer = new MutationObserver((mutations) => {
  143. if (document.querySelector(selector)) {
  144. resolve(document.querySelector(selector))
  145. observer.disconnect()
  146. }
  147. })
  148.  
  149. observer.observe(document.body, {
  150. childList: true,
  151. subtree: true
  152. })
  153. })
  154. }
  155.  
  156. const symbol = Symbol("minimapCounter")
  157. Object.defineProperty(Object.prototype, "minimapCounter", {
  158. get() {
  159. return this[symbol]
  160. },
  161. set(value) {
  162. this[symbol] = value
  163. if (this.isPlayer === true && this.sid === mySID) {
  164. myPlayer = this
  165. }
  166. },
  167. configurable: true
  168. })
  169.  
  170. waitForElm("#topInfoHolder").then((topInfoHolder) => {
  171. const style = document.createElement("style")
  172. style.innerHTML = `
  173. #reloadTimer1 {
  174. right: 0px;
  175. margin-top: 65px;
  176. color: #fff;
  177. font-size: 28px;
  178. background-color: rgba(0, 0, 0, 0.25);
  179. -webkit-border-radius: 4px;
  180. -moz-border-radius: 4px;
  181. border-radius: 4px;
  182. }
  183.  
  184. #reloadTimer2 {
  185. right: 0px;
  186. margin-top: 120px;
  187. color: #fff;
  188. font-size: 28px;
  189. -webkit-border-radius: 4px;
  190. -moz-border-radius: 4px;
  191. border-radius: 4px;
  192. }
  193. `
  194. document.head.appendChild(style)
  195.  
  196. topInfoHolder.appendChild(reloadTimer1)
  197. topInfoHolder.appendChild(reloadTimer2)
  198. })
  199. })()