Your auto chat...

Create your own personal automated chat. To open the menu, click on the new button next to the chat button. To create a message, enter it in the input field where the timer is shown, then click on the "Create" button. To delete a message, click on the "Delete" button. You can change existing messages, just click on the text in them and change.

  1. // ==UserScript==
  2. // @name Your auto chat...
  3. // @namespace -
  4. // @version 0.2
  5. // @description Create your own personal automated chat. To open the menu, click on the new button next to the chat button. To create a message, enter it in the input field where the timer is shown, then click on the "Create" button. To delete a message, click on the "Delete" button. You can change existing messages, just click on the text in them and change.
  6. // @author Nudo#7346
  7. // @match *://moomoo.io/*
  8. // @match *://*.moomoo.io/*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=moomoo.io
  10. // @grant none
  11. // @license MIT
  12. // @run-at document-start
  13. // ==/UserScript==
  14.  
  15. // Shit code is our everything!
  16.  
  17. (function() {
  18. const Config = {}
  19.  
  20. Config.random = function(min, max) {
  21. return Math.floor(Math.random() * (max - min + 1)) + min
  22. }
  23.  
  24. Config.stopStupidProcesses = function(event) {
  25. if (!this.hasOwnProperty("socket")) {
  26. return void 0
  27. }
  28.  
  29. if (event.data.toLowerCase() === "e") {
  30. this.socket.send(new Uint8Array(Array.from(Config.msgpack.encode(["7", [1]]))))
  31. }
  32.  
  33. this.socket.send(new Uint8Array(Array.from(Config.msgpack.encode(["33", [null]]))))
  34. }
  35.  
  36. class Message {
  37. constructor(id, message, position) {
  38. this.id = id
  39. this.text = message
  40. this.position = position
  41. }
  42.  
  43. send() {
  44. if (!Config.hasOwnProperty("socket")) {
  45. return void 0
  46. }
  47.  
  48. const message = document.querySelector(`#storageInvInput[data-iid="${this.id}"]`).value
  49.  
  50. this.text = message
  51.  
  52. Config.messageManager.messages[this.id].text = this.text
  53.  
  54. window.localStorage.setItem("__srg", JSON.stringify(Config.messageManager.messages))
  55.  
  56. Config.socket.send(new Uint8Array(Array.from(Config.msgpack.encode(["ch", [message]]))))
  57. }
  58. }
  59.  
  60. class MessageManager {
  61. constructor() {
  62. this.messages = {}
  63. this.savedMessages = {}
  64. this.limit = 99
  65. this.lastMessage = Date.now()
  66. this.updateSpeed = 3000
  67. this.currentMessage = 0
  68. }
  69.  
  70. get newID() {
  71. return Config.random(1e9, 10e9)
  72. }
  73.  
  74. addSavedMessage() {
  75. this.savedMessages = window.localStorage.__srg
  76.  
  77. if (typeof this.savedMessages === 'undefined') {
  78. return void 0
  79. }
  80.  
  81. let messages = Object.values(JSON.parse(this.savedMessages))
  82. messages = messages.sort((a, b) => a.position - b.position)
  83.  
  84. for (const i in messages) {
  85. const message = messages[i]
  86.  
  87. this.add(message.text, message.id)
  88. }
  89. }
  90.  
  91. add(message, oldID) {
  92. const messages = Object.values(this.messages)
  93.  
  94. if (messages.length >= this.limit || message.match(/[а-яА-Я]/)) {
  95. return void 0
  96. }
  97.  
  98. const id = typeof oldID === 'undefined' ? this.newID : oldID
  99. const position = messages.length + 1
  100.  
  101. this.messages[id] = new Message(id, message, position)
  102.  
  103. Config.createMessageItem(id, message, position)
  104.  
  105. this.savedMessages = window.localStorage.__srg
  106.  
  107. window.localStorage.setItem("__srg", JSON.stringify(this.messages))
  108.  
  109. return this.messages[id]
  110. }
  111.  
  112. remove(id) {
  113. const position = this.messages[id].position - 1
  114. let messages = Object.values(this.messages)
  115.  
  116. for (let i = position; i < messages.length; i++) {
  117. messages = messages.sort((a, b) => a.position - b.position)
  118.  
  119. this.messages[messages[i].id].position -= 1
  120.  
  121. document.getElementById(`position-${messages[i].id}`).textContent = `${this.messages[messages[i].id].position}.`
  122. }
  123.  
  124. Config.removeMessageItem(id)
  125.  
  126. delete this.messages[id]
  127.  
  128. this.savedMessages = window.localStorage.__srg
  129.  
  130. window.localStorage.setItem("__srg", JSON.stringify(this.messages))
  131.  
  132. return this.messages
  133. }
  134.  
  135. clear(clearStorage) {
  136. this.messages = {}
  137.  
  138. const storageHolder = document.getElementById("storageHolder")
  139.  
  140. storageHolder.innerHTML = `
  141. <div class="storageItem">No Auto Message Yet</div>
  142. `
  143.  
  144. if (clearStorage) {
  145. window.localStorage.removeItem("__srg")
  146. }
  147.  
  148. return this.messages
  149. }
  150.  
  151. setUpdateSpeed(speed) {
  152. speed = speed[1]
  153.  
  154. if (!speed.length) {
  155. return void 0
  156. }
  157.  
  158. speed = parseInt(speed)
  159.  
  160. if (speed < 0) {
  161. speed = 0
  162. }
  163.  
  164. this.updateSpeed = speed
  165.  
  166. return this.updateSpeed
  167. }
  168.  
  169. init() {
  170. setInterval(() => {
  171. try {
  172. const storageInput = document.getElementById("storageInput")
  173. const storageButtonM = document.querySelector(".storageButtonM")
  174.  
  175. if (storageInput.value === "__srg:clear" || storageInput.value.startsWith("__srg:speed=") || storageInput.value.startsWith("__srg:sp=")) {
  176. storageButtonM.textContent = "Execute"
  177. } else {
  178. storageButtonM.textContent = "Create"
  179. }
  180.  
  181. if (!this.lastMessage || Date.now() - this.lastMessage >= this.updateSpeed) {
  182. let messages = Object.values(this.messages)
  183.  
  184. messages = messages.sort((a, b) => a.position - b.position)
  185.  
  186. this.lastMessage = Date.now()
  187.  
  188. if (!messages.length) {
  189. return void 0
  190. }
  191.  
  192. if (this.currentMessage >= messages.length) {
  193. this.currentMessage = 0
  194. }
  195.  
  196. messages[this.currentMessage].send()
  197.  
  198. this.currentMessage += 1
  199. } else {
  200. const storageInput = document.getElementById("storageInput")
  201.  
  202. storageInput.placeholder = `${this.updateSpeed - (Date.now() - this.lastMessage)}ms`
  203. }
  204. } catch {}
  205. })
  206. }
  207. }
  208.  
  209. Config.messageManager = new MessageManager()
  210.  
  211. Config.messageManager.init()
  212.  
  213. window.cfg = Config
  214.  
  215. window.addEventListener("load", () => {
  216. const gameUI = document.getElementById("gameUI")
  217. const html = `
  218. <div id="storageButton" class="uiElement gameButton">
  219. <i class="material-icons" style="font-size:40px;vertical-align:middle">post_add</i>
  220. </div>
  221.  
  222. <div id="storageMenu" style="display: none;">
  223. <div id="storageHolder">
  224. <div class="storageItem">No Auto Message Yet</div>
  225. </div>
  226. <div id="storageManager">
  227. <input type="text" id="storageInput" maxlength="30" placeholder="unique message">
  228. <div class="storageButtonM" style="width: 140px;">Create</div>
  229. </div>
  230. </div>
  231.  
  232. <style>
  233. .removeMsgBtn {
  234. float: right;
  235. font-size: 24px;
  236. text-align: right;
  237. cursor: pointer;
  238. color: #80eefc;
  239. }
  240.  
  241. .removeMsgBtn:hover {
  242. color: #72d3e0;
  243. }
  244.  
  245. .storageItem {
  246. font-size: 24px;
  247. color: #fff;
  248. padding: 5px;
  249. }
  250.  
  251. .storageButtonM {
  252. pointer-events: all;
  253. cursor: pointer;
  254. margin-top: 10px;
  255. font-size: 24px;
  256. color: #fff;
  257. padding: 5px;
  258. background-color: rgba(0, 0, 0, 0.25);
  259. -webkit-border-radius: 4px;
  260. -moz-border-radius: 4px;
  261. border-radius: 4px;
  262. text-align: center;
  263. display: inline-block;
  264. }
  265.  
  266. #storageInput {
  267. pointer-events: all;
  268. font-size: 24px;
  269. color: #fff;
  270. background-color: rgba(0, 0, 0, 0.25);
  271. -webkit-border-radius: 4px;
  272. -moz-border-radius: 4px;
  273. border-radius: 4px;
  274. padding: 5px;
  275. display: inline-block;
  276. outline: none;
  277. border-color: none;
  278. border: 0;
  279. -webkit-box-shadow: none;
  280. box-shadow: none;
  281. width: 200px;
  282. margin-right: 7px;
  283. }
  284.  
  285. #storageInvInput {
  286. pointer-events: all;
  287. font-size: 24px;
  288. color: rgba(255, 255, 255, 0.6);
  289. background-color: rgba(0, 0, 0, 0);
  290. outline: none;
  291. border-color: none;
  292. border: 0;
  293. -webkit-box-shadow: none;
  294. box-shadow: none;
  295. width: 184px;
  296. }
  297.  
  298. #storageHolder {
  299. pointer-events: all;
  300. height: 200px;
  301. max-height: calc(100vh - 260px);
  302. overflow-y: scroll;
  303. -webkit-overflow-scrolling: touch;
  304. width: 350px;
  305. display: inline-block;
  306. text-align: left;
  307. padding: 10px;
  308. background-color: rgba(0, 0, 0, 0.25);
  309. -webkit-border-radius: 4px;
  310. -moz-border-radius: 4px;
  311. border-radius: 4px;
  312. }
  313.  
  314. #storageMenu {
  315. display: none;
  316. width: 100%;
  317. position: absolute;
  318. text-align: center;
  319. top: 50%;
  320. transform: translateY(-50%);
  321. -ms-transform: translateY(-50%);
  322. -moz-transform: translateY(-50%);
  323. -webkit-transform: translateY(-50%);
  324. -o-transform: translateY(-50%);
  325. }
  326.  
  327. #storageButton {
  328. right: 450px;
  329. }
  330.  
  331. @media only screen and (max-width: 768px) {
  332. #storageButton {
  333. top: inherit;
  334. left: 60px;
  335. }
  336.  
  337. .storageItem, #storageInput, .storageButtonM, .removeMsgBtn, #storageInvInput {
  338. font-size: 18px;
  339. }
  340. }
  341. </style>
  342. `
  343.  
  344. gameUI.insertAdjacentHTML("beforeend", html)
  345.  
  346. const storageButton = document.getElementById("storageButton")
  347. const storageMenu = document.getElementById("storageMenu")
  348. const storageInput = document.getElementById("storageInput")
  349. const storageHolder = document.getElementById("storageHolder")
  350. const storageButtonM = document.querySelector(".storageButtonM")
  351. const gameActionBtns = ["allianceButton", "storeButton", "chatButton"]
  352. const gameActionMenus = ["chatHolder", "allianceMenu", "storeMenu"]
  353.  
  354. storageButton.addEventListener("click", () => {
  355. const action = {
  356. "block": "none",
  357. "none": "block"
  358. }
  359.  
  360. for (const menu of gameActionMenus) {
  361. document.getElementById(menu).style.display = "none"
  362. }
  363.  
  364. storageMenu.style.display = action[storageMenu.style.display]
  365. })
  366.  
  367. Config.removeMessageItem = function(id) {
  368. const removeMsgBtns = document.querySelectorAll(".removeMsgBtn")
  369.  
  370. for (const btn of removeMsgBtns) {
  371. if (btn.dataset.id === id.toString()) {
  372. btn.parentNode.remove()
  373. }
  374. }
  375.  
  376. if (removeMsgBtns.length === 1) {
  377. storageHolder.innerHTML = `
  378. <div class="storageItem">No Auto Message Yet</div>
  379. `
  380. }
  381. }
  382.  
  383. Config.createMessageItem = function(id, message, position) {
  384. const removeMsgBtns = document.querySelectorAll(".removeMsgBtn")
  385.  
  386. if (!removeMsgBtns.length) {
  387. storageHolder.innerHTML = ""
  388. }
  389.  
  390. const messagePosition = position
  391.  
  392. storageHolder.innerHTML += `
  393. <div class="storageItem" data-siid="${id}">
  394. <span id="position-${id}" style="color: rgba(255, 255, 255, 0.6)">${messagePosition}.</span>
  395. <input type="text" id="storageInvInput" value="${message}" maxlength="30" placeholder="3000ms" data-iid="${id}">
  396. <div class="removeMsgBtn" data-id="${id}">Remove</div>
  397. </div>
  398. `
  399.  
  400. const storageInvInputs = document.querySelectorAll("#storageInvInput")
  401.  
  402. for (const input of storageInvInputs) {
  403. input.addEventListener("input", (event) => {
  404. Config.stopStupidProcesses(event)
  405. })
  406. }
  407. }
  408.  
  409. storageButtonM.addEventListener("click", (event) => {
  410. let value = storageInput.value
  411.  
  412. if (value === "__srg:clear") {
  413. storageHolder.innerHTML = ""
  414. storageInput.value = ""
  415.  
  416. return Config.messageManager.clear(true)
  417. }
  418.  
  419. if (value.startsWith("__srg:speed=")) {
  420. const speed = value.split("=")
  421.  
  422. storageInput.value = ""
  423.  
  424. return Config.messageManager.setUpdateSpeed(speed)
  425. }
  426.  
  427. if (!value.length) {
  428. return void 0
  429. }
  430.  
  431. if (value.length >= Config.messageManager.limit) {
  432. value = value.slice(0, 30)
  433. }
  434.  
  435. storageInput.value = ""
  436.  
  437. Config.messageManager.add(value)
  438. })
  439.  
  440. storageHolder.addEventListener("click", (event) => {
  441. const target = event.target
  442.  
  443. if (target.className === "removeMsgBtn") {
  444. Config.messageManager.remove(target.dataset.id)
  445. }
  446. })
  447.  
  448. storageInput.addEventListener("input", (event) => {
  449. Config.stopStupidProcesses(event)
  450. })
  451.  
  452. document.addEventListener("keydown", (event) => {
  453. if (event.code === "Enter" || event.code === "Escape") {
  454. storageMenu.style.display = "none"
  455. }
  456. })
  457.  
  458. for (const btn of gameActionBtns) {
  459. document.getElementById(btn).addEventListener("click", (event) => {
  460. storageMenu.style.display = "none"
  461. })
  462. }
  463.  
  464. Config.messageManager.addSavedMessage()
  465. })
  466.  
  467. Config.msgpack = {}
  468.  
  469. Function.prototype.call = new Proxy(Function.prototype.call, {
  470. apply(target, _this, args) {
  471. const data = target.apply(_this, args)
  472.  
  473. if (args[1] && args[1].i) {
  474. const i = args[1].i
  475.  
  476. if (i === 9) {
  477. Config.msgpack.encode = args[0].encode
  478. }
  479.  
  480. if (i === 15) {
  481. Config.msgpack.decode = args[0].decode
  482. Function.prototype.call = target
  483. }
  484. }
  485.  
  486. return data
  487. }
  488. })
  489.  
  490. const set = Object.getOwnPropertyDescriptor(WebSocket.prototype, "onmessage").set;
  491. Object.defineProperty(WebSocket.prototype, "onmessage", {
  492. set(callback) {
  493. return set.call(this, new Proxy(callback, {
  494. apply(target, _this, args) {
  495. Config.socket = _this
  496.  
  497. return target.apply(_this, args)
  498. }
  499. }))
  500. }
  501. })
  502. })()