MooMoo.io Reload Timer

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

当前为 2023-09-16 提交的版本,查看 最新版本

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