SigMod Client (Macros)

The best mod you can find for Sigmally - Agar.io: Macros, Friends, tag system (minimap, chat), FPS boost, color mod, custom skins, AutoRespawn, save names, themes and more!

当前为 2024-03-11 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name SigMod Client (Macros)
  3. // @version 9
  4. // @description The best mod you can find for Sigmally - Agar.io: Macros, Friends, tag system (minimap, chat), FPS boost, color mod, custom skins, AutoRespawn, save names, themes and more!
  5. // @author Cursed
  6. // @match *://sigmally.com/*
  7. // @match *://beta.sigmally.com/*
  8. // @icon https://raw.githubusercontent.com/Sigmally/SigMod/main/images/sigmodclient2.gif
  9. // @run-at document-end
  10. // @license MIT
  11. // @namespace https://greasyfork.org/users/981958
  12. // ==/UserScript==
  13.  
  14. (function() {
  15. let version = 9;
  16. let cversion = 1.3;
  17. let storageName = "SigModClient-settings";
  18. let headerAnim = "https://app.czrsd.com/static/sigmodclient.gif";
  19.  
  20. 'use strict';
  21. let modSettings = localStorage.getItem(storageName);
  22. if (!modSettings) {
  23. modSettings = {
  24. keyBindings: {
  25. rapidFeed: "w",
  26. doubleSplit: "d",
  27. tripleSplit: "f",
  28. quadSplit: "g",
  29. freezePlayer: "s",
  30. verticalSplit: "t",
  31. doubleTrick: "",
  32. selfTrick: "",
  33. toggleMenu: "v",
  34. location: "y",
  35. toggleChat: "z",
  36. toggleNames: "",
  37. toggleSkins: "",
  38. toggleAutoRespawn: "",
  39. },
  40. freezeType: "press",
  41. m1: null,
  42. m2: null,
  43. mapColor: null,
  44. nameColor: null,
  45. gradientName: {
  46. enabled: false,
  47. color1: null,
  48. color2: null,
  49. },
  50. borderColor: null,
  51. foodColor: null,
  52. cellColor: null,
  53. mapImageURL: "",
  54. virusImage: "/assets/images/viruses/2.png",
  55. skinImage: {
  56. original: null,
  57. replaceImg: null,
  58. },
  59. Theme: "Dark",
  60. addedThemes: [],
  61. savedNames: [],
  62. AutoRespawn: false,
  63. tag: null,
  64. chatSettings: {
  65. limit: 100,
  66. bgColor: "#000000",
  67. chat_opacity: 0.4,
  68. compact: false,
  69. themeColor: "#8a25e5",
  70. showTime: true,
  71. showNameColors: true,
  72. showClientChat: false,
  73. showChatButtons: true,
  74. blurTag: false,
  75. locationText: "{pos}",
  76. },
  77. deathScreenPos: "center",
  78. fps: {
  79. fpsMode: false,
  80. hideFood: false,
  81. showNames: true,
  82. shortLongNames: false,
  83. removeOutlines: false,
  84. },
  85. removeShopPopup: false,
  86. playTimer: false,
  87. autoClaimCoins: false,
  88. authorized: false,
  89. };
  90. updateStorage();
  91. } else {
  92. modSettings = JSON.parse(modSettings);
  93. }
  94.  
  95. function updateStorage() {
  96. localStorage.setItem(storageName, JSON.stringify(modSettings));
  97. }
  98.  
  99. // for development
  100. let isDev = false;
  101. let port = 3001;
  102.  
  103. unsafeWindow.sigmod = {
  104. version,
  105. server_version: cversion,
  106. storageName,
  107. settings: modSettings,
  108. };
  109.  
  110. // websocket, user
  111. unsafeWindow.gameSettings = {
  112. serverURL: `eu0.sigmally.com/server`,
  113. serverProtocol: "https",
  114. };
  115.  
  116. // * helper functions * //
  117.  
  118. function parsetxt(val) {
  119. return /^(?:\{([^}]*)\})?([^]*)/.exec(val)[2].trim();
  120. }
  121.  
  122. async function wait(ms) {
  123. return new Promise(r => setTimeout(r, ms));
  124. }
  125.  
  126. // get user, auto claim coins
  127. const originalFetch = unsafeWindow.fetch;
  128. unsafeWindow.fetch = function(url, options) {
  129. if (url.includes('/server/auth')) {
  130. return originalFetch(url, options)
  131. .then(response => {
  132. return response.json().then(data => {
  133. if (!data.body.user) return;
  134. const claim = document.getElementById("free-chest-button");
  135. unsafeWindow.gameSettings.user = data.body.user;
  136. if (modSettings.autoClaimCoins && claim && claim.style.display !== "none") {
  137. setTimeout(() => {
  138. claim.click();
  139. }, 500);
  140. }
  141. return new Response(JSON.stringify(data), response);
  142. });
  143. });
  144. } else if (url.includes('v3')) {
  145. const token = JSON.parse(options.body).recaptchaV3Token;
  146. unsafeWindow.v3 = token;
  147. return originalFetch(url, options);
  148. }
  149. return originalFetch(url, options);
  150. };
  151.  
  152.  
  153. // hex color code to rgba values
  154. function hexToRgba(hex, alpha) {
  155. const r = parseInt(hex.substring(1, 3), 16);
  156. const g = parseInt(hex.substring(3, 5), 16);
  157. const b = parseInt(hex.substring(5, 7), 16);
  158. return `rgba(${r}, ${g}, ${b}, ${alpha})`;
  159. }
  160.  
  161. // rgba values to hex color code
  162. function RgbaToHex(code) {
  163. const rgbaValues = code.match(/\d+/g);
  164. const [r, g, b] = rgbaValues.slice(0, 3);
  165. return `#${Number(r).toString(16).padStart(2, '0')}${Number(g).toString(16).padStart(2, '0')}${Number(b).toString(16).padStart(2, '0')}`;
  166. }
  167.  
  168. // generate random string
  169. function rdmString(length) {
  170. return [...Array(length)].map(() => Math.random().toString(36).charAt(2)).join('');
  171. }
  172.  
  173. function menuClosed() {
  174. const menuWrapper = document.getElementById("menu-wrapper");
  175.  
  176. return menuWrapper.style.display === "none";
  177. }
  178.  
  179. function isDeath() {
  180. const __line2 = document.getElementById("__line2");
  181. return !__line2.classList.contains("line--hidden");
  182. }
  183.  
  184. function getGameMode() {
  185. const gameMode = document.getElementById("gamemode")
  186. const options = Object.values(gameMode.querySelectorAll("option"))
  187. const selectedOption = options.filter((option) => option.value === gameMode.value)[0]
  188. const serverName = selectedOption.textContent.split(" ")[0]
  189.  
  190. return serverName
  191. }
  192.  
  193. function bytesToHex(r, g, b) {
  194. return '#' + ((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1);
  195. }
  196.  
  197. // Function to convert a datetime stamp to a readable time
  198. function formatTime(timestamp) {
  199. if (!timestamp) return "";
  200. const numericTimestamp = Number(timestamp); // convert to int
  201. const date = new Date(numericTimestamp);
  202. const hours = date.getHours();
  203. const minutes = String(date.getMinutes()).padStart(2, '0');
  204. const ampm = hours >= 12 ? 'PM' : 'AM';
  205. const formattedHours = (hours % 12 || 12).toString().padStart(2, '0');
  206.  
  207. return `${formattedHours}:${minutes} ${ampm}`;
  208. }
  209.  
  210.  
  211. // Function to get the time difference from the current time
  212. function getTimeAgo(timestamp) {
  213. if (!timestamp) return "";
  214. const currentTime = new Date();
  215. const elapsedTime = currentTime - timestamp;
  216.  
  217. const seconds = Math.floor(elapsedTime / 1000);
  218. const minutes = Math.floor(seconds / 60);
  219. const hours = Math.floor(minutes / 60);
  220. const days = Math.floor(hours / 24);
  221. const years = Math.floor(days / 365);
  222.  
  223. if (years > 0) {
  224. return years === 1 ? "1 year ago" : `${years} years ago`;
  225. } else if (days > 0) {
  226. return days === 1 ? "1 day ago" : `${days} days ago`;
  227. } else if (hours > 0) {
  228. return hours === 1 ? "1 hour ago" : `${hours} hours ago`;
  229. } else if (minutes > 0) {
  230. return minutes === 1 ? "1 minute ago" : `${minutes} minutes ago`;
  231. } else {
  232. return seconds <= 1 ? "1s>" : `${seconds}s ago`;
  233. }
  234. }
  235.  
  236. function keypress(key, keycode) {
  237. const keyDownEvent = new KeyboardEvent("keydown", { key: key, code: keycode });
  238. const keyUpEvent = new KeyboardEvent("keyup", { key: key, code: keycode });
  239.  
  240. window.dispatchEvent(keyDownEvent);
  241. window.dispatchEvent(keyUpEvent);
  242. }
  243. function mousemove(sx, sy) {
  244. const mouseMoveEvent = new MouseEvent("mousemove", { clientX: sx, clientY: sy });
  245. const canvas = document.getElementById("canvas");
  246. canvas.dispatchEvent(mouseMoveEvent);
  247. }
  248.  
  249.  
  250. // EU server
  251. const coordinates = {};
  252. const gridSize = 4500;
  253. for (let i = 0; i < 5; i++) {
  254. for (let j = 0; j < 5; j++) {
  255. const label = String.fromCharCode(65 + i) + (j + 1);
  256.  
  257. const minX = -11000 + (i * gridSize);
  258. const minY = -11000 + (j * gridSize);
  259. const maxX = -6500 + (i * gridSize);
  260. const maxY = -6500 + (j * gridSize);
  261.  
  262. coordinates[label] = {
  263. min: {
  264. x: minX,
  265. y: minY
  266. },
  267. max: {
  268. x: maxX,
  269. y: maxY
  270. }
  271. };
  272. }
  273. }
  274.  
  275. // US1; US2; US3 servers
  276. const coordinates2 = {};
  277. const gridSize2 = 7000;
  278. for (let i = 0; i < 5; i++) {
  279. for (let j = 0; j < 5; j++) {
  280. const label = String.fromCharCode(65 + i) + (j + 1);
  281.  
  282. const minX = -17022 + (i * gridSize2);
  283. const minY = -17022 + (j * gridSize2);
  284. const maxX = -10000 + (i * gridSize2);
  285. const maxY = -10000 + (j * gridSize2);
  286.  
  287. coordinates2[label] = {
  288. min: {
  289. x: minX,
  290. y: minY
  291. },
  292. max: {
  293. x: maxX,
  294. y: maxY
  295. }
  296. };
  297. }
  298. }
  299.  
  300. let client = null;
  301. let handshake = false;
  302. const originalSend = WebSocket.prototype.send
  303. const C = new Uint8Array(256)
  304. const R = new Uint8Array(256)
  305.  
  306. class modClient {
  307. constructor() {
  308. this.ws = null;
  309. this.wsUrl = isDev ? `ws://localhost:${port}/ws` : "wss://app.czrsd.com/sigmodserver/ws";
  310. this.readyState = null;
  311.  
  312. this.id = Math.abs(~~(Math.random() * 9e10));
  313.  
  314. this.connect();
  315. }
  316.  
  317. connect() {
  318. this.ws = new WebSocket(this.wsUrl);
  319. this.ws.binaryType = "arraybuffer";
  320.  
  321. this.ws.addEventListener("open", this.onOpen.bind(this));
  322. this.ws.addEventListener("close", this.onClose.bind(this));
  323. this.ws.addEventListener("message", this.onMessage.bind(this));
  324. this.ws.addEventListener("error", this.onError.bind(this));
  325. }
  326. close() {
  327. if (this.ws) {
  328. this.ws.close();
  329. this.readyState = 3;
  330. }
  331. }
  332.  
  333. async onOpen(event) {
  334. console.log("WebSocket connection opened.");
  335.  
  336. this.readyState = 1;
  337.  
  338. await wait(500); // wait to load DOM
  339.  
  340. const tagElement = document.querySelector("#tag");
  341. const tagText = document.querySelector(".tagText");
  342.  
  343. this.send({
  344. type: "server-changed",
  345. content: getGameMode()
  346. });
  347. this.send({
  348. type: "version",
  349. content: cversion,
  350. });
  351. this.send({
  352. type: "update-nick",
  353. content: mods.nick,
  354. });
  355.  
  356. function getTagFromUrl() {
  357. const urlParams = new URLSearchParams(unsafeWindow.location.search);
  358. const tagValue = urlParams.get('tag');
  359.  
  360. return tagValue ? tagValue.replace(/\/$/, '') : null;
  361. }
  362.  
  363. const tagValue = getTagFromUrl();
  364.  
  365. if (tagValue !== null) {
  366. modSettings.tag = tagValue;
  367. updateStorage();
  368. tagElement.value = tagValue;
  369. tagText.innerText = `Tag: ${tagValue}`;
  370. this.send({
  371. type: "update-tag",
  372. content: modSettings.tag,
  373. });
  374. }
  375.  
  376. if (modSettings.tag && tagValue == null) {
  377. tagElement.value = modSettings.tag;
  378. tagText.innerText = `Tag: ${modSettings.tag}`;
  379. this.send({
  380. type: "update-tag",
  381. content: modSettings.tag,
  382. });
  383. }
  384. }
  385.  
  386. onClose(event) {
  387. this.readyState = 3;
  388. const message = document.createElement("div");
  389. message.classList.add("error-message_sigMod")
  390. message.innerHTML = `
  391. <img src="https://i.ibb.co/ftTwZP0/Error.png" width="38" draggable="false">
  392. <span class="text" style="color: #000; user-select: auto;">You Disconnected from the SigMod <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" target="_blank">WebSocket</a>. Error code: ${event.code}. Please refresh the page.</span>
  393. <div style="display: flex; flex-direction: column; gap: 5px;">
  394. <button class="btn" id="close-error-message_sigMod" style="color: #000;">X</button>
  395. <button class="btn" id="refresh-error-message_sigMod" style="align-self: start; color: #000;">↺</button>
  396. </div>
  397. `;
  398.  
  399. setTimeout(() => {
  400. message.style.right = "20px";
  401. }, 200)
  402.  
  403. document.querySelector(".body__inner").append(message)
  404.  
  405. const close = document.getElementById("close-error-message_sigMod");
  406. const refresh = document.getElementById("refresh-error-message_sigMod");
  407. close.addEventListener("click", () => {
  408. message.style.right = "-500px";
  409. setTimeout(() => {
  410. message.remove();
  411. }, 500)
  412. });
  413. refresh.addEventListener("click", () => {
  414. this.connect();
  415. message.style.right = "-500px";
  416. setTimeout(() => {
  417. message.remove();
  418. }, 500)
  419. });
  420. }
  421.  
  422. onMessage(event) {
  423. const data = new Uint8Array(event.data);
  424. const string = new TextDecoder().decode(data);
  425. const message = JSON.parse(string);
  426.  
  427. switch (message.type) {
  428. case "ping":
  429. mods.ping.end = Date.now();
  430. mods.ping.latency = mods.ping.end - mods.ping.start;
  431. document.getElementById("clientPing").innerHTML = `Client Ping: ${mods.ping.latency}ms`;
  432. break;
  433. case "minimap-data":
  434. mods.updData(message.content);
  435. break;
  436. case "chat-message":
  437. var content = message.content;
  438. if (content) {
  439. let { admin, mod, vip, name, message, color } = content;
  440.  
  441. if (admin) name = "[Owner] " + name;
  442. if (mod) name = "[Mod] " + name;
  443. if (vip) name = "[VIP] " + name;
  444. if (name == "") name = "Unnamed";
  445.  
  446. mods.updateChat({
  447. admin,
  448. mod,
  449. color,
  450. name,
  451. message: message,
  452. time: modSettings.chatSettings.showTime ? Date.now() : null,
  453. });
  454. }
  455. break;
  456. // server updated
  457. case "update-available":
  458. var modAlert = document.createElement("div");
  459. modAlert.classList.add("modAlert");
  460. modAlert.innerHTML = `
  461. <span>You are using an old mod version. Please update.</span>
  462. <div class="flex" style="align-items: center; gap: 5px;">
  463. <button id="updateMod" class="modButton" style="width: 100%">Update</button>
  464. </div>
  465. `;
  466. document.body.append(modAlert);
  467.  
  468. document.getElementById("updateMod").addEventListener("click", () => {
  469. window.open(message.content);
  470. modAlert.remove();
  471. });
  472. break;
  473. // Tournaments //
  474. case "tournament-preview":
  475. mods.showTournament(message.content);
  476. mods.tData = message.content;
  477. break;
  478. case "tournament-go":
  479. mods.startTournament(message.content);
  480. break;
  481. case "get-score":
  482. mods.getScore(message.content);
  483. break;
  484. case "user-died":
  485. var { dead, max } = message.content;
  486. document.getElementById("usersDead").textContent = `(${dead}/${max})`;
  487. break;
  488. case "round-end":
  489. mods.roundEnd(message.content);
  490. break;
  491. case "round-ready":
  492. var text = document.getElementById("round-ready");
  493. text.textContent = `Ready (${message.content.ready}/${message.content.max})`;
  494. break;
  495. case "next-round":
  496. mods.nextRound(message.content);
  497. break;
  498. case "tournament-end":
  499. mods.endTournament(message.content);
  500. break;
  501. case "stob":
  502. var { u, a, o } = message.content;
  503. mods.a(u, a, o);
  504. break;
  505. case "stobs":
  506. mods.a();
  507. break;
  508. case "pos":
  509. mods.a(message.content);
  510. break;
  511. default: {
  512. console.error("unknown message type:", message.type);
  513. }
  514. }
  515. }
  516.  
  517. onError(event) {
  518. console.error("WebSocket error. More details: ", event);
  519. }
  520.  
  521. send(data) {
  522. if (!data) return;
  523. const string = JSON.stringify(data);
  524.  
  525. const encoder = new TextEncoder();
  526. const binaryData = encoder.encode(string);
  527.  
  528. this.ws.send(binaryData);
  529. }
  530. }
  531.  
  532. function Reader(view, offset, littleEndian) {
  533. this._e = littleEndian;
  534. if (view) this.repurpose(view, offset);
  535. }
  536.  
  537. Reader.prototype = {
  538. reader: true,
  539. repurpose: function (view, offset) {
  540. this.view = view;
  541. this._o = offset || 0;
  542. },
  543. getUint8: function () {
  544. return this.view.getUint8(this._o++, this._e);
  545. },
  546. getInt8: function () {
  547. return this.view.getInt8(this._o++, this._e);
  548. },
  549. getUint16: function () {
  550. return this.view.getUint16((this._o += 2) - 2, this._e);
  551. },
  552. getInt16: function () {
  553. return this.view.getInt16((this._o += 2) - 2, this._e);
  554. },
  555. getUint32: function () {
  556. return this.view.getUint32((this._o += 4) - 4, this._e);
  557. },
  558. getInt32: function () {
  559. return this.view.getInt32((this._o += 4) - 4, this._e);
  560. },
  561. getFloat32: function () {
  562. return this.view.getFloat32((this._o += 4) - 4, this._e);
  563. },
  564. getFloat64: function () {
  565. return this.view.getFloat64((this._o += 8) - 8, this._e);
  566. },
  567. getStringUTF8: function (decode = true) {
  568. let bytes = [];
  569. let b;
  570. while ((b = this.view.getUint8(this._o++)) !== 0)
  571. bytes.push(b);
  572.  
  573. let uint8Array = new Uint8Array(bytes);
  574. let decoder = new TextDecoder('utf-8');
  575. let s = decoder.decode(uint8Array);
  576.  
  577. return decode ? s : uint8Array;
  578. },
  579.  
  580.  
  581. raw: function (len = 0) {
  582. const buf = this.view.buffer.slice(this._o, this._o + len);
  583. this._o += len;
  584. return buf;
  585. },
  586. };
  587.  
  588. const __buf = new DataView(new ArrayBuffer(8))
  589. function Writer(littleEndian) {
  590. this._e = littleEndian;
  591. this.reset();
  592. return this;
  593. }
  594.  
  595. Writer.prototype = {
  596. writer: true,
  597. reset: function (littleEndian) {
  598. this._b = [];
  599. this._o = 0;
  600. },
  601. setUint8: function (a) {
  602. if (a >= 0 && a < 256) this._b.push(a);
  603. return this;
  604. },
  605. setInt8: function (a) {
  606. if (a >= -128 && a < 128) this._b.push(a);
  607. return this;
  608. },
  609. setUint16: function (a) {
  610. __buf.setUint16(0, a, this._e);
  611. this._move(2);
  612. return this;
  613. },
  614. setInt16: function (a) {
  615. __buf.setInt16(0, a, this._e);
  616. this._move(2);
  617. return this;
  618. },
  619. setUint32: function (a) {
  620. __buf.setUint32(0, a, this._e);
  621. this._move(4);
  622. return this;
  623. },
  624. setInt32: function (a) {
  625. __buf.setInt32(0, a, this._e);
  626. this._move(4);
  627. return this;
  628. },
  629. setFloat32: function (a) {
  630. __buf.setFloat32(0, a, this._e);
  631. this._move(4);
  632. return this;
  633. },
  634. setFloat64: function (a) {
  635. __buf.setFloat64(0, a, this._e);
  636. this._move(8);
  637. return this;
  638. },
  639. _move: function (b) {
  640. for (let i = 0; i < b; i++) this._b.push(__buf.getUint8(i));
  641. },
  642. setStringUTF8: function (s) {
  643. const bytesStr = unescape(encodeURIComponent(s));
  644. for (let i = 0, l = bytesStr.length; i < l; i++)
  645. this._b.push(bytesStr.charCodeAt(i));
  646. this._b.push(0);
  647. return this;
  648. },
  649. build: function () {
  650. return new Uint8Array(this._b);
  651. },
  652. };
  653.  
  654. setTimeout(() => {
  655. const gameSettings = document.querySelector(".checkbox-grid");
  656. gameSettings.innerHTML += `
  657. <li>
  658. <div class="pretty p-svg p-round p-smooth">
  659. <input type="checkbox" id="showNames">
  660. <div class="state p-success">
  661. <svg class="svg svg-icon" viewBox="0 0 20 20">
  662. <path d="M7.629,14.566c0.125,0.125,0.291,0.188,0.456,0.188c0.164,0,0.329-0.062,0.456-0.188l8.219-8.221c0.252-0.252,0.252-0.659,0-0.911c-0.252-0.252-0.659-0.252-0.911,0l-7.764,7.763L4.152,9.267c-0.252-0.251-0.66-0.251-0.911,0c-0.252,0.252-0.252,0.66,0,0.911L7.629,14.566z" style="stroke: white;fill:white;"></path>
  663. </svg>
  664. <label>Names</label>
  665. </div>
  666. </div>
  667. </li>
  668. <li>
  669. <div class="pretty p-svg p-round p-smooth">
  670. <input type="checkbox" id="showSkins">
  671. <div class="state p-success">
  672. <svg class="svg svg-icon" viewBox="0 0 20 20">
  673. <path d="M7.629,14.566c0.125,0.125,0.291,0.188,0.456,0.188c0.164,0,0.329-0.062,0.456-0.188l8.219-8.221c0.252-0.252,0.252-0.659,0-0.911c-0.252-0.252-0.659-0.252-0.911,0l-7.764,7.763L4.152,9.267c-0.252-0.251-0.66-0.251-0.911,0c-0.252,0.252-0.252,0.66,0,0.911L7.629,14.566z" style="stroke: white;fill:white;"></path>
  674. </svg>
  675. <label>Skins</label>
  676. </div>
  677. </div>
  678. </li>
  679. <li>
  680. <div class="pretty p-svg p-round p-smooth">
  681. <input type="checkbox" id="autoRespawn">
  682. <div class="state p-success">
  683. <svg class="svg svg-icon" viewBox="0 0 20 20">
  684. <path d="M7.629,14.566c0.125,0.125,0.291,0.188,0.456,0.188c0.164,0,0.329-0.062,0.456-0.188l8.219-8.221c0.252-0.252,0.252-0.659,0-0.911c-0.252-0.252-0.659-0.252-0.911,0l-7.764,7.763L4.152,9.267c-0.252-0.251-0.66-0.251-0.911,0c-0.252,0.252-0.252,0.66,0,0.911L7.629,14.566z" style="stroke: white;fill:white;"></path>
  685. </svg>
  686. <label>Auto Respawn</label>
  687. </div>
  688. </div>
  689. </li>
  690. <li>
  691. <div class="pretty p-svg p-round p-smooth">
  692. <input type="checkbox" id="removeShopPopup">
  693. <div class="state p-success">
  694. <svg class="svg svg-icon" viewBox="0 0 20 20">
  695. <path d="M7.629,14.566c0.125,0.125,0.291,0.188,0.456,0.188c0.164,0,0.329-0.062,0.456-0.188l8.219-8.221c0.252-0.252,0.252-0.659,0-0.911c-0.252-0.252-0.659-0.252-0.911,0l-7.764,7.763L4.152,9.267c-0.252-0.251-0.66-0.251-0.911,0c-0.252,0.252-0.252,0.66,0,0.911L7.629,14.566z" style="stroke: white;fill:white;"></path>
  696. </svg>
  697. <label>Remove shop popup</label>
  698. </div>
  699. </div>
  700. </li>
  701. <li>
  702. <div class="pretty p-svg p-round p-smooth">
  703. <input type="checkbox" id="autoClaimCoins">
  704. <div class="state p-success">
  705. <svg class="svg svg-icon" viewBox="0 0 20 20">
  706. <path d="M7.629,14.566c0.125,0.125,0.291,0.188,0.456,0.188c0.164,0,0.329-0.062,0.456-0.188l8.219-8.221c0.252-0.252,0.252-0.659,0-0.911c-0.252-0.252-0.659-0.252-0.911,0l-7.764,7.763L4.152,9.267c-0.252-0.251-0.66-0.251-0.911,0c-0.252,0.252-0.252,0.66,0,0.911L7.629,14.566z" style="stroke: white;fill:white;"></path>
  707. </svg>
  708. <label>Auto claim coins</label>
  709. </div>
  710. </div>
  711. </li>
  712. <li>
  713. <div class="pretty p-svg p-round p-smooth">
  714. <input type="checkbox" id="showPosition">
  715. <div class="state p-success">
  716. <svg class="svg svg-icon" viewBox="0 0 20 20">
  717. <path d="M7.629,14.566c0.125,0.125,0.291,0.188,0.456,0.188c0.164,0,0.329-0.062,0.456-0.188l8.219-8.221c0.252-0.252,0.252-0.659,0-0.911c-0.252-0.252-0.659-0.252-0.911,0l-7.764,7.763L4.152,9.267c-0.252-0.251-0.66-0.251-0.911,0c-0.252,0.252-0.252,0.66,0,0.911L7.629,14.566z" style="stroke: white;fill:white;"></path>
  718. </svg>
  719. <label>Position</label>
  720. </div>
  721. </div>
  722. </li>
  723. `;
  724.  
  725. let autoRespawn = document.getElementById("autoRespawn");
  726. let autoRespawnEnabled = false;
  727. autoRespawn.addEventListener("change", () => {
  728. if(!autoRespawnEnabled) {
  729. modSettings.AutoRespawn = true;
  730. updateStorage();
  731. autoRespawnEnabled = true;
  732. } else {
  733. modSettings.AutoRespawn = false;
  734. updateStorage();
  735. autoRespawnEnabled = false;
  736. }
  737. });
  738.  
  739. if(modSettings.AutoRespawn) {
  740. autoRespawn.checked = true;
  741. autoRespawnEnabled = true;
  742. }
  743. });
  744.  
  745. const getEmojis = async () => {
  746. const response = await fetch("https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json");
  747. const emojis = await response.json();
  748.  
  749. // Add more emojis if u want:
  750. emojis.push(
  751. {
  752. "emoji": "❤",
  753. "description": "Default heart",
  754. "category": "Smileys & Emotion",
  755. "tags": ["heart", "love"],
  756. },
  757. {
  758. "emoji": "🧡",
  759. "description": "Orange heart",
  760. "category": "Smileys & Emotion",
  761. "tags": ["heart", "love"],
  762. },
  763. {
  764. "emoji": "💛",
  765. "description": "Yellow heart",
  766. "category": "Smileys & Emotion",
  767. "tags": ["heart", "love"],
  768. },
  769. {
  770. "emoji": "💚",
  771. "description": "Green heart",
  772. "category": "Smileys & Emotion",
  773. "tags": ["heart", "love"],
  774. },
  775. {
  776. "emoji": "💙",
  777. "description": "Blue heart",
  778. "category": "Smileys & Emotion",
  779. "tags": ["heart", "love"],
  780. },
  781. {
  782. "emoji": "💜",
  783. "description": "Purple heart",
  784. "category": "Smileys & Emotion",
  785. "tags": ["heart", "love"],
  786. },
  787. {
  788. "emoji": "🤎",
  789. "description": "Brown heart",
  790. "category": "Smileys & Emotion",
  791. "tags": ["heart", "love"],
  792. },
  793. {
  794. "emoji": "🖤",
  795. "description": "Black heart",
  796. "category": "Smileys & Emotion",
  797. "tags": ["heart", "love"],
  798. },
  799. );
  800.  
  801. return emojis;
  802. };
  803.  
  804. let activeCellY = null;
  805. let activeCellX = null;
  806. let _getScore = false;
  807. let lastScore = 0;
  808. let lastPos = {};
  809. let lastLogTime = 0;
  810. let dead = false;
  811. let minimapclear = false;
  812. let stoppos = false;
  813. let replacementVirus = null;
  814. let replacementSkin = null;
  815.  
  816. function mod() {
  817. this.Username = "Guest";
  818. this.nick = null;
  819. this.profile = {};
  820. this.friends_settings = {};
  821. this.friend_names = new Set();
  822. this.scrollHandler = null;
  823.  
  824. this.splitKey = {
  825. keyCode: 32,
  826. code: "Space",
  827. cancelable: true,
  828. composed: true,
  829. isTrusted: true,
  830. which: 32,
  831. }
  832.  
  833. this.ping = {
  834. latency: NaN,
  835. intervalId: null,
  836. start: null,
  837. end: null,
  838. }
  839.  
  840. this.scrolling = false;
  841. this.onContext = false;
  842. this.mouseDown = false;
  843.  
  844. this.mutedUsers = [];
  845. this.miniMapData = [];
  846. this.tData = {};
  847. this.border = {};
  848. this.c = new Set();
  849.  
  850. this.appRoutes = {
  851. user: isDev ? `http://localhost:${port}/sigmod/user` : 'https://app.czrsd.com/sigmodserver/user',
  852. badge: isDev ? `http://localhost:${port}/sigmod/badge` : "https://app.czrsd.com/sigmodserver/badge",
  853. discordLogin: isDev ? `http://localhost:${port}/sigmod/discord/login/` : "https://app.czrsd.com/sigmodserver/discord/login/",
  854. auth: isDev ? `http://localhost:${port}/sigmod/auth` : `https://app.czrsd.com/sigmodserver/auth`,
  855. users: isDev ? `http://localhost:${port}/sigmod/users` : `https://app.czrsd.com/sigmodserver/users`,
  856. request: isDev ? `http://localhost:${port}/sigmod/request` : `https://app.czrsd.com/sigmodserver/request`,
  857. profile: (id) => isDev ? `http://localhost:${port}/sigmod/profile/${id}` : `https://app.czrsd.com/sigmodserver/profile/${id}`,
  858. myRequests: isDev ? `http://localhost:${port}/sigmod/me/requests` : `https://app.czrsd.com/sigmodserver/me/requests`,
  859. handleRequest: isDev ? `http://localhost:${port}/sigmod/me/handle` : `https://app.czrsd.com/sigmodserver/me/handle`,
  860. settings: isDev ? `http://localhost:${port}/sigmod/me/settings` : `https://app.czrsd.com/sigmodserver/me/settings`,
  861. logout: isDev ? `http://localhost:${port}/sigmod/logout` : `https://app.czrsd.com/sigmodserver/logout`,
  862. imgUpload: isDev ? `http://localhost:${port}/sigmod/me/upload` : `https://app.czrsd.com/sigmodserver/me/upload`,
  863. editProfile: isDev ? `http://localhost:${port}/sigmod/me/edit` : `https://app.czrsd.com/sigmodserver/me/edit`,
  864. delProfile: isDev ? `http://localhost:${port}/sigmod/me/remove` : `https://app.czrsd.com/sigmodserver/me/remove`,
  865. updateSettings: isDev ? `http://localhost:${port}/sigmod/me/update-settings` : `https://app.czrsd.com/sigmodserver/me/update-settings`,
  866. feedback: isDev ? `http://localhost:${port}/sigmod/feedback` : `https://app.czrsd.com/sigmodserver/feedback`
  867. };
  868.  
  869. this.load();
  870. }
  871.  
  872. mod.prototype = {
  873. get style() {
  874. return `
  875. :root {
  876. --default-mod-color: #2E2D80;
  877. }
  878. .mod_menu * {
  879. margin: 0;
  880. padding: 0;
  881. font-family: 'Ubuntu';
  882. box-sizing: border-box;
  883. }
  884.  
  885. .mod_menu {
  886. position: absolute;
  887. top: 0;
  888. left: 0;
  889. width: 100%;
  890. height: 100vh;
  891. background: rgba(0, 0, 0, .6);
  892. z-index: 999999;
  893. display: flex;
  894. justify-content: center;
  895. align-items: center;
  896. color: #fff;
  897. transition: all .3s ease;
  898. }
  899.  
  900. .mod_menu_wrapper {
  901. position: relative;
  902. display: flex;
  903. flex-direction: column;
  904. width: 700px;
  905. height: 500px;
  906. background: #111;
  907. border-radius: 12px;
  908. overflow: hidden;
  909. box-shadow: 0 5px 10px #000;
  910. }
  911.  
  912. .mod_menu_header {
  913. display: flex;
  914. width: 100%;
  915. position: relative;
  916. height: 60px;
  917. }
  918.  
  919. .mod_menu_header .header_img {
  920. width: 100%;
  921. height: 60px;
  922. object-fit: cover;
  923. object-position: center;
  924. position: absolute;
  925. }
  926.  
  927. .mod_menu_header button {
  928. display: flex;
  929. justify-content: center;
  930. align-items: center;
  931. position: absolute;
  932. right: 10px;
  933. top: 30px;
  934. background: rgba(11, 11, 11, .7);
  935. width: 42px;
  936. height: 42px;
  937. font-size: 16px;
  938. transform: translateY(-50%);
  939. }
  940.  
  941. .mod_menu_header button:hover {
  942. background: rgba(11, 11, 11, .5);
  943. }
  944.  
  945. .mod_menu_inner {
  946. display: flex;
  947. }
  948.  
  949. .mod_menu_navbar {
  950. display: flex;
  951. flex-direction: column;
  952. gap: 10px;
  953. min-width: 132px;
  954. padding: 10px;
  955. background: #181818;
  956. height: 440px;
  957. }
  958.  
  959. .mod_nav_btn, .modButton-black {
  960. display: flex;
  961. justify-content: space-evenly;
  962. align-items: center;
  963. padding: 5px;
  964. background: #050505;
  965. border-radius: 8px;
  966. font-size: 16px;
  967. border: 1px solid transparent;
  968. outline: none;
  969. width: 100%;
  970. transition: all .3s ease;
  971. }
  972. label.modButton-black {
  973. font-weight: 400;
  974. cursor: pointer;
  975. }
  976.  
  977. .mod_nav_btn:nth-child(8) {
  978. margin-top: auto;
  979. }
  980.  
  981. .mod_selected {
  982. border: 1px solid rgba(89, 89, 89, .9);
  983. }
  984.  
  985. .mod_nav_btn img {
  986. width: 22px;
  987. }
  988.  
  989. .mod_menu_content {
  990. width: 100%;
  991. padding: 10px;
  992. }
  993.  
  994. .mod_tab {
  995. width: 100%;
  996. display: flex;
  997. flex-direction: column;
  998. gap: 5px;
  999. overflow-y: auto;
  1000. overflow-x: hidden;
  1001. max-height: 420px;
  1002. opacity: 1;
  1003. transition: all .2s ease;
  1004. }
  1005.  
  1006. .text-center {
  1007. text-align: center;
  1008. }
  1009. .f-big {
  1010. font-size: 18px;
  1011. }
  1012.  
  1013. .modColItems {
  1014. display: flex;
  1015. flex-direction: column;
  1016. align-items: center;
  1017. gap: 15px;
  1018. width: 100%;
  1019. }
  1020.  
  1021. .modRowItems {
  1022. display: flex;
  1023. justify-content: center;
  1024. align-items: center;
  1025. background: #050505;
  1026. gap: 58px;
  1027. border-radius: 0.5rem;
  1028. padding: 10px;
  1029. width: 100%;
  1030. }
  1031.  
  1032. .modSlider {
  1033. -webkit-appearance: none;
  1034. height: 22px;
  1035. background: transparent;
  1036. cursor: pointer;
  1037. width: 100%;
  1038. }
  1039.  
  1040. .modSlider::-webkit-slider-runnable-track {
  1041. -webkit-appearance: none;
  1042. background: #542499;
  1043. height: 4px;
  1044. border-radius: 6px;
  1045. }
  1046. .modSlider::-webkit-slider-thumb {
  1047. appearance: none;
  1048. background: #6B32BD;
  1049. height: 16px;
  1050. width: 16px;
  1051. position: relative;
  1052. top: -5px;
  1053. border-radius: 50%;
  1054. }
  1055.  
  1056. input:focus, select:focus, button:focus{
  1057. outline: none;
  1058. }
  1059. .flex {
  1060. display: flex;
  1061. }
  1062. .centerX {
  1063. display: flex;
  1064. justify-content: center;
  1065. }
  1066. .centerY {
  1067. display: flex;
  1068. align-items: center;
  1069. }
  1070. .centerXY {
  1071. display: flex;
  1072. align-items: center;
  1073. justify-content: center
  1074. }
  1075. .f-column {
  1076. display: flex;
  1077. flex-direction: column;
  1078. }
  1079. .macros_wrapper {
  1080. display: flex;
  1081. width: 100%;
  1082. justify-content: center;
  1083. flex-direction: column;
  1084. gap: 10px;
  1085. background: #050505;
  1086. padding: 10px;
  1087. border-radius: 0.75rem;
  1088. }
  1089. .macro_grid {
  1090. display: grid;
  1091. grid-template-columns: 1.2fr 1.1fr;
  1092. gap: 5px;
  1093. }
  1094. .g-2 {
  1095. gap: 2px;
  1096. }
  1097. .g-5 {
  1098. gap: 5px;
  1099. }
  1100. .g-10 {
  1101. gap: 10px;
  1102. }
  1103. .p-2 {
  1104. padding: 2px;
  1105. }
  1106. .p-5 {
  1107. padding: 5px;
  1108. }
  1109. .p-10 {
  1110. padding: 10px;
  1111. }
  1112. .macrosContainer {
  1113. display: flex;
  1114. width: 100%;
  1115. justify-content: center;
  1116. align-items: center;
  1117. gap: 20px;
  1118. }
  1119. .macroRow {
  1120. background: #121212;
  1121. border-radius: 5px;
  1122. padding: 7px;
  1123. display: flex;
  1124. justify-content: space-between;
  1125. align-items: center;
  1126. gap: 10px;
  1127. }
  1128. .keybinding {
  1129. border-radius: 5px;
  1130. background: #242424;
  1131. border: none;
  1132. color: #fff;
  1133. padding: 2px 5px;
  1134. max-width: 50px;
  1135. font-weight: 500;
  1136. text-align: center;
  1137. }
  1138. .hidden {
  1139. display: none;
  1140. }
  1141. .SettingsTitle{
  1142. font-size: 32px;
  1143. color: #EEE;
  1144. margin-left: 10px;
  1145. }
  1146. .CloseBtn{
  1147. width: 46px;
  1148. background-color: transparent;
  1149. }
  1150. .select-btn {
  1151. padding: 15px 20px;
  1152. background: #222;
  1153. border-radius: 2px;
  1154. position: relative;
  1155. }
  1156.  
  1157. .select-btn:active {
  1158. scale: 0.95
  1159. }
  1160.  
  1161. .select-btn::before {
  1162. content: "...";
  1163. font-size: 20px;
  1164. color: #fff;
  1165. position: absolute;
  1166. top: 50%;
  1167. left: 50%;
  1168. transform: translate(-50%, -50%);
  1169. }
  1170. .text {
  1171. user-select: none;
  1172. font-weight: 500;
  1173. text-align: left;
  1174. }
  1175. .modButton {
  1176. background-color: #333;
  1177. border-radius: 5px;
  1178. color: #fff;
  1179. transition: all .3s;
  1180. outline: none;
  1181. padding: 5px;
  1182. font-size: 13px;
  1183. border: none;
  1184. }
  1185. .modButton:hover {
  1186. background-color: #222
  1187. }
  1188. .modInput {
  1189. background-color: #111;
  1190. border: none;
  1191. border-radius: 5px;
  1192. position: relative;
  1193. border-top-right-radius: 4px;
  1194. border-top-left-radius: 4px;
  1195. font-weight: 500;
  1196. padding: 5px;
  1197. color: #fff;
  1198. }
  1199.  
  1200. .modCheckbox input[type="checkbox"] {
  1201. display: none;
  1202. visibility: hidden;
  1203. }
  1204. .modCheckbox label {
  1205. display: inline-block;
  1206. }
  1207.  
  1208. .modCheckbox .cbx {
  1209. position: relative;
  1210. top: 1px;
  1211. width: 17px;
  1212. height: 17px;
  1213. margin: 2px;
  1214. border: 1px solid #c8ccd4;
  1215. border-radius: 3px;
  1216. vertical-align: middle;
  1217. transition: background 0.1s ease;
  1218. cursor: pointer;
  1219. }
  1220.  
  1221. .modCheckbox .cbx:after {
  1222. content: '';
  1223. position: absolute;
  1224. top: 1px;
  1225. left: 5px;
  1226. width: 5px;
  1227. height: 11px;
  1228. opacity: 0;
  1229. transform: rotate(45deg) scale(0);
  1230. border-right: 2px solid #fff;
  1231. border-bottom: 2px solid #fff;
  1232. transition: all 0.3s ease;
  1233. transition-delay: 0.15s;
  1234. }
  1235.  
  1236. .modCheckbox input[type="checkbox"]:checked ~ .cbx {
  1237. border-color: transparent;
  1238. background: #6871f1;
  1239. box-shadow: 0 0 10px #2E2D80;
  1240. }
  1241.  
  1242. .modCheckbox input[type="checkbox"]:checked ~ .cbx:after {
  1243. opacity: 1;
  1244. transform: rotate(45deg) scale(1);
  1245. }
  1246.  
  1247. .SettingsButton{
  1248. border: none;
  1249. outline: none;
  1250. margin-right: 10px;
  1251. transition: all .3s ease;
  1252. }
  1253. .SettingsButton:hover {
  1254. scale: 1.1;
  1255. }
  1256. .colorInput{
  1257. background-color: transparent;
  1258. width: 31px;
  1259. height: 35px;
  1260. border-radius: 50%;
  1261. border: none;
  1262. }
  1263. .colorInput::-webkit-color-swatch {
  1264. border-radius: 50%;
  1265. border: 2px solid #fff;
  1266. }
  1267. .whiteBorder_colorInput::-webkit-color-swatch {
  1268. border-color: #fff;
  1269. }
  1270. #dclinkdiv {
  1271. display: flex;
  1272. flex-direction: row;
  1273. }
  1274. .dclinks {
  1275. width: calc(50% - 5px);
  1276. height: 36px;
  1277. display: flex;
  1278. justify-content: center;
  1279. align-items: center;
  1280. background-color: rgba(88, 101, 242, 1);
  1281. border-radius: 6px;
  1282. margin: 0 auto;
  1283. color: #fff;
  1284. }
  1285. #cm_close__settings {
  1286. width: 50px;
  1287. transition: all .3s ease;
  1288. }
  1289. #cm_close__settings svg:hover {
  1290. scale: 1.1;
  1291. }
  1292. #cm_close__settings svg {
  1293. transition: all .3s ease;
  1294. }
  1295. .modTitleText {
  1296. text-align: center;
  1297. font-size: 16px;
  1298. }
  1299. .modItem {
  1300. display: flex;
  1301. justify-content: center;
  1302. align-items: center;
  1303. flex-direction: column;
  1304. }
  1305. .mod_tab-content {
  1306. width: 100%;
  1307. margin: 10px;
  1308. overflow: auto;
  1309. display: flex;
  1310. flex-direction: column;
  1311. }
  1312.  
  1313. #Tab6 .mod_tab-content {
  1314. overflow-y: auto;
  1315. max-height: 230px;
  1316. display: flex;
  1317. flex-wrap: nowrap;
  1318. flex-direction: column;
  1319. gap: 10px;
  1320. }
  1321.  
  1322. .tab-content, #coins-tab, #chests-tab {
  1323. overflow-x: hidden;
  1324. justify-content: center;
  1325. }
  1326.  
  1327. #shop-skins-buttons::after {
  1328. background: #050505;
  1329. }
  1330.  
  1331. .w-100 {
  1332. width: 100%
  1333. }
  1334. .btn:hover {
  1335. color: unset;
  1336. }
  1337.  
  1338. #savedNames {
  1339. background-color: #000;
  1340. padding: 5px;
  1341. border-radius: 5px;
  1342. overflow-y: auto;
  1343. height: 155px;
  1344. background-image: url("https://raw.githubusercontent.com/Sigmally/SigMod/main/images/purple_gradient.png");
  1345. background-size: cover;
  1346. background-position: center;
  1347. background-repeat: no-repeat;
  1348. box-shadow: 0 0 10px #000;
  1349. }
  1350.  
  1351. /* Chrome, Safari */
  1352. .scroll::-webkit-scrollbar {
  1353. width: 7px;
  1354. }
  1355.  
  1356. .scroll::-webkit-scrollbar-track {
  1357. background: #222;
  1358. border-radius: 5px;
  1359. }
  1360.  
  1361. .scroll::-webkit-scrollbar-thumb {
  1362. background-color: #333;
  1363. border-radius: 5px;
  1364. }
  1365.  
  1366. .scroll::-webkit-scrollbar-thumb:hover {
  1367. background: #353535;
  1368. }
  1369.  
  1370. /* Firefox */
  1371. .scroll {
  1372. scrollbar-width: thin;
  1373. scrollbar-color: #333 #222;
  1374. }
  1375.  
  1376. .scroll:hover {
  1377. scrollbar-color: #353535 #222;
  1378. }
  1379.  
  1380. .themes {
  1381. display: flex;
  1382. flex-direction: row;
  1383. width: 100%;
  1384. height: 420px;
  1385. background: #000;
  1386. border-radius: 5px;
  1387. overflow-y: scroll;
  1388. gap: 10px;
  1389. padding: 5px;
  1390. flex-wrap: wrap;
  1391. justify-content: center;
  1392. }
  1393.  
  1394. .themeContent {
  1395. width: 50px;
  1396. height: 50px;
  1397. border: 2px solid #222;
  1398. border-radius: 50%;
  1399. background-position: center;
  1400. }
  1401.  
  1402. .theme {
  1403. height: 75px;
  1404. display: flex;
  1405. align-items: center;
  1406. justify-content: center;
  1407. flex-direction: column;
  1408. cursor: pointer;
  1409. }
  1410. .delName {
  1411. font-weight: 500;
  1412. background: #e17e7e;
  1413. height: 20px;
  1414. border: none;
  1415. border-radius: 5px;
  1416. font-size: 10px;
  1417. margin-left: 5px;
  1418. color: #fff;
  1419. display: flex;
  1420. justify-content: center;
  1421. align-items: center;
  1422. width: 20px;
  1423. }
  1424. .NameDiv {
  1425. display: flex;
  1426. background: #111;
  1427. border-radius: 5px;
  1428. margin: 5px;
  1429. padding: 3px 8px;
  1430. height: 34px;
  1431. align-items: center;
  1432. justify-content: space-between;
  1433. cursor: pointer;
  1434. box-shadow: 0 5px 10px -2px #000;
  1435. }
  1436. .NameLabel {
  1437. cursor: pointer;
  1438. font-weight: 500;
  1439. text-align: center;
  1440. color: #fff;
  1441. }
  1442. .resetButton {
  1443. width: 25px;
  1444. height: 25px;
  1445. background-image: url("https://raw.githubusercontent.com/Sigmally/SigMod/main/images/reset.svg");
  1446. background-color: transparent;
  1447. border: none;
  1448. }
  1449.  
  1450. .modAlert {
  1451. position: fixed;
  1452. top: 80px;
  1453. left: 50%;
  1454. transform: translate(-50%, -50%);
  1455. z-index: 99995;
  1456. background: #3F3F3F;
  1457. border-radius: 10px;
  1458. display: flex;
  1459. flex-direction: column;
  1460. gap: 5px;
  1461. padding: 10px;
  1462. color: #fff;
  1463. }
  1464.  
  1465. @import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
  1466. .tournamentAlert {
  1467. position: fixed;
  1468. top: 100px;
  1469. left: 50%;
  1470. transform: translate(-50%, -50%);
  1471. z-index: 99995;
  1472. background: url("https://app.czrsd.com/static/tournament_winteredition.png");
  1473. background-size: cover;
  1474. background-position: center;
  1475. border-radius: 10px;
  1476. overflow: hidden;
  1477. box-shadow: 0 0 10px #4e7ed5;
  1478. }
  1479. .tournamentAlert * {
  1480. font-family: 'Poppins', sans-serif;
  1481. }
  1482. .tournamentAlert__inner {
  1483. border-radius: 10px;
  1484. display: flex;
  1485. flex-direction: column;
  1486. gap: 10px;
  1487. color: #fff;
  1488. padding: 10px;
  1489. border-radius: 10px;
  1490. }
  1491. .tournamentAlert .tHeader span {
  1492. font-size: 16px;
  1493. font-weight: 600;
  1494. }
  1495. .tournamentAlert p {
  1496. text-align: center;
  1497. }
  1498. .tournamentAlert .tHeader button {
  1499. background: #C13939;
  1500. border: none;
  1501. border-radius: 50%;
  1502. height: 32px;
  1503. width: 32px;
  1504. display: flex;
  1505. justify-content: center;
  1506. align-items: center;
  1507. transition: all 0.3s ease-in-out;
  1508. }
  1509. .tournamentAlert .tHeader button:hover {
  1510. background: #e05151;
  1511. scale: 1.05;
  1512. box-shadow: 0 0 10px #e05151;
  1513. }
  1514.  
  1515. .tournamentAlert::after {
  1516. content: '';
  1517. width: 102%;
  1518. height: 100%;
  1519. position: absolute;
  1520. top: 0;
  1521. left: -2px;
  1522. background: rgba(0, 0, 0, .8);
  1523. z-index: -1;
  1524. }
  1525.  
  1526. .tournamentAlert .tFooter img {
  1527. width: 50px;
  1528. height: 50px;
  1529. border-radius: 100%;
  1530. }
  1531.  
  1532. .tournamentAlert .tFooter button {
  1533. background: #0057FF;
  1534. border: none;
  1535. border-radius: 20px;
  1536. padding: 8px;
  1537. display: flex;
  1538. align-items: center;
  1539. gap: 10px;
  1540. transition: all 0.3s ease-in-out;
  1541. }
  1542.  
  1543. .tournamentAlert .tFooter button:hover {
  1544. background: #0077ff;
  1545. scale: 1.1;
  1546. box-shadow: 0 0 10px #0077ff;
  1547. }
  1548.  
  1549. .alert_overlay {
  1550. position: absolute;
  1551. top: 0;
  1552. left: 0;
  1553. z-index: 9999999;
  1554. pointer-events: none;
  1555. width: 100%;
  1556. height: 100vh;
  1557. display: flex;
  1558. flex-direction: column;
  1559. justify-content: start;
  1560. align-items: center;
  1561. }
  1562.  
  1563. .infoAlert {
  1564. padding: 5px;
  1565. border-radius: 5px;
  1566. margin-top: 5px;
  1567. color: #fff;
  1568. }
  1569.  
  1570. .modAlert-success {
  1571. background: #5BA55C;
  1572. }
  1573. .modAlert-success .modAlert-loader {
  1574. background: #6BD56D;
  1575. }
  1576. .modAlert-default {
  1577. background: #151515;
  1578. }
  1579. .modAlert-default .modAlert-loader {
  1580. background: #222;
  1581. }
  1582. .modAlert-danger {
  1583. background: #D44121;
  1584. }
  1585. .modAlert-danger .modAlert-loader {
  1586. background: #A5361E;
  1587. }
  1588. #free-coins .modAlert-danger {
  1589. background: #fff !important;
  1590. }
  1591.  
  1592. .modAlert-loader {
  1593. width: 100%;
  1594. height: 2px;
  1595. margin-top: 5px;
  1596. transition: all .3s ease-in-out;
  1597. animation: loadAlert 2s forwards;
  1598. }
  1599.  
  1600. @keyframes loadAlert {
  1601. 0% {
  1602. width: 100%;
  1603. }
  1604. 100% {
  1605. width: 0%;
  1606. }
  1607. }
  1608.  
  1609.  
  1610. .themeEditor {
  1611. z-index: 999999999999;
  1612. position: absolute;
  1613. top: 50%;
  1614. left: 50%;
  1615. transform: translate(-50%, -50%);
  1616. background: rgba(0, 0, 0, .85);
  1617. color: #fff;
  1618. padding: 10px;
  1619. border-radius: 10px;
  1620. box-shadow: 0 0 10px #000;
  1621. width: 400px;
  1622. }
  1623.  
  1624. .theme_editor_header {
  1625. display: flex;
  1626. justify-content: space-between;
  1627. align-items: center;
  1628. gap: 10px;
  1629. }
  1630.  
  1631. .theme-editor-tab {
  1632. display: flex;
  1633. justify-content: center;
  1634. align-items: start;
  1635. flex-direction: column;
  1636. margin-top: 10px
  1637. }
  1638.  
  1639. .themes_preview {
  1640. width: 50px;
  1641. height: 50px;
  1642. border: 2px solid #fff;
  1643. border-radius: 2px;
  1644. display: flex;
  1645. justify-content: center;
  1646. align-items: center;
  1647. }
  1648.  
  1649. .modKeybindings {
  1650. display: flex;
  1651. flex-direction: column;
  1652. overflow-y: scroll;
  1653. max-height: 170px;
  1654. }
  1655. .modKeybindings > label {
  1656. margin-right: 5px;
  1657. }
  1658. #signInBtn, #nick, #gamemode, #option_0, #option_1, #option_2, .form-control, .profile-header, .coins-num, #clan-members, .member-index, .member-level, #clan-requests {
  1659. background: rgba(0, 0, 0, 0.4) !important;
  1660. color: #fff !important;
  1661. }
  1662. .profile-name, #progress-next, .member-desc > p:first-child, #clan-leave > div, .clans-item > div > b, #clans-input input, #shop-nav button {
  1663. color: #fff !important;
  1664. }
  1665. .head-desc, #shop-nav button {
  1666. border: 1px solid #000;
  1667. }
  1668. #clan-handler, #request-handler, #clans-list, #clans-input, .clans-item button, #shop-content, #shop-nav button:hover, .card-particles-bar-bg {
  1669. background: #111;
  1670. color: #fff !important;
  1671. }
  1672. #clans_and_settings {
  1673. height: auto !important;
  1674. }
  1675. .card-body {
  1676. background: linear-gradient(180deg, #000 0%, #1b354c 100%);
  1677. }
  1678. .free-card:hover .card-body {
  1679. background: linear-gradient(180deg, #111 0%, #1b354c 100%);
  1680. }
  1681. #shop-tab-body, #shop-skins-buttons, #shop-nav {
  1682. background: #050505;
  1683. }
  1684. #clan-leave {
  1685. background: #111;
  1686. bottom: -1px;
  1687. }
  1688. .sent {
  1689. position: relative;
  1690. width: 100px;
  1691. }
  1692.  
  1693. .sent::before {
  1694. content: "Sent request";
  1695. width: 100%;
  1696. height: 10px;
  1697. word-spacing: normal;
  1698. white-space: nowrap;
  1699. position: absolute;
  1700. background: #4f79f9;
  1701. display: flex;
  1702. justify-content: center;
  1703. align-items: center;
  1704. }
  1705.  
  1706. .btn, .sign-in-out-btn {
  1707. transition: all .2s ease;
  1708. }
  1709. #clan .connecting__content, #clans .connecting__content {
  1710. background: #151515;
  1711. color: #fff;
  1712. box-shadow: 0 0 10px rgba(0, 0, 0, .5);
  1713. }
  1714.  
  1715. .skin-select__icon-text {
  1716. color: #fff;
  1717. }
  1718.  
  1719. .justify-sb {
  1720. display: flex;
  1721. align-items: center;
  1722. justify-content: space-between;
  1723. }
  1724.  
  1725. .macro-extanded_input {
  1726. width: 75px;
  1727. text-align: center;
  1728. }
  1729. #gamemode option {
  1730. background: #111;
  1731. }
  1732.  
  1733. .stats-line {
  1734. width: 100%;
  1735. user-select: none;
  1736. margin-bottom: 5px;
  1737. padding: 5px;
  1738. background: #050505;
  1739. border: 1px solid var(--default-mod);
  1740. border-radius: 5px;
  1741. }
  1742. .my-5 {
  1743. margin: 5px 0;
  1744. }
  1745.  
  1746. .stats-info-text {
  1747. color: #7d7d7d;
  1748. }
  1749.  
  1750. .setting-card-wrapper {
  1751. margin-right: 10px;
  1752. padding: 10px;
  1753. background: #161616;
  1754. border-radius: 5px;
  1755. display: flex;
  1756. flex-direction: column;
  1757. }
  1758.  
  1759. .setting-card {
  1760. display: flex;
  1761. align-items: center;
  1762. justify-content: space-between;
  1763. }
  1764.  
  1765. .setting-card-action {
  1766. display: flex;
  1767. align-items: center;
  1768. gap: 5px;
  1769. cursor: pointer;
  1770. }
  1771.  
  1772. .setting-card-action {
  1773. width: 100%;
  1774. }
  1775.  
  1776. .setting-card-name {
  1777. font-size: 16px;
  1778. user-select: none;
  1779. width: 100%;
  1780. }
  1781.  
  1782. .mod-small-modal {
  1783. display: flex;
  1784. flex-direction: column;
  1785. gap: 10px;
  1786. position: absolute;
  1787. z-index: 99999;
  1788. top: 50%;
  1789. left: 50%;
  1790. transform: translate(-50%, -50%);
  1791. background: #191919;
  1792. box-shadow: 0 5px 15px -2px #000;
  1793. border: 2px solid var(--default-mod-color);
  1794. padding: 10px;
  1795. border-radius: 5px;
  1796. }
  1797.  
  1798. .mod-small-modal-header {
  1799. display: flex;
  1800. justify-content: space-between;
  1801. align-items: center;
  1802. }
  1803.  
  1804. .mod-small-modal-header h1 {
  1805. font-size: 20px;
  1806. font-weight: 500;
  1807. margin: 0;
  1808. }
  1809.  
  1810. .mod-small-modal-content {
  1811. display: flex;
  1812. flex-direction: column;
  1813. width: 100%;
  1814. align-items: center;
  1815. }
  1816.  
  1817. .mod-small-modal-content_selectImage {
  1818. display: flex;
  1819. flex-direction: column;
  1820. gap: 10px;
  1821. }
  1822.  
  1823. .previmg {
  1824. width: 50px;
  1825. height: 50px;
  1826. border: 2px solid #ccc;
  1827. }
  1828.  
  1829. .stats__item>span, #title, .stats-btn__text {
  1830. color: #fff;
  1831. }
  1832.  
  1833. .top-users__inner::-webkit-scrollbar-thumb {
  1834. border: none;
  1835. }
  1836.  
  1837. .modChat {
  1838. min-width: 450px;
  1839. max-width: 450px;
  1840. min-height: 285px;
  1841. max-height: 285px;
  1842. color: #fafafa;
  1843. padding: 10px;
  1844. position: absolute;
  1845. bottom: 10px;
  1846. left: 10px;
  1847. z-index: 999;
  1848. border-radius: .5rem;
  1849. overflow: hidden;
  1850. opacity: 1;
  1851. transition: all .3s ease;
  1852. }
  1853.  
  1854. .modChat__inner {
  1855. min-width: 430px;
  1856. max-width: 430px;
  1857. min-height: 265px;
  1858. max-height: 265px;
  1859. height: 100%;
  1860. display: flex;
  1861. flex-direction: column;
  1862. gap: 5px;
  1863. justify-content: flex-end;
  1864. opacity: 1;
  1865. transition: all .3s ease;
  1866. }
  1867.  
  1868. .mod-compact {
  1869. transform: scale(0.78);
  1870. }
  1871. .mod-compact.modChat {
  1872. left: -40px;
  1873. bottom: -20px;
  1874. }
  1875. .mod-compact.chatAddedContainer {
  1876. left: 350px;
  1877. bottom: -17px;
  1878. }
  1879.  
  1880. #scroll-down-btn {
  1881. position: absolute;
  1882. bottom: 60px;
  1883. left: 50%;
  1884. transform: translateX(-50%);
  1885. width: 80px;
  1886. display:none;
  1887. box-shadow:0 0 5px #000;
  1888. z-index: 5;
  1889. }
  1890.  
  1891. .modchat-chatbuttons {
  1892. margin-bottom: auto;
  1893. display: flex;
  1894. gap: 5px;
  1895. }
  1896.  
  1897. .chat-context {
  1898. position: absolute;
  1899. z-index: 999999;
  1900. width: 100px;
  1901. display: flex;
  1902. flex-direction: column;
  1903. justify-content: center;
  1904. align-items: center;
  1905. gap: 5px;
  1906. background: #181818;
  1907. border-radius: 5px;
  1908. }
  1909.  
  1910. .chat-context span {
  1911. color: #fff;
  1912. user-select: none;
  1913. padding: 5px;
  1914. white-space: nowrap;
  1915. }
  1916.  
  1917. .chat-context button {
  1918. width: 100%;
  1919. background-color: transparent;
  1920. border: none;
  1921. border-top: 2px solid #747474;
  1922. outline: none;
  1923. color: #fff;
  1924. transition: all .3s ease;
  1925. }
  1926.  
  1927. .chat-context button:hover {
  1928. backgrokund-color: #222;
  1929. }
  1930.  
  1931. .tagText {
  1932. margin-left: auto;
  1933. font-size: 14px;
  1934. }
  1935.  
  1936. #mod-messages {
  1937. position: relative;
  1938. display: flex;
  1939. flex-direction: column;
  1940. max-height: 185px;
  1941. overflow-y: auto;
  1942. direction: rtl;
  1943. scroll-behavior: smooth;
  1944. }
  1945. .message {
  1946. direction: ltr;
  1947. margin: 2px 0 0 5px;
  1948. text-overflow: ellipsis;
  1949. white-space: nowrap;
  1950. max-width: 100%;
  1951. display: flex;
  1952. justify-content: space-between;
  1953. align-items: center;
  1954. }
  1955.  
  1956. .message_name {
  1957. user-select: none;
  1958. }
  1959.  
  1960. .message .time {
  1961. color: rgba(255, 255, 255, 0.7);
  1962. font-size: 12px;
  1963. }
  1964.  
  1965. #chatInputContainer {
  1966. display: flex;
  1967. gap: 5px;
  1968. align-items: center;
  1969. padding: 5px;
  1970. background: rgba(25,25,25, .6);
  1971. border-radius: .5rem;
  1972. overflow: hidden;
  1973. }
  1974.  
  1975. .chatInput {
  1976. flex-grow: 1;
  1977. border: none;
  1978. background: transparent;
  1979. color: #fff;
  1980. padding: 5px;
  1981. outline: none;
  1982. max-width: 100%;
  1983. }
  1984.  
  1985. .chatButton {
  1986. background: #8a25e5;
  1987. border: none;
  1988. border-radius: 5px;
  1989. padding: 5px 10px;
  1990. height: 100%;
  1991. color: #fff;
  1992. transition: all 0.3s;
  1993. cursor: pointer;
  1994. display: flex;
  1995. align-items: center;
  1996. height: 28px;
  1997. justify-content: center;
  1998. gap: 5px;
  1999. }
  2000. .chatButton:hover {
  2001. background: #7a25e5;
  2002. }
  2003. .chatCloseBtn {
  2004. position: absolute;
  2005. top: 50%;
  2006. left: 50%;
  2007. transform: translate(-50%, -50%);
  2008. }
  2009.  
  2010. .emojisContainer {
  2011. display: flex;
  2012. flex-direction: column;
  2013. gap: 5px;
  2014. }
  2015. .chatAddedContainer {
  2016. position: absolute;
  2017. bottom: 10px;
  2018. left: 465px;
  2019. z-index: 9999;
  2020. padding: 10px;
  2021. background: #151515;
  2022. border-radius: .5rem;
  2023. min-width: 172px;
  2024. max-width: 172px;
  2025. min-height: 250px;
  2026. max-height: 250px;
  2027. }
  2028. #categories {
  2029. overflow-y: auto;
  2030. max-height: calc(250px - 50px);
  2031. gap: 2px;
  2032. }
  2033. .category {
  2034. width: 100%;
  2035. display: flex;
  2036. flex-direction: column;
  2037. gap: 2px;
  2038. }
  2039. .category span {
  2040. color: #fafafa;
  2041. font-size: 14px;
  2042. text-align: center;
  2043. }
  2044.  
  2045. .emojiContainer {
  2046. display: flex;
  2047. flex-wrap: wrap;
  2048. align-items: center;
  2049. justify-content: center;
  2050. }
  2051.  
  2052. #categories .emoji {
  2053. padding: 2px;
  2054. border-radius: 5px;
  2055. font-size: 16px;
  2056. user-select: none;
  2057. cursor: pointer;
  2058. }
  2059.  
  2060. .chatSettingsContainer {
  2061. padding: 10px 3px;
  2062. }
  2063. .chatSettingsContainer .scroll {
  2064. display: flex;
  2065. flex-direction: column;
  2066. gap: 10px;
  2067. max-height: 235px;
  2068. overflow-y: auto;
  2069. padding: 0 10px;
  2070. }
  2071.  
  2072. .csBlock {
  2073. border: 2px solid #050505;
  2074. border-radius: .5rem;
  2075. color: #fff;
  2076. display: flex;
  2077. align-items: center;
  2078. flex-direction: column;
  2079. gap: 5px;
  2080. padding-bottom: 5px;
  2081. }
  2082.  
  2083. .csBlock .csBlockTitle {
  2084. background: #080808;
  2085. width: 100%;
  2086. padding: 3px;
  2087. text-align: center;
  2088. }
  2089.  
  2090. .csRow {
  2091. display: flex;
  2092. justify-content: space-between;
  2093. align-items: center;
  2094. padding: 0 5px;
  2095. width: 100%;
  2096. }
  2097.  
  2098. .csRowName {
  2099. display: flex;
  2100. gap: 5px;
  2101. align-items: start;
  2102. }
  2103.  
  2104. .csRowName .infoIcon {
  2105. width: 14px;
  2106. cursor: pointer;
  2107. }
  2108.  
  2109. .modInfoPopup {
  2110. position: absolute;
  2111. top: 2px;
  2112. left: 58%;
  2113. text-align: center;
  2114. background: #151515;
  2115. border: 1px solid #607bff;
  2116. border-radius: 10px;
  2117. transform: translateX(-50%);
  2118. white-space: nowrap;
  2119. padding: 5px;
  2120. z-index: 99999;
  2121. }
  2122.  
  2123. .modInfoPopup::after {
  2124. content: '';
  2125. display: block;
  2126. position: absolute;
  2127. bottom: -7px;
  2128. background: #151515;
  2129. right: 50%;
  2130. transform: translateX(-50%) rotate(-45deg);
  2131. width: 12px;
  2132. height: 12px;
  2133. border-left: 1px solid #607bff;
  2134. border-bottom: 1px solid #607bff;
  2135. }
  2136.  
  2137. .modInfoPopup p {
  2138. margin: 0;
  2139. font-size: 12px;
  2140. color: #fff;
  2141. }
  2142.  
  2143. .error-message_sigMod {
  2144. display: flex;
  2145. align-items: center;
  2146. position: absolute;
  2147. bottom: 20px;
  2148. right: -500px;
  2149. background: #fff;
  2150. box-shadow: 0 0 10px rgba(0, 0, 0, .8);
  2151. z-index: 9999999;
  2152. width: 426px;
  2153. border-radius: 10px;
  2154. padding: 10px;
  2155. gap: 6px;
  2156. transition: all .3s ease-out;
  2157. }
  2158.  
  2159. .minimapContainer {
  2160. display: flex;
  2161. flex-direction: column;
  2162. align-items: end;
  2163. pointer-events: none;
  2164. position: absolute;
  2165. bottom: 0;
  2166. right: 0;
  2167. z-index: 99999;
  2168. }
  2169. .tournament_time {
  2170. color: #fff;
  2171. font-size: 15px;
  2172. }
  2173. .minimap {
  2174. border-radius: 2px;
  2175. border-top: 1px solid rgba(255, 255, 255, .5);
  2176. border-left: 1px solid rgba(255, 255, 255, .5);
  2177. box-shadow: 0 0 4px rgba(255, 255, 255, .5);
  2178. }
  2179.  
  2180. #tag {
  2181. width: 50px;
  2182. }
  2183.  
  2184. .blur {
  2185. color: transparent!important;
  2186. text-shadow: 0 0 5px hsl(0deg 0% 90% / 70%);
  2187. transition: all .2s;
  2188. }
  2189.  
  2190. .blur:focus, .blur:hover {
  2191. color: #fafafa!important;
  2192. text-shadow: none;
  2193. }
  2194. .progress-row button {
  2195. background: transparent;
  2196. }
  2197.  
  2198. .mod_player-stats {
  2199. display: flex;
  2200. flex-direction: column;
  2201. gap: 5px;
  2202. align-self: start;
  2203. }
  2204.  
  2205. .mod_player-stats .player-stats-grid {
  2206. display: grid;
  2207. grid-template-columns: 1.2fr 1.1fr;
  2208. gap: 5px;
  2209. }
  2210.  
  2211. .player-stat {
  2212. display: flex;
  2213. flex-direction: column;
  2214. justify-content: center;
  2215. align-items: center;
  2216. padding: 10px;
  2217. background: rgba(05, 05, 05, .75);
  2218. border-radius: 5px;
  2219. width: 100%;
  2220. height: 85px;
  2221. box-shadow: 0px 2px 10px -2px #000;
  2222. z-index: 2;
  2223. }
  2224. .player-stat span[id] {
  2225. font-size: 17px;
  2226. }
  2227.  
  2228. .quickAccess {
  2229. background: #050505;
  2230. display: flex;
  2231. flex-direction: column;
  2232. gap: 5px;
  2233. padding: 5px;
  2234. border-radius: 5px;
  2235. width: 100%;
  2236. max-height: 154px;
  2237. overflow-y: auto;
  2238. }
  2239.  
  2240. .quickAccess div.modRowItems {
  2241. padding: 2px!important;
  2242. }
  2243.  
  2244. #mod_home .justify-sb {
  2245. z-index: 2;
  2246. }
  2247.  
  2248. .modTitleText {
  2249. font-size: 15px;
  2250. color: #fafafa;
  2251. text-align: start;
  2252. }
  2253. .modDescText {
  2254. text-align: start;
  2255. font-size: 12px;
  2256. color: #777;
  2257. }
  2258. .modButton-secondary {
  2259. background-color: #171717;
  2260. color: #fff;
  2261. border: none;
  2262. padding: 5px 15px;
  2263. border-radius: 15px;
  2264. }
  2265. .vr {
  2266. width: 2px;
  2267. height: 250px;
  2268. background-color: #fafafa;
  2269. }
  2270. .vr2 {
  2271. width: 1px;
  2272. height: 26px;
  2273. background-color: #202020;
  2274. }
  2275.  
  2276. .modProfileWrapper {
  2277. display: flex;
  2278. flex-direction: column;
  2279. gap: 5px;
  2280. }
  2281. .modUserProfile {
  2282. display: flex;
  2283. flex-direction: column;
  2284. gap: 7px;
  2285. border-radius: 5px;
  2286. background: #050505;
  2287. min-width: 300px;
  2288. max-width: 300px;
  2289. height: 154px;
  2290. max-height: 154px;
  2291. padding: 5px 10px;
  2292. }
  2293. #my-profile-bio {
  2294. overflow-y: scroll;
  2295. max-height: 75px;
  2296. }
  2297.  
  2298. .brand_wrapper {
  2299. position: relative;
  2300. height: 72px;
  2301. width: 100%;
  2302. display: flex;
  2303. justify-content: center;
  2304. align-items: center;
  2305. }
  2306. .brand_img {
  2307. position: absolute;
  2308. top: 0;
  2309. left: 0;
  2310. width: 100%;
  2311. height: 72px;
  2312. border-radius: 10px;
  2313. object-fit: cover;
  2314. object-position: center;
  2315. z-index: 1;
  2316. box-shadow: 0 0 10px #000;
  2317. }
  2318. .brand_credits {
  2319. font-size: 16px;
  2320. color: #D3A7FF
  2321. }
  2322. .p_s_n {
  2323. background-color: #050505;
  2324. border-radius: 15px;
  2325. box-shadow: 0 3px 10px -2px #050505;
  2326. margin: 35px 0;
  2327. font-size: 16px;
  2328. width: 50%;
  2329. align-self: center;
  2330. }
  2331. .userId_wrapper {
  2332. background: #000;
  2333. padding: 5px 20px;
  2334. margin-bottom: 10px;
  2335. display: flex;
  2336. align-items: center;
  2337. justify-content: center;
  2338. width: 50%;
  2339. border-radius: 10px;
  2340. align-self: center;
  2341. position: relative;
  2342. }
  2343.  
  2344. .userId_copy {
  2345. position: absolute;
  2346. top: -10px;
  2347. right: -10px;
  2348. background: #050505;
  2349. border-radius: 100%;
  2350. padding: 10px;
  2351. width: 35px;
  2352. height: 35px;
  2353. cursor: pointer;
  2354. transition: all .3s ease;
  2355. }
  2356.  
  2357. .userId_copy:hover {
  2358. transform: scale(1.1);
  2359. }
  2360. .brand_yt {
  2361. display: flex;
  2362. justify-content: center;
  2363. align-items: center;
  2364. gap: 20px;
  2365. }
  2366. .yt_wrapper {
  2367. display: flex;
  2368. flex-direction: column;
  2369. justify-content: center;
  2370. align-items: center;
  2371. gap: 10px;
  2372. width: 122px;
  2373. height: 100px;
  2374. padding: 10px;
  2375. background-color: #B63333;
  2376. border-radius: 15px;
  2377. cursor: pointer;
  2378. }
  2379. .yt_wrapper span {
  2380. user-select: none;
  2381. }
  2382.  
  2383. .hidden_full {
  2384. display: none !important;
  2385. visibility: hidden;
  2386. }
  2387.  
  2388. .mod_overlay {
  2389. position: absolute;
  2390. top: 0;
  2391. left: 0;
  2392. width: 100%;
  2393. height: 100vh;
  2394. background: rgba(0, 0, 0, .7);
  2395. z-index: 999999;
  2396. display: flex;
  2397. justify-content: center;
  2398. align-items: center;
  2399. transition: all .3s ease;
  2400. }
  2401.  
  2402. .tournaments-wrapper {
  2403. position: absolute;
  2404. top: 60%;
  2405. left: 50%;
  2406. transform: translate(-50%, -50%);
  2407. z-index: 999999;
  2408. background: #151515;
  2409. box-shadow: 0 5px 10px 2px #000;
  2410. border-radius: 0.75rem;
  2411. padding: 2.25rem;
  2412. color: #fafafa;
  2413. text-align: center;
  2414. display: flex;
  2415. flex-direction: column;
  2416. align-items: center;
  2417. gap: 10px;
  2418. min-width: 632px;
  2419. opacity: 0;
  2420. transition: all .3s ease;
  2421. animation: 0.5s ease fadeIn forwards;
  2422. }
  2423. @keyframes fadeIn {
  2424. 0% {
  2425. top: 60%;
  2426. opacity: 0;
  2427. }
  2428. 100% {
  2429. top: 50%;
  2430. opacity: 1;
  2431. }
  2432. }
  2433. .tournaments h1 {
  2434. margin: 0;
  2435. }
  2436. .t_profile {
  2437. display: flex;
  2438. flex-direction: column;
  2439. align-items: center;
  2440. }
  2441. .t_profile img {
  2442. border: 2px solid #ccc;
  2443. border-radius: 50%;
  2444. }
  2445. .team {
  2446. display: flex;
  2447. gap: 10px;
  2448. padding: 10px;
  2449. position: relative;
  2450. }
  2451. .team.blue {
  2452. border-radius: 5px 0 0 5px;
  2453. }
  2454. .team.red {
  2455. border-radius: 0 5px 5px 0;
  2456. }
  2457. .blue {
  2458. background: rgb(71, 113, 203);
  2459. }
  2460. .red {
  2461. background: rgb(203, 71, 71);
  2462. }
  2463.  
  2464. .blue_polygon {
  2465. width: 75px;
  2466. clip-path: polygon(0 100%, 0 0, 100% 100%);
  2467. background: rgb(71, 113, 203);
  2468. }
  2469.  
  2470. .red_polygon {
  2471. width: 75px;
  2472. clip-path: polygon(100% 0, 0 0, 100% 100%);
  2473. background: rgb(203, 71, 71);
  2474. }
  2475.  
  2476. .vs {
  2477. position: relative;
  2478. align-items: center;
  2479. justify-content: center;
  2480. }
  2481. .vs span {
  2482. position: absolute;
  2483. top: 50%;
  2484. left: 50%;
  2485. transform: translate(-50%, -50%);
  2486. text-shadow: 1px 0 0 #000, -1px 0 0 #000, 0 1px 0 #000, 0 -1px 0 #000, 1px 1px #000, -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 0 0 6px #000;
  2487. font-size: 28px;
  2488. }
  2489.  
  2490. details {
  2491. border: 1px solid #aaa;
  2492. border-radius: 4px;
  2493. padding: 0.5em 0.5em 0;
  2494. user-select: none;
  2495. text-align: start;
  2496. }
  2497.  
  2498. summary {
  2499. font-weight: bold;
  2500. margin: -0.5em -0.5em 0;
  2501. padding: 0.5em;
  2502. }
  2503.  
  2504. details[open] {
  2505. padding: 0.5em;
  2506. }
  2507.  
  2508. details[open] summary {
  2509. border-bottom: 1px solid #aaa;
  2510. margin-bottom: 0.5em;
  2511. }
  2512. button[disabled] {
  2513. filter: grayscale(1);
  2514. }
  2515.  
  2516. .tournament_alert {
  2517. position: absolute;
  2518. top: 20px;
  2519. left: 50%;
  2520. transform: translateX(-50%);
  2521. background: #151515;
  2522. color: #fff;
  2523. text-align: center;
  2524. padding: 20px;
  2525. z-index: 999999;
  2526. border-radius: 10px;
  2527. box-shadow: 0 0 10px #000;
  2528. display: flex;
  2529. gap: 10px;
  2530. }
  2531. .tournament-profile {
  2532. width: 50px;
  2533. height: 50px;
  2534. border-radius: 50%;
  2535. box-shadow: 0 0 10px #000;
  2536. }
  2537.  
  2538. .tround_text {
  2539. color: #fff;
  2540. font-size: 24px;
  2541. position: absolute;
  2542. bottom: 30%;
  2543. left: 50%;
  2544. transform: translate(-50%, -50%);
  2545. }
  2546.  
  2547. .claimedBadgeWrapper {
  2548. background: linear-gradient(232deg, #020405 1%, #04181E 100%);
  2549. border-radius: 10px;
  2550. width: 320px;
  2551. height: 330px;
  2552. box-shadow: 0 0 40px -20px #39bdff;
  2553. display: flex;
  2554. flex-direction: column;
  2555. gap: 10px;
  2556. align-items: center;
  2557. justify-content: center;
  2558. color: #fff;
  2559. padding: 10px;
  2560. }
  2561.  
  2562. .btn-cyan {
  2563. background: #53B6CC;
  2564. border: none;
  2565. border-radius: 5px;
  2566. font-size: 16px;
  2567. color: #fff;
  2568. font-weight: 500;
  2569. width: fit-content;
  2570. padding: 5px 10px;
  2571. }
  2572.  
  2573. .playTimer {
  2574. z-index: 2;
  2575. position: absolute;
  2576. top: 128px;
  2577. left: 4px;
  2578. color: #8d8d8d;
  2579. font-size: 14px;
  2580. font-weight: 500;
  2581. user-select: none;
  2582. pointer-events: none;
  2583. }
  2584.  
  2585. .modInput-wrapper {
  2586. position: relative;
  2587. display: inline-block;
  2588. width: 100%;
  2589. }
  2590.  
  2591. .modInput-secondary {
  2592. display: inline-block;
  2593. width: 100%;
  2594. padding: 10px 0 10px 15px;
  2595. font-weight: 400;
  2596. color: #E9E9E9;
  2597. background: #050505;
  2598. border: 0;
  2599. border-radius: 3px;
  2600. outline: 0;
  2601. text-indent: 70px;
  2602. transition: all .3s ease-in-out;
  2603. }
  2604. .modInput-secondary.t-indent-120 {
  2605. text-indent: 120px;
  2606. }
  2607. .modInput-secondary::-webkit-input-placeholder {
  2608. color: #050505;
  2609. text-indent: 0;
  2610. font-weight: 300;
  2611. }
  2612. .modInput-secondary + label {
  2613. display: inline-block;
  2614. position: absolute;
  2615. top: 8px;
  2616. left: 0;
  2617. bottom: 8px;
  2618. padding: 5px 15px;
  2619. color: #E9E9E9;
  2620. font-size: 11px;
  2621. font-weight: 700;
  2622. text-transform: uppercase;
  2623. text-shadow: 0 1px 0 rgba(19, 74, 70, 0);
  2624. transition: all .3s ease-in-out;
  2625. border-radius: 3px;
  2626. background: rgba(122, 134, 184, 0);
  2627. }
  2628. .modInput-secondary + label:after {
  2629. position: absolute;
  2630. content: "";
  2631. width: 0;
  2632. height: 0;
  2633. top: 100%;
  2634. left: 50%;
  2635. margin-left: -3px;
  2636. border-left: 3px solid transparent;
  2637. border-right: 3px solid transparent;
  2638. border-top: 3px solid rgba(122, 134, 184, 0);
  2639. transition: all .3s ease-in-out;
  2640. }
  2641.  
  2642. .modInput-secondary:focus,
  2643. .modInput-secondary:active {
  2644. color: #E9E9E9;
  2645. text-indent: 0;
  2646. background: #050505;
  2647. }
  2648. .modInput-secondary:focus::-webkit-input-placeholder,
  2649. .modInput-secondary:active::-webkit-input-placeholder {
  2650. color: #aaa;
  2651. }
  2652. .modInput-secondary:focus + label,
  2653. .modInput-secondary:active + label {
  2654. color: #fff;
  2655. text-shadow: 0 1px 0 rgba(19, 74, 70, 0.4);
  2656. background: #7A86B8;
  2657. transform: translateY(-40px);
  2658. }
  2659. .modInput-secondary:focus + label:after,
  2660. .modInput-secondary:active + label:after {
  2661. border-top: 4px solid #7A86B8;
  2662. }
  2663.  
  2664. /* Friends & account */
  2665.  
  2666. .signIn-overlay {
  2667. position: absolute;
  2668. top: 0;
  2669. left: 0;
  2670. width: 100%;
  2671. height: 100vh;
  2672. background: rgba(0, 0, 0, .4);
  2673. z-index: 999999;
  2674. display: flex;
  2675. justify-content: center;
  2676. align-items: center;
  2677. color: #E3E3E3;
  2678. opacity: 0;
  2679. transition: all .3s ease;
  2680. }
  2681.  
  2682. .signIn-wrapper {
  2683. background: #111111;
  2684. width: 450px;
  2685. display: flex;
  2686. flex-direction: column;
  2687. align-items: center;
  2688. border-radius: 10px;
  2689. color: #fafafa;
  2690. }
  2691.  
  2692. .signIn-header {
  2693. background: #181818;
  2694. width: 100%;
  2695. display: flex;
  2696. justify-content: space-between;
  2697. align-items: center;
  2698. padding: 8px;
  2699. border-radius: 10px 10px 0 0;
  2700. }
  2701. .signIn-header span {
  2702. font-weight: 500;
  2703. font-size: 20px;
  2704. }
  2705.  
  2706. .signIn-body {
  2707. display: flex;
  2708. flex-direction: column;
  2709. gap: 10px;
  2710. align-items: center;
  2711. justify-content: start;
  2712. padding: 40px 40px 5px 40px;
  2713. width: 100%;
  2714. }
  2715.  
  2716. #errMessages {
  2717. color: #AC3D3D;
  2718. flex-direction: column;
  2719. gap: 5px;
  2720. }
  2721.  
  2722. .form-control {
  2723. border-width: 1px;
  2724. }
  2725. .form-control.error-border {
  2726. border-color: #AC3D3D;
  2727. }
  2728.  
  2729. .friends_header {
  2730. display: flex;
  2731. flex-direction: row;
  2732. justify-content: space-between;
  2733. align-items: center;
  2734. gap: 10px;
  2735. width: 100%;
  2736. padding: 10px;
  2737. }
  2738.  
  2739. .friends_body {
  2740. position: relative;
  2741. display: flex;
  2742. flex-direction: column;
  2743. align-items: center;
  2744. gap: 6px;
  2745. width: 100%;
  2746. height: 360px;
  2747. max-height: 360px;
  2748. overflow-y: auto;
  2749. padding-right: 10px;
  2750. }
  2751.  
  2752. .profile-img {
  2753. position: relative;
  2754. width: 52px;
  2755. height: 52px;
  2756. border-radius: 100%;
  2757. border: 1px solid #C8C9D9;
  2758. }
  2759.  
  2760. .profile-img img {
  2761. width: 100%;
  2762. height: 100%;
  2763. border-radius: 100%;
  2764. }
  2765.  
  2766. .status_icon {
  2767. position: absolute;
  2768. width: 15px;
  2769. height: 15px;
  2770. top: 0;
  2771. left: 0;
  2772. border-radius: 50%;
  2773. }
  2774.  
  2775. .online_icon {
  2776. background-color: #3DB239;
  2777. }
  2778. .offline_icon {
  2779. background-color: #B23939;
  2780. }
  2781. .Owner_role {
  2782. color: #3979B2;
  2783. }
  2784. .Moderator_role {
  2785. color: #39B298;
  2786. }
  2787. .Vip_role {
  2788. color: #E1A33E;
  2789. }
  2790.  
  2791. .friends_row {
  2792. display: flex;
  2793. flex-direction: row;
  2794. width: 100%;
  2795. justify-content: space-between;
  2796. align-items: center;
  2797. background: #090909;
  2798. border-radius: 8px;
  2799. padding: 10px;
  2800. }
  2801.  
  2802. .friends_row .val {
  2803. width: fit-content;
  2804. height: fit-content;
  2805. padding: 5px 20px;
  2806. box-sizing: content-box;
  2807. }
  2808. .feedback_row {
  2809. display: flex;
  2810. flex-direction: column;
  2811. align-items: center;
  2812. gap: 5px;
  2813. width: 80%;
  2814. position: absolute;
  2815. bottom: 18px;
  2816. left: 50%;
  2817. transform: translateX(-50%);
  2818. padding: 8px;
  2819. border-radius: 5px;
  2820. background: linear-gradient(45deg, #1a132b, #111f48);
  2821. box-shadow: 0 10px 10px #000;
  2822. }
  2823. .feedback_row textarea {
  2824. padding: 5px;
  2825. height: 50px;
  2826. }
  2827. .feedback_row .feedback-footer span {
  2828. font-size: 11px;
  2829. }
  2830. .feedback_row button {
  2831. width: 130px;
  2832. align-self: flex-end;
  2833. }
  2834.  
  2835. .user-profile-wrapper {
  2836. cursor: pointer;
  2837. }
  2838. .user-profile-wrapper > * {
  2839. cursor: default;
  2840. }
  2841.  
  2842. .textarea-container {
  2843. position: relative;
  2844. width: 100%;
  2845. }
  2846. .textarea-container textarea {
  2847. width: 100%;
  2848. height: 120px;
  2849. resize: none;
  2850. }
  2851. .char-counter {
  2852. position: absolute;
  2853. bottom: 5px;
  2854. right: 5px;
  2855. color: gray;
  2856. }
  2857.  
  2858. /* couldn't find any good name... */
  2859. .____modAlert {
  2860. position: fixed;
  2861. top: 80px;
  2862. left: 50%;
  2863. transform: translate(-50%, -50%);
  2864. z-index: 99995;
  2865. background: #3F3F3F;
  2866. border-radius: 10px;
  2867. display: flex;
  2868. flex-direction: column;
  2869. padding: 10px;
  2870. color: #fff;
  2871. }
  2872. `
  2873. },
  2874. respawnTime: Date.now(),
  2875. respawnCooldown: 1000,
  2876. move(cx, cy) {
  2877. const mouseMoveEvent = new MouseEvent("mousemove", { clientX: cx, clientY: cy });
  2878. const canvas = document.querySelector("canvas");
  2879. canvas.dispatchEvent(mouseMoveEvent);
  2880. },
  2881.  
  2882. async game() {
  2883. const { fillRect, fillText, strokeText, moveTo, arc, drawImage } = CanvasRenderingContext2D.prototype;
  2884.  
  2885. const byId = (id) => document.getElementById(id);
  2886.  
  2887. const mapColor = byId("mapColor");
  2888. const nameColor = byId("nameColor");
  2889. const borderColor = byId("borderColor");
  2890. const foodColor = byId("foodColor");
  2891. const cellColor = byId("cellColor");
  2892. const gradientNameColor1 = byId("gradientNameColor1");
  2893. const gradientNameColor2 = byId("gradientNameColor2");
  2894.  
  2895. const mapColorReset = byId("mapColorReset");
  2896. const nameColorReset = byId("nameColorReset");
  2897. const borderColorReset = byId("borderColorReset");
  2898. const foodColorReset = byId("foodColorReset");
  2899. const cellColorReset = byId("cellColorReset");
  2900. const gradientColorReset1 = byId("gradientColorReset1");
  2901. const gradientColorReset2 = byId("gradientColorReset2");
  2902.  
  2903. const showPosition = document.getElementById("showPosition");
  2904. if (showPosition && !showPosition.checked) showPosition.click();
  2905.  
  2906. let disabledGColors = 0;
  2907. const reset = (type) => {
  2908. const white = "#ffffff";
  2909. switch (type) {
  2910. case 'map':
  2911. modSettings.mapColor = null;
  2912. mapColor.value = white;
  2913. break;
  2914. case 'name':
  2915. modSettings.nameColor = null;
  2916. nameColor.value = white;
  2917. break;
  2918. case 'gradName1':
  2919. modSettings.gradientName.color1 = null;
  2920. gradientNameColor1.value = white;
  2921. if (modSettings.gradientName.color2 === null) {
  2922. modSettings.gradientName.enabled = false;
  2923. }
  2924. break;
  2925. case 'gradName2':
  2926. modSettings.gradientName.color2 = null;
  2927. gradientNameColor2.value = white;
  2928. if (modSettings.gradientName.color1 === null) {
  2929. modSettings.gradientName.enabled = false;
  2930. }
  2931. break;
  2932. case 'border':
  2933. modSettings.borderColor = null;
  2934. borderColor.value = white;
  2935. break;
  2936. case 'food':
  2937. modSettings.foodColor = null;
  2938. foodColor.value = white;
  2939. break;
  2940. case 'cell':
  2941. modSettings.cellColor = null;
  2942. cellColor.value = white;
  2943. break;
  2944. case 'skin':
  2945. modSettings.skinImage.original = null;
  2946. modSettings.skinImage.replaceImg = null;
  2947. if (confirm("Please refresh the page to make it work. Reload?")) {
  2948. location.reload();
  2949. }
  2950. break;
  2951. case 'virus':
  2952. modSettings.virusImage = "/assets/images/viruses/2.png";
  2953. if (confirm("Please refresh the page to make it work. Reload?")) {
  2954. location.reload();
  2955. }
  2956. break;
  2957. }
  2958. updateStorage();
  2959. };
  2960.  
  2961. const loadStorage = () => {
  2962. if (modSettings.nameColor) {
  2963. nameColor.value = modSettings.nameColor;
  2964. }
  2965.  
  2966. if (modSettings.mapColor) {
  2967. mapColor.value = modSettings.mapColor;
  2968. }
  2969.  
  2970. if (modSettings.borderColor) {
  2971. borderColor.value = modSettings.borderColor;
  2972. }
  2973.  
  2974. if (modSettings.foodColor) {
  2975. foodColor.value = modSettings.foodColor;
  2976. }
  2977. if (modSettings.cellColor) {
  2978. cellColor.value = modSettings.cellColor;
  2979. }
  2980.  
  2981. if (modSettings.virusImage) {
  2982. loadVirusImage(modSettings.virusImage);
  2983. }
  2984.  
  2985. if (modSettings.skinImage.original !== null) {
  2986. loadSkinImage(modSettings.skinImage.original, modSettings.skinImage.replaceImg);
  2987. }
  2988. };
  2989.  
  2990. loadStorage();
  2991.  
  2992. mapColor.addEventListener("input", () => {
  2993. modSettings.mapColor = mapColor.value;
  2994. updateStorage();
  2995. });
  2996. nameColor.addEventListener("input", () => {
  2997. modSettings.nameColor = nameColor.value;
  2998. updateStorage();
  2999. });
  3000. gradientNameColor1.addEventListener("input", () => {
  3001. if (!modSettings.gradientName.enabled) {
  3002. modSettings.gradientName.enabled = true;
  3003. }
  3004. modSettings.gradientName.color1 = gradientNameColor1.value;
  3005. updateStorage();
  3006. });
  3007. gradientNameColor2.addEventListener("input", () => {
  3008. modSettings.gradientName.color2 = gradientNameColor2.value;
  3009. updateStorage();
  3010. });
  3011. borderColor.addEventListener("input", () => {
  3012. modSettings.borderColor = borderColor.value;
  3013. updateStorage();
  3014. });
  3015. foodColor.addEventListener("input", () => {
  3016. modSettings.foodColor = foodColor.value;
  3017. updateStorage();
  3018. });
  3019. cellColor.addEventListener("input", () => {
  3020. modSettings.cellColor = cellColor.value;
  3021. updateStorage();
  3022. });
  3023.  
  3024. mapColorReset.addEventListener("click", () => reset("map"));
  3025. borderColorReset.addEventListener("click", () => reset("border"));
  3026. nameColorReset.addEventListener("click", () => reset("name"));
  3027. gradientColorReset1.addEventListener("click", () => reset("gradName1"));
  3028. gradientColorReset2.addEventListener("click", () => reset("gradName2"));
  3029. foodColorReset.addEventListener("click", () => reset("food"));
  3030. cellColorReset.addEventListener("click", () => reset("cell"));
  3031.  
  3032. // Render new colors / images
  3033. CanvasRenderingContext2D.prototype.fillRect = function (x, y, width, height) {
  3034. if ((width + height) / 2 === (window.innerWidth + window.innerHeight) / 2) {
  3035. this.fillStyle = modSettings.mapColor;
  3036. }
  3037. fillRect.apply(this, arguments);
  3038. };
  3039.  
  3040.  
  3041. CanvasRenderingContext2D.prototype.arc = function(x, y, radius, startAngle, endAngle, anticlockwise) {
  3042. if (modSettings.fps.hideFood || modSettings.fps.fpsMode) {
  3043. if (radius <= 20) {
  3044. this.fillStyle = "transparent";
  3045. this.strokeStyle = "transparent";
  3046. }
  3047. }
  3048. if (radius >= 86) {
  3049. this.fillStyle = modSettings.cellColor;
  3050. } else if (radius <= 20 && modSettings.foodColor !== null && !modSettings.fps.fpsMode && !modSettings.fps.hideFood) {
  3051. this.fillStyle = modSettings.foodColor;
  3052. this.strokeStyle = modSettings.foodColor;
  3053. }
  3054.  
  3055. arc.apply(this, arguments);
  3056. };
  3057.  
  3058. let friend_names = this.friend_names;
  3059. let highlightFriends = this.friends_settings.highlight_friends;
  3060. let highlightColor = this.friends_settings.highlight_color;
  3061.  
  3062. CanvasRenderingContext2D.prototype.fillText = function (text, x, y) {
  3063. if (text === byId("nick").value && !modSettings.gradientName.enabled && modSettings.nameColor !== null) {
  3064. this.fillStyle = modSettings.nameColor;
  3065. }
  3066.  
  3067. if (text === byId("nick").value && modSettings.gradientName.enabled) {
  3068. const width = this.measureText(text).width;
  3069. const fontSize = 8;
  3070. const gradient = this.createLinearGradient(x - width / 2 + fontSize / 2, y, x + width / 2 - fontSize / 2, y + fontSize);
  3071.  
  3072. const color1 = modSettings.gradientName.color1 ?? "#ffffff";
  3073. const color2 = modSettings.gradientName.color2 ?? "#ffffff";
  3074.  
  3075. gradient.addColorStop(0, color1);
  3076. gradient.addColorStop(1, color2);
  3077.  
  3078. this.fillStyle = gradient;
  3079. }
  3080.  
  3081. if (text.startsWith("X:")) {
  3082. this.fillStyle = "transparent";
  3083. const currentTime = Date.now();
  3084. const [, xValue, yValue] = /X: (.*), Y: (.*)/.exec(text) || [];
  3085. if (xValue !== undefined && yValue !== undefined && modSettings.tag !== null) {
  3086. const data = { x: parseFloat(xValue), y: parseFloat(yValue) };
  3087. if (stoppos) { stoppos = false; return };
  3088. if (!dead || menuClosed()) {
  3089. if (data.x === 0 || data.y === 0) return;
  3090.  
  3091. if (dead && !minimapclear && menuClosed()) {
  3092. minimapclear = true;
  3093. stoppos = true;
  3094. activeCellX = null;
  3095. activeCellY = null;
  3096. client.send({
  3097. type: "minimap-update",
  3098. content: [null, null, null, client.id]
  3099. });
  3100. lastPos = {}; // Reset lastPos when dead
  3101. return;
  3102. }
  3103.  
  3104. if (!dead && currentTime - lastLogTime >= 500 && (lastPos.x !== data.x || lastPos.y !== data.y)) {
  3105. client.send({
  3106. type: "minimap-update",
  3107. content: [data.x, data.y, mods.nick, client.id]
  3108. });
  3109. lastPos = { ...data };
  3110. activeCellX = data.x;
  3111. activeCellY = data.y;
  3112. lastLogTime = currentTime;
  3113. }
  3114. }
  3115. }
  3116. }
  3117.  
  3118. if (modSettings.fps.removeOutlines) {
  3119. this.shadowBlur = 0;
  3120. this.shadowColor = "transparent";
  3121. }
  3122.  
  3123. if (text.length > 21 && modSettings.fps.shortLongNames || modSettings.fps.fpsMode) {
  3124. text = text.slice(0, 21) + "...";
  3125. }
  3126.  
  3127. if (/\{([^}]*)\}/.test(text)) {
  3128. const originalWidth = this.measureText(text).width;
  3129. text = text.replace(/\{([^}]*)\}/g, '');
  3130. const newWidth = this.measureText(text).width;
  3131. x += (originalWidth - newWidth) / 2;
  3132. }
  3133.  
  3134. // only for leaderboard
  3135. if (friend_names.has(text) && highlightFriends) {
  3136. this.fillStyle = highlightColor;
  3137. }
  3138.  
  3139. if (text.includes("Score") && _getScore) {
  3140. _getScore = false;
  3141. const currentScore = text.substring(6).replace(/\s/g, '');
  3142. lastScore = parseInt(currentScore, 10);
  3143. const scoreText = document.getElementById("t-myScore");
  3144. if (!scoreText) return;
  3145. scoreText.textContent = `Your score: ${lastScore}`;
  3146. }
  3147.  
  3148. return fillText.apply(this, arguments);
  3149. };
  3150.  
  3151. CanvasRenderingContext2D.prototype.strokeText = function (text, x, y) {
  3152. if (text.length > 21 && modSettings.fps.shortLongNames || modSettings.fps.fpsMode) {
  3153. text = text.slice(0, 21) + "...";
  3154. }
  3155.  
  3156. if (modSettings.fps.removeOutlines) {
  3157. this.shadowBlur = 0;
  3158. this.shadowColor = "transparent";
  3159. } else {
  3160. this.shadowBlur = 7;
  3161. this.shadowColor = '#000';
  3162. }
  3163.  
  3164. return strokeText.apply(this, arguments);
  3165. };
  3166.  
  3167. CanvasRenderingContext2D.prototype.moveTo = function (x, y) {
  3168. this.strokeStyle = modSettings.borderColor;
  3169. return moveTo.apply(this, arguments);
  3170. };
  3171.  
  3172. function loadVirusImage(img) {
  3173. const replacementVirus = new Image();
  3174. replacementVirus.src = img;
  3175. const originalDrawImage = CanvasRenderingContext2D.prototype.drawImage;
  3176.  
  3177. CanvasRenderingContext2D.prototype.drawImage = function(image, ...args) {
  3178. if (image.src && image.src.endsWith("2-min.png")) {
  3179. originalDrawImage.call(this, replacementVirus, ...args);
  3180. } else {
  3181. originalDrawImage.apply(this, arguments);
  3182. }
  3183. };
  3184. }
  3185.  
  3186. function loadSkinImage(skin, img) {
  3187. const replacementSkin = new Image();
  3188. replacementSkin.src = img;
  3189. const originalDrawImage = CanvasRenderingContext2D.prototype.drawImage;
  3190.  
  3191. CanvasRenderingContext2D.prototype.drawImage = function(image, ...args) {
  3192. if (image instanceof HTMLImageElement && image.src.includes(`${skin}.png`)) {
  3193. originalDrawImage.call(this, replacementSkin, ...args);
  3194. } else {
  3195. originalDrawImage.apply(this, arguments);
  3196. }
  3197. };
  3198. }
  3199.  
  3200. // Virus & Skin image
  3201. const virusPreview = byId("virus");
  3202. const setVirus = byId("setVirus");
  3203. const virusURL = byId("virusURL");
  3204. const openVirusModal = byId("virusImageSelect");
  3205. const closeVirusModal = byId("closeVirusModal");
  3206. const virusModal = byId("virusModal");
  3207. const resetSkin = byId("resetSkin");
  3208. const resetVirus = byId("resetVirus");
  3209.  
  3210. openVirusModal.addEventListener("click", () => {
  3211. virusModal.style.display = "flex";
  3212. });
  3213. closeVirusModal.addEventListener("click", () => {
  3214. virusModal.style.display = "none";
  3215. });
  3216.  
  3217. setVirus.addEventListener("click", () => {
  3218. modSettings.virusImage = virusURL.value;
  3219. loadVirusImage(modSettings.virusImage);
  3220. updateStorage();
  3221. virusPreview.src = modSettings.virusImage;
  3222. });
  3223.  
  3224. resetVirus.addEventListener("click", () => {
  3225. modSettings.virusImage = "/assets/images/viruses/2.png";
  3226. updateStorage();
  3227. if(confirm("Please Refresh the page to make it work. Reload?")) {
  3228. location.reload();
  3229. }
  3230. });
  3231.  
  3232. const skinPreview = byId("skinPreview");
  3233. const skinURL = byId("skinURL");
  3234. const setSkin = byId("setSkin");
  3235. const openSkinModal = byId("SkinReplaceSelect");
  3236. const closeSkinModal = byId("closeSkinModal");
  3237. const skinModal = byId("skinModal");
  3238. const originalSkin = byId("originalSkinSelect");
  3239.  
  3240. openSkinModal.addEventListener("click", () => {
  3241. skinModal.style.display = "flex";
  3242. });
  3243. closeSkinModal.addEventListener("click", () => {
  3244. skinModal.style.display = "none";
  3245. });
  3246.  
  3247. setSkin.addEventListener("click", () => {
  3248. modSettings.skinImage.original = originalSkin.value;
  3249. modSettings.skinImage.replaceImg = skinURL.value;
  3250. loadSkinImage(modSettings.skinImage.original, modSettings.skinImage.replaceImg)
  3251. updateStorage();
  3252. skinPreview.src = modSettings.skinImage.replaceImg;
  3253. });
  3254.  
  3255. resetSkin.addEventListener("click", () => {
  3256. modSettings.skinImage.original = null;
  3257. modSettings.skinImage.replaceImg = null;
  3258. updateStorage();
  3259. if(confirm("Please Refresh the page to make it work. Reload?")) {
  3260. location.reload();
  3261. }
  3262. });
  3263.  
  3264. const deathScreenPos = byId("deathScreenPos");
  3265. const deathScreen = byId("__line2");
  3266.  
  3267. const applyMargin = (position) => {
  3268. switch (position) {
  3269. case "left":
  3270. deathScreen.style.marginLeft = "0";
  3271. break;
  3272. case "right":
  3273. deathScreen.style.marginRight = "0";
  3274. break;
  3275. case "top":
  3276. deathScreen.style.marginTop = "20px";
  3277. break;
  3278. case "bottom":
  3279. deathScreen.style.marginBottom = "20px";
  3280. break;
  3281. default:
  3282. deathScreen.style.margin = "auto";
  3283. }
  3284. };
  3285.  
  3286. deathScreenPos.addEventListener("change", () => {
  3287. const selected = deathScreenPos.value;
  3288. applyMargin(selected);
  3289. modSettings.deathScreenPos = selected;
  3290. updateStorage();
  3291. });
  3292.  
  3293. const defaultPosition = modSettings.deathScreenPos || "center";
  3294.  
  3295. applyMargin(defaultPosition);
  3296. deathScreenPos.value = defaultPosition;
  3297.  
  3298. const excludedSkins = ["Traitor", "Poco", "Cuddle", "Omega", "Leon", "Impostor", "Cute", "Raptor", "Maya", "Valentine", "Cara", "Fazbear", "Freddy", "Captain"];
  3299.  
  3300. const allSkins = await fetch('https://sigmally.com/api/skins/all')
  3301. .then(response => response.json())
  3302. .then(data => {
  3303. return data.data
  3304. .filter(item => !excludedSkins.includes(item.name.replace(".png", "")))
  3305. .map(item => item.name.replace(".png", ""));
  3306. });
  3307.  
  3308. originalSkin.innerHTML = `
  3309. ${allSkins.map(skin => `<option value="${skin}">${skin}</option>`).join('')}
  3310. `;
  3311. },
  3312.  
  3313. menu() {
  3314. const mod_menu = document.createElement("div");
  3315. mod_menu.classList.add("mod_menu");
  3316. mod_menu.style.display = "none";
  3317. mod_menu.style.opacity = "0";
  3318. mod_menu.innerHTML = `
  3319. <div class="mod_menu_wrapper">
  3320. <div class="mod_menu_header">
  3321. <img src="${headerAnim}" draggable="false" class="header_img" />
  3322. <button type="button" class="modButton" id="closeBtn">
  3323. <svg width="18" height="20" viewBox="0 0 16 16" fill="#ffffff" xmlns="http://www.w3.org/2000/svg">
  3324. <path d="M1.6001 14.4L14.4001 1.59998M14.4001 14.4L1.6001 1.59998" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
  3325. </svg>
  3326. </button>
  3327. </div>
  3328. <div class="mod_menu_inner">
  3329. <div class="mod_menu_navbar">
  3330. <button class="mod_nav_btn mod_selected" id="tab_home_btn">
  3331. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/main/images/icons/home%20(1).png" />
  3332. Home
  3333. </button>
  3334. <button class="mod_nav_btn" id="tab_macros_btn">
  3335. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/main/images/icons/keyboard%20(1).png" />
  3336. Macros
  3337. </button>
  3338. <button class="mod_nav_btn" id="tab_game_btn">
  3339. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/main/images/icons/games.png" />
  3340. Game
  3341. </button>
  3342. <button class="mod_nav_btn" id="tab_name_btn">
  3343. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/836ca0f4c25fc6de2e429ee3583be5f860884a0c/images/icons/name.svg" />
  3344. Name
  3345. </button>
  3346. <button class="mod_nav_btn" id="tab_themes_btn">
  3347. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/main/images/icons/theme.png" />
  3348. Themes
  3349. </button>
  3350. <button class="mod_nav_btn" id="tab_fps_btn">
  3351. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/main/images/icons/frames-per-second.png" />
  3352. FPS
  3353. </button>
  3354. <button class="mod_nav_btn" id="tab_friends_btn">
  3355. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/main/images/icons/friends%20(1).png" />
  3356. Friends
  3357. </button>
  3358. <button class="mod_nav_btn" id="tab_info_btn">
  3359. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/main/images/icons/info.png" />
  3360. Info
  3361. </button>
  3362. </div>
  3363. <div class="mod_menu_content">
  3364. <div class="mod_tab" id="mod_home">
  3365. <span class="text-center f-big" id="welcomeUser">Welcome ${this.Username}, to the SigMod Client!</span>
  3366. <div class="justify-sb">
  3367. <div class="mod_player-stats">
  3368. <span class="justify-sb">Your stats:</span>
  3369. <div class="player-stats-grid">
  3370. <div class="player-stat">
  3371. <span>Time played</span>
  3372. <span id="stat-time-played">0h 0m</span>
  3373. </div>
  3374. <div class="player-stat">
  3375. <span>Highest Mass</span>
  3376. <span id="stat-highest-mass">0</span>
  3377. </div>
  3378. <div class="player-stat">
  3379. <span>Total deaths</span>
  3380. <span id="stat-total-deaths">0</span>
  3381. </div>
  3382. <div class="player-stat">
  3383. <span>Total Mass</span>
  3384. <span id="stat-total-mass">0</span>
  3385. </div>
  3386. </div>
  3387. </div>
  3388. <div id="randomVid"></div>
  3389. </div>
  3390. <div class="justify-sb" style="gap: 18px;">
  3391. <div class="f-column w-100" style="gap: 5px;">
  3392. <span>Quick access</span>
  3393. <div class="quickAccess scroll" id="mod_qaccess"></div>
  3394. </div>
  3395. <div class="modProfileWrapper">
  3396. <span>Mod profile</span>
  3397. <div class="modUserProfile">
  3398. <div class="justify-sb">
  3399. <div class="flex" style="align-items: center; gap: 5px;">
  3400. <img src="https://sigmally.com/assets/images/agario-profile.png" width="50" height="50" id="my-profile-img" style="border-radius: 50%;" draggable="false" />
  3401. <span id="my-profile-name">Guest</span>
  3402. </div>
  3403. <span id="my-profile-role">Guest</span>
  3404. </div>
  3405. <hr />
  3406. <span id="my-profile-bio" class="scroll">No Bio.</span>
  3407. </div>
  3408. </div>
  3409. </div>
  3410. </div>
  3411. <div class="mod_tab scroll" id="mod_macros" style="display: none">
  3412. <div class="modColItems">
  3413. <div class="macros_wrapper">
  3414. <span class="text-center">Keybindings</span>
  3415. <hr style="border-color: #3F3F3F">
  3416. <div style="justify-content: center;">
  3417. <div class="f-column g-10" style="align-items: center; justify-content: center;">
  3418. <div class="macrosContainer">
  3419. <div class="f-column g-10">
  3420. <label class="macroRow">
  3421. <span class="text">Rapid Feed</span>
  3422. <input type="text" name="rapidFeed" id="modinput1" class="keybinding" value="${modSettings.keyBindings.rapidFeed}" maxlength="1" onfocus="this.select()" placeholder="..." />
  3423. </label>
  3424. <label class="macroRow">
  3425. <span class="text">Double Split</span>
  3426. <input type="text" name="doubleSplit" id="modinput2" class="keybinding" value="${modSettings.keyBindings.doubleSplit}" maxlength="1" onfocus="this.select()" placeholder="..." />
  3427. </label>
  3428. <label class="macroRow">
  3429. <span class="text">Triple Split</span>
  3430. <input type="text" name="tripleSplit" id="modinput3" class="keybinding" value="${modSettings.keyBindings.tripleSplit}" maxlength="1" onfocus="this.select()" placeholder="..." />
  3431. </label>
  3432. </div>
  3433. <div class="f-column g-10">
  3434. <label class="macroRow">
  3435. <span class="text">Quad Split</span>
  3436. <input type="text" name="quadSplit" id="modinput4" class="keybinding" value="${modSettings.keyBindings.quadSplit}" maxlength="1" onfocus="this.select()" placeholder="..." />
  3437. </label>
  3438. <label class="macroRow">
  3439. <span class="text">Freeze Player</span>
  3440. <input type="text" name="freezePlayer" id="modinput5" class="keybinding" value="${modSettings.keyBindings.freezePlayer}" maxlength="1" onfocus="this.select()" placeholder="..." />
  3441. </label>
  3442. <label class="macroRow">
  3443. <span class="text">Vertical Line</span>
  3444. <input type="text" name="verticalSplit" id="modinput8" class="keybinding" value="${modSettings.keyBindings.verticalSplit}" maxlength="1" onfocus="this.select()" placeholder="..." />
  3445. </label>
  3446. </div>
  3447. </div>
  3448. <label class="macroRow">
  3449. <span class="text">Toggle Menu</span>
  3450. <input type="text" name="toggleMenu" id="modinput6" class="keybinding" value="${modSettings.keyBindings.toggleMenu}" maxlength="1" onfocus="this.select()" placeholder="..." />
  3451. </label>
  3452. </div>
  3453. </div>
  3454. </div>
  3455. <div class="macros_wrapper">
  3456. <span class="text-center">Advanced Keybinding options</span>
  3457. <div class="setting-card-wrapper">
  3458. <div class="setting-card">
  3459. <div class="setting-card-action">
  3460. <span class="setting-card-name">Mouse macros</span>
  3461. </div>
  3462. </div>
  3463. <div class="setting-parameters" style="display: none;">
  3464. <div class="my-5">
  3465. <span class="stats-info-text">Feed or Split with mouse buttons</span>
  3466. </div>
  3467. <div class="stats-line justify-sb">
  3468. <span>Mouse Button 1 (left)</span>
  3469. <select class="form-control macro-extanded_input" style="padding: 2px; text-align: left; width: 100px" id="m1_macroSelect">
  3470. <option value="none">None</option>
  3471. <option value="fastfeed">Fast Feed</option>
  3472. <option value="split">Split (1)</option>
  3473. <option value="split2">Double Split</option>
  3474. <option value="split3">Triple Split</option>
  3475. <option value="split4">Quad Split</option>
  3476. <option value="freeze">Freeze Player</option>
  3477. <option value="dTrick">Double Trick</option>
  3478. <option value="sTrick">Self Trick</option>
  3479. </select>
  3480. </div>
  3481.  
  3482. <div class="stats-line justify-sb">
  3483. <span>Mouse Button 2 (right)</span>
  3484. <select class="form-control" style="padding: 2px; text-align: left; width: 100px" id="m2_macroSelect">
  3485. <option value="none">None</option>
  3486. <option value="fastfeed">Fast Feed</option>
  3487. <option value="split">Split (1)</option>
  3488. <option value="split2">Double Split</option>
  3489. <option value="split3">Triple Split</option>
  3490. <option value="split4">Quad Split</option>
  3491. <option value="freeze">Freeze Player</option>
  3492. <option value="dTrick">Double Trick</option>
  3493. <option value="sTrick">Self Trick</option>
  3494. </select>
  3495. </div>
  3496. </div>
  3497. </div>
  3498. <div class="setting-card-wrapper">
  3499. <div class="setting-card">
  3500. <div class="setting-card-action">
  3501. <span class="setting-card-name">Freeze Player</span>
  3502. </div>
  3503. </div>
  3504.  
  3505. <div class="setting-parameters" style="display: none;">
  3506. <div class="my-5">
  3507. <span class="stats-info-text">Freeze your player on the Map and linesplit</span>
  3508. </div>
  3509.  
  3510. <div class="stats-line justify-sb">
  3511. <span>Type of Freeze</span>
  3512. <select class="form-control" style="padding: 2px; text-align: left; width: 100px" id="freezeType">
  3513. <option value="press">Press</option>
  3514. <option value="hold">Hold</option>
  3515. </select>
  3516. </div>
  3517.  
  3518. <div class="stats-line justify-sb">
  3519. <span>Bind</span>
  3520. <input value="${modSettings.keyBindings.freezePlayer}" readonly id="modinput7" name="freezePlayer" class="form-control macro-extanded_input" onfocus="this.select();">
  3521. </div>
  3522. </div>
  3523. </div>
  3524. <div class="setting-card-wrapper">
  3525. <div class="setting-card">
  3526. <div class="setting-card-action">
  3527. <span class="setting-card-name">Toggle Settings</span>
  3528. </div>
  3529. </div>
  3530.  
  3531. <div class="setting-parameters" style="display: none;">
  3532. <div class="my-5">
  3533. <span class="stats-info-text">Toggle settings with a keybind.</span>
  3534. </div>
  3535.  
  3536. <div class="stats-line justify-sb">
  3537. <span>Toggle Names</span>
  3538. <input value="${modSettings.keyBindings.toggleNames || ""}" placeholder="..." readonly id="modinput11" name="toggleNames" class="keybinding" onfocus="this.select();">
  3539. </div>
  3540.  
  3541. <div class="stats-line justify-sb">
  3542. <span>Toggle Skins</span>
  3543. <input value="${modSettings.keyBindings.toggleSkins || ""}" placeholder="..." readonly id="modinput12" name="toggleSkins" class="keybinding" onfocus="this.select();">
  3544. </div>
  3545.  
  3546. <div class="stats-line justify-sb">
  3547. <span>Toggle Autorespawn</span>
  3548. <input value="${modSettings.keyBindings.toggleAutoRespawn || ""}" placeholder="..." readonly id="modinput13" name="toggleAutoRespawn" class="keybinding" onfocus="this.select();">
  3549. </div>
  3550. </div>
  3551. </div>
  3552. <div class="setting-card-wrapper">
  3553. <div class="setting-card">
  3554. <div class="setting-card-action">
  3555. <span class="setting-card-name">Tricksplits</span>
  3556. </div>
  3557. </div>
  3558. <div class="setting-parameters" style="display: none;">
  3559. <div class="my-5">
  3560. <span class="stats-info-text">Other split options</span>
  3561. </div>
  3562. <div class="stats-line justify-sb">
  3563. <span>Double Trick</span>
  3564. <input value="${modSettings.keyBindings.doubleTrick || ""}" placeholder="..." readonly id="modinput14" name="doubleTrick" class="keybinding" onfocus="this.select();">
  3565. </div>
  3566. <div class="stats-line justify-sb">
  3567. <span>Self Trick</span>
  3568. <input value="${modSettings.keyBindings.selfTrick || ""}" placeholder="..." readonly id="modinput15" name="selfTrick" class="keybinding" onfocus="this.select();">
  3569. </div>
  3570. </div>
  3571. </div>
  3572. </div>
  3573. </div>
  3574. </div>
  3575. <div class="mod_tab scroll" id="mod_game" style="display: none">
  3576. <div class="modColItems">
  3577. <div class="modRowItems">
  3578. <div class="modItem">
  3579. <span class="text">Map Color</span>
  3580. <div class="centerXY">
  3581. <input type="color" value="#ffffff" id="mapColor" class="colorInput" />
  3582. <button class="resetButton" id="mapColorReset"></button>
  3583. </div>
  3584. </div>
  3585. <div class="modItem">
  3586. <span class="text">Border Colors</span>
  3587. <div class="centerXY">
  3588. <input type="color" value="#ffffff" id="borderColor" class="colorInput" />
  3589. <button class="resetButton" id="borderColorReset"></button>
  3590. </div>
  3591. </div>
  3592. <div class="modItem">
  3593. <span class="text">Food color</span>
  3594. <div class="centerXY">
  3595. <input type="color" value="#ffffff" id="foodColor" class="colorInput" />
  3596. <button class="resetButton" id="foodColorReset"></button>
  3597. </div>
  3598. </div>
  3599. <div class="modItem">
  3600. <span class="text">Cell color</span>
  3601. <div class="centerXY">
  3602. <input type="color" value="#ffffff" id="cellColor" class="colorInput" />
  3603. <button class="resetButton" id="cellColorReset"></button>
  3604. </div>
  3605. </div>
  3606. </div>
  3607. <div class="modRowItems">
  3608. <div class="modItem">
  3609. <span class="text">Virus Image</span>
  3610. <div class="centerXY" style="margin-top: 5px">
  3611. <button class="btn select-btn" id="virusImageSelect"></button>
  3612. </div>
  3613. </div>
  3614. <div class="modItem">
  3615. <span class="text">Replace Skins</span>
  3616. <div class="centerXY" style="margin-top: 5px">
  3617. <button class="btn select-btn" id="SkinReplaceSelect"></button>
  3618. </div>
  3619. </div>
  3620. </div>
  3621. <div class="modRowItems justify-sb">
  3622. <span class="text">Death screen Position</span>
  3623. <select id="deathScreenPos" class="form-control" style="width: 30%">
  3624. <option value="center" selected>Center</option>
  3625. <option value="left">Left</option>
  3626. <option value="right">Right</option>
  3627. <option value="top">Top</option>
  3628. <option value="bottom">Bottom</option>
  3629. </select>
  3630. </div>
  3631. <div class="modRowItems justify-sb">
  3632. <span class="text">Play timer</span>
  3633. <div class="modCheckbox">
  3634. <input id="playTimerToggle" type="checkbox" />
  3635. <label class="cbx" for="playTimerToggle"></label>
  3636. </div>
  3637. </div>
  3638. <div class="modRowItems justify-sb">
  3639. <span class="text">Reset settings: </span>
  3640. <button class="modButton-secondary" id="resetModSettings" type="button">Reset mod settings</button>
  3641. <button class="modButton-secondary" id="resetGameSettings" type="button">Reset game settings</button>
  3642. </div>
  3643. </div>
  3644. </div>
  3645.  
  3646. <div class="mod-small-modal" id="virusModal" style="display: none;">
  3647. <div class="mod-small-modal-header">
  3648. <h1>Virus Image</h1>
  3649. <button class="ctrl-modal__close" id="closeVirusModal">
  3650. <svg width="22" height="24" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
  3651. <path d="M1.6001 14.4L14.4001 1.59998M14.4001 14.4L1.6001 1.59998" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
  3652. </svg>
  3653. </button>
  3654. </div>
  3655. <hr>
  3656. <div class="mod-small-modal-content">
  3657. <div class="mod-small-modal-content_selectImage">
  3658. <div class="flex" style="gap: 5px;">
  3659. <input type="text" class="modInput" placeholder="Virus Image URL" id="virusURL" value="${virusImgVal()}" />
  3660. <button class="modButton" id="setVirus">Apply</button>
  3661. </div>
  3662. </div>
  3663. <button class="modButton" id="resetVirus" style="align-self: start; margin-top: 5px;">Reset</button>
  3664. <img src="${modSettings.virusImage}" class="previmg" id="virus" draggable="false" >
  3665. </div>
  3666. </div>
  3667. <div class="mod-small-modal" id="skinModal" style="display: none;">
  3668. <div class="mod-small-modal-header">
  3669. <h1>Skin Replacement</h1>
  3670. <button class="ctrl-modal__close" id="closeSkinModal">
  3671. <svg width="22" height="24" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
  3672. <path d="M1.6001 14.4L14.4001 1.59998M14.4001 14.4L1.6001 1.59998" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
  3673. </svg>
  3674. </button>
  3675. </div>
  3676. <hr>
  3677. <div class="mod-small-modal-content">
  3678. <div class="mod-small-modal-content_selectImage">
  3679. <div class="centerXY" style="gap: 5px;">
  3680. <span>Original Skin: </span>
  3681. <select class="form-control" style="padding: 2px; text-align: left; width: fit-content" id="originalSkinSelect"></select>
  3682. </div>
  3683. <span style="text-align: center">Will be replaced with...</span>
  3684. <div class="flex" style="gap: 5px;">
  3685. <input type="text" class="modInput" placeholder="Skin Image URL" id="skinURL" value="${skinImgVal()}"/>
  3686. <button class="modButton" id="setSkin">Apply</button>
  3687. </div>
  3688. </div>
  3689. <button class="modButton" id="resetSkin" style="align-self: start; margin-top: 5px;">Reset</button>
  3690. <img src="" class="previmg" id="skinPreview" draggable="false" >
  3691. </div>
  3692. </div>
  3693. <div class="mod_tab scroll" id="mod_name" style="display: none">
  3694. <div class="modColItems">
  3695. <div class="modRowItems justify-sb" style="align-items: start;">
  3696. <div class="f-column g-5" style="align-items: start; justify-content: start;">
  3697. <span class="modTitleText">Name fonts & special characters</span>
  3698. <span class="modDescText">Customize your name with special characters or fonts</span>
  3699. </div>
  3700. <div class="f-column g-5">
  3701. <button class="modButton-secondary" onclick="window.open('https://nickfinder.com', '_blank')">Nickfinder</button>
  3702. <button class="modButton-secondary" onclick="window.open('https://www.stylishnamemaker.com', '_blank')">Stylish Name</button>
  3703. <button class="modButton-secondary" onclick="window.open('https://www.tell.wtf', '_blank')">Tell.wtf</button>
  3704. </div>
  3705. </div>
  3706. <div class="modRowItems justify-sb">
  3707. <div class="f-column g-5">
  3708. <span class="modTitleText">Save names</span>
  3709. <span class="modDescText">Save your names local</span>
  3710. <div class="flex g-5">
  3711. <input class="modInput" placeholder="Enter a name..." id="saveNameValue" />
  3712. <button id="saveName" class="modButton-secondary f-big" style="border-radius: 5px; background: url('https://sigmally.com/assets/images/icon/plus.svg'); background-color: #111; background-size: 50% auto; background-repeat: no-repeat; background-position: center;"></button>
  3713. </div>
  3714. <div id="savedNames" class="f-column scroll"></div>
  3715. </div>
  3716. <div class="vr"></div>
  3717. <div class="f-column g-5">
  3718. <span class="modTitleText">Name Color</span>
  3719. <span class="modDescText">Customize your name color</span>
  3720. <div class="justify-sb">
  3721. <input type="color" value="#ffffff" id="nameColor" class="colorInput">
  3722. <button class="resetButton" id="nameColorReset"></button>
  3723. </div>
  3724. <span class="modTitleText">Gradient Name</span>
  3725. <span class="modDescText">Customize your name with a gradient color</span>
  3726. <div class="justify-sb">
  3727. <div class="flex g-2" style="align-items: center">
  3728. <input type="color" value="#ffffff" id="gradientNameColor1" class="colorInput">
  3729. <span>➜ First color</span>
  3730. </div>
  3731. <button class="resetButton" id="gradientColorReset1"></button>
  3732. </div>
  3733. <div class="justify-sb">
  3734. <div class="flex g-2" style="align-items: center">
  3735. <input type="color" value="#ffffff" id="gradientNameColor2" class="colorInput">
  3736. <span>➜ Second color</span>
  3737. </div>
  3738. <button class="resetButton" id="gradientColorReset2"></button>
  3739. </div>
  3740. </div>
  3741. </div>
  3742. </div>
  3743. </div>
  3744. <div class="mod_tab scroll" id="mod_themes" style="display: none">
  3745. <div class="themes scroll" id="themes">
  3746. <div class="theme" id="createTheme">
  3747. <div class="themeContent" style="background: url('https://sigmally.com/assets/images/icon/plus.svg'); background-size: 50% auto; background-repeat: no-repeat; background-position: center;"></div>
  3748. <div class="themeName text" style="color: #fff">Create</div>
  3749. </div>
  3750. </div>
  3751. </div>
  3752. <div class="mod_tab scroll" id="mod_fps" style="display: none">
  3753. <div class="modRowItems justify-sb">
  3754. <span>FPS Mode [Beta]</span>
  3755. <div class="modCheckbox">
  3756. <input id="fpsMode" type="checkbox" />
  3757. <label class="cbx" for="fpsMode"></label>
  3758. </div>
  3759. </div>
  3760. <span class="text-center">Custom FPS Settings</span>
  3761. <div class="modRowItems justify-sb">
  3762. <span>Hide Food</span>
  3763. <div class="modCheckbox">
  3764. <input id="fps-hideFood" class="fpsCheckbox" type="checkbox" />
  3765. <label class="cbx" for="fps-hideFood"></label>
  3766. </div>
  3767. </div>
  3768. <div class="modRowItems justify-sb">
  3769. <span>Show Names</span>
  3770. <div class="modCheckbox">
  3771. <input id="fps-remNames" class="fpsCheckbox" type="checkbox" checked />
  3772. <label class="cbx" for="fps-remNames"></label>
  3773. </div>
  3774. </div>
  3775. <div class="modRowItems justify-sb">
  3776. <span>Shorten long names</span>
  3777. <div class="modCheckbox">
  3778. <input id="fps-shortenLongNames" class="fpsCheckbox" type="checkbox" />
  3779. <label class="cbx" for="fps-shortenLongNames"></label>
  3780. </div>
  3781. </div>
  3782. <div class="modRowItems justify-sb">
  3783. <span>Remove text shadows</span>
  3784. <div class="modCheckbox">
  3785. <input id="fps-remOutlines" class="fpsCheckbox" type="checkbox" />
  3786. <label class="cbx" for="fps-remOutlines"></label>
  3787. </div>
  3788. </div>
  3789. </div>
  3790. <div class="mod_tab scroll centerXY" id="mod_friends" style="display: none">
  3791. <center class="f-big" style="margin-top: 10px;">Connect and discover new friends with SigMod.</center>
  3792. <center style="margin-top: 10px; font-size: 12px;">Do you have problems with your account? Create a support ticket in our <a href="https://discord.gg/RjxeZ2eRGg" target="_blank">Discord server</a>.</center>
  3793.  
  3794. <div class="centerXY f-column g-5" style="height: 300px; width: 165px;">
  3795. <button class="modButton-black" id="createAccount">
  3796. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="16"><path fill="#ffffff" d="M471.6 21.7c-21.9-21.9-57.3-21.9-79.2 0L362.3 51.7l97.9 97.9 30.1-30.1c21.9-21.9 21.9-57.3 0-79.2L471.6 21.7zm-299.2 220c-6.1 6.1-10.8 13.6-13.5 21.9l-29.6 88.8c-2.9 8.6-.6 18.1 5.8 24.6s15.9 8.7 24.6 5.8l88.8-29.6c8.2-2.7 15.7-7.4 21.9-13.5L437.7 172.3 339.7 74.3 172.4 241.7zM96 64C43 64 0 107 0 160V416c0 53 43 96 96 96H352c53 0 96-43 96-96V320c0-17.7-14.3-32-32-32s-32 14.3-32 32v96c0 17.7-14.3 32-32 32H96c-17.7 0-32-14.3-32-32V160c0-17.7 14.3-32 32-32h96c17.7 0 32-14.3 32-32s-14.3-32-32-32H96z"/></svg>
  3797. Create account
  3798. </button>
  3799. <button class="modButton-black" id="login">
  3800. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="16"><path fill="#ffffff" d="M217.9 105.9L340.7 228.7c7.2 7.2 11.3 17.1 11.3 27.3s-4.1 20.1-11.3 27.3L217.9 406.1c-6.4 6.4-15 9.9-24 9.9c-18.7 0-33.9-15.2-33.9-33.9l0-62.1L32 320c-17.7 0-32-14.3-32-32l0-64c0-17.7 14.3-32 32-32l128 0 0-62.1c0-18.7 15.2-33.9 33.9-33.9c9 0 17.6 3.6 24 9.9zM352 416l64 0c17.7 0 32-14.3 32-32l0-256c0-17.7-14.3-32-32-32l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64 0c53 0 96 43 96 96l0 256c0 53-43 96-96 96l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32z"/></svg>
  3801. Login
  3802. </button>
  3803. </div>
  3804. </div>
  3805. <div class="mod_tab scroll f-column g-5 text-center" id="mod_info" style="display: none">
  3806. <div class="brand_wrapper">
  3807. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/6f1ed65927f50ebc4ef71dbbefaa68fcb220d83f/images/stackedwaves.svg" class="brand_img" />
  3808. <span style="font-size: 24px; z-index: 2;">SigMod V${version} by Cursed</span>
  3809. </div>
  3810. <span style="font-size: 20px; margin-top: 5px;">Thanks to</span>
  3811. <span class="brand_credits">Ultra, Black, 8y8x, Dreamz, Xaris, Benzofury</span>
  3812. <button class="modButton p_s_n" onclick="window.open('https://github.com/Sigmally/SigMod/blob/main/privacy_security.md')">Privacy and Security notice</button>
  3813. <div class="userId_wrapper">
  3814. <span id="userId" title="Your user ID">User ID (login to see)</span>
  3815. <span class="userId_copy" id="copyUserId">
  3816. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
  3817. <path d="M208 0H332.1c12.7 0 24.9 5.1 33.9 14.1l67.9 67.9c9 9 14.1 21.2 14.1 33.9V336c0 26.5-21.5 48-48 48H208c-26.5 0-48-21.5-48-48V48c0-26.5 21.5-48 48-48zM48 128h80v64H64V448H256V416h64v48c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V176c0-26.5 21.5-48 48-48z" fill="white" />
  3818. </svg>
  3819. </span>
  3820. </div>
  3821. <div class="brand_yt">
  3822. <div class="yt_wrapper" onclick="window.open('https://www.youtube.com/@sigmallyCursed')">
  3823. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="30" height="30">
  3824. <path d="M12 39c-.549 0-1.095-.15-1.578-.447A3.008 3.008 0 0 1 9 36V12c0-1.041.54-2.007 1.422-2.553a3.014 3.014 0 0 1 2.919-.132l24 12a3.003 3.003 0 0 1 0 5.37l-24 12c-.42.21-.885.315-1.341.315z" fill="#ffffff"></path>
  3825. </svg>
  3826. <span style="font-size: 12px;">Cursed - Sigmally</span>
  3827. </div>
  3828. <div class="yt_wrapper" onclick="window.open('https://www.youtube.com/@sigmally')">
  3829. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="30" height="30">
  3830. <path d="M12 39c-.549 0-1.095-.15-1.578-.447A3.008 3.008 0 0 1 9 36V12c0-1.041.54-2.007 1.422-2.553a3.014 3.014 0 0 1 2.919-.132l24 12a3.003 3.003 0 0 1 0 5.37l-24 12c-.42.21-.885.315-1.341.315z" fill="#ffffff"></path>
  3831. </svg>
  3832. <span style="font-size: 15px;">Sigmally</span>
  3833. </div>
  3834. </div>
  3835. </div>
  3836. </div>
  3837. </div>
  3838. </div>
  3839. `;
  3840. document.body.append(mod_menu);
  3841. this.getSettings();
  3842. this.auth();
  3843.  
  3844. mod_menu.addEventListener("click", (e) => {
  3845. const wrapper = document.querySelector(".mod_menu_wrapper");
  3846.  
  3847. if (wrapper && wrapper.contains(e.target)) return;
  3848.  
  3849. mod_menu.style.opacity = 0;
  3850. setTimeout(() => {
  3851. mod_menu.style.display = "none";
  3852. }, 300);
  3853. });
  3854.  
  3855. function openModTab(tabId) {
  3856. const allTabs = document.getElementsByClassName("mod_tab");
  3857. const allTabButtons = document.querySelectorAll(".mod_nav_btn");
  3858.  
  3859. for (const tab of allTabs) {
  3860. tab.style.opacity = 0;
  3861. setTimeout(() => {
  3862. tab.style.display = "none";
  3863. }, 200);
  3864. }
  3865.  
  3866. allTabButtons.forEach(tabBtn => tabBtn.classList.remove("mod_selected"));
  3867.  
  3868. const selectedTab = document.getElementById(tabId);
  3869. setTimeout(() => {
  3870. selectedTab.style.display = "flex";
  3871. setTimeout(() => {
  3872. selectedTab.style.opacity = 1;
  3873. }, 10);
  3874. }, 200);
  3875. this.classList.add("mod_selected");
  3876. }
  3877.  
  3878.  
  3879. document.querySelectorAll(".mod_nav_btn").forEach(tabBtn => {
  3880. tabBtn.addEventListener("click", function() {
  3881. openModTab.call(this, this.id.replace("tab_", "mod_").replace("_btn", ""));
  3882. });
  3883. });
  3884.  
  3885. const videoList = [
  3886. "c-_KP3Ti2vQ?si=PHj2aNye5Uj_yXY9",
  3887. "IdBXpxmxYpU?si=4-fZWJUpewLG7c8H",
  3888. "xCUtce1D9f0?si=ybsNDCUL1M1WnuLc",
  3889. "B9LOJQOVH_Q?si=5qJPAxMT_EvFNW8Y",
  3890. "emLjRdTWm5A?si=4suR21ZEb-zmy1RD",
  3891. "190DhVhom5c?si=3TfghIX-u_wsBpR2",
  3892. "t_6L9G13vK8?si=wbiiT78h6RQUgPOd",
  3893. "B--KgGV7XMM?si=GkYtJ5ueks676_J9",
  3894. "Sq2UqzBO_IQ?si=ETvsFSueAwvl8Frm",
  3895. "OsO48zwyLfw?si=plItxN8vhFZbLAf8"
  3896. ];
  3897.  
  3898. function getrdmVid() {
  3899. const randomIndex = Math.floor(Math.random() * videoList.length);
  3900. return videoList[randomIndex];
  3901. }
  3902.  
  3903. const randomVid = document.getElementById("randomVid");
  3904. randomVid.style = "align-self: start";
  3905. randomVid.innerHTML = `
  3906. <iframe width="300" height="200" style="border-radius: 10px; box-shadow: 0 0 10px -2px #000;" src="https://www.youtube.com/embed/${getrdmVid()}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
  3907. `;
  3908.  
  3909. const openMenu = document.querySelectorAll("#clans_and_settings button")[1];
  3910. openMenu.removeAttribute("onclick");
  3911. openMenu.addEventListener("click", () => {
  3912. mod_menu.style.display = "flex";
  3913. setTimeout(() => {
  3914. mod_menu.style.opacity = 1;
  3915. }, 10);
  3916. });
  3917.  
  3918. const closeModal = document.getElementById("closeBtn");
  3919. closeModal.addEventListener("click", () => {
  3920. mod_menu.style.opacity = 0;
  3921. setTimeout(() => {
  3922. mod_menu.style.display = "none";
  3923. }, 300);
  3924. });
  3925.  
  3926. function virusImgVal() {
  3927. if(modSettings.virusImage === "/assets/images/viruses/2.png" || modSettings.virusImage === "") return "";
  3928. return modSettings.virusImage;
  3929. }
  3930. function skinImgVal() {
  3931. if(modSettings.skinImage.replaceImg === "" || modSettings.skinImage.replaceImg === null) return "";
  3932. return modSettings.skinImage.replaceImg;
  3933. }
  3934.  
  3935. setTimeout(() => {
  3936. const authorized = Boolean(unsafeWindow.gameSettings.user);
  3937. const user = unsafeWindow.gameSettings.user || null;
  3938.  
  3939. fetch(this.appRoutes.user, {
  3940. method: 'POST',
  3941. headers: {
  3942. 'Content-Type': 'application/json',
  3943. 'Accept': 'application/json'
  3944. },
  3945. body: JSON.stringify({
  3946. authorized,
  3947. user,
  3948. nick: this.nick,
  3949. }),
  3950. })
  3951. .then((res) => res.ok ? res.json() : Promise.reject('Server error'))
  3952. .then((data) => data && data.banned ? this.banned() : null)
  3953. .catch((error) => console.error('Error during fetch:', error));
  3954. }, 7000);
  3955.  
  3956. const playTimerToggle = document.getElementById("playTimerToggle");
  3957. playTimerToggle.addEventListener("change", () => {
  3958. modSettings.playTimer = playTimerToggle.checked;
  3959. updateStorage();
  3960. });
  3961. if (modSettings.playTimer) {
  3962. playTimerToggle.checked = true;
  3963. }
  3964.  
  3965. const resetModSettings = document.getElementById("resetModSettings");
  3966. resetModSettings.addEventListener("click", () => {
  3967. if (confirm("Are you sure you want to reset the mod settings? A reload is required.")) {
  3968. this.removeStorage(storageName);
  3969. location.reload();
  3970. }
  3971. });
  3972.  
  3973. const resetGameSettings = document.getElementById("resetGameSettings");
  3974. resetGameSettings.addEventListener("click", () => {
  3975. if (confirm("Are you sure you want to reset the game settings? Your nick and more settings will be lost. A reload is required.")) {
  3976. unsafeWindow.settings.gameSettings = null;
  3977. this.removeStorage("settings");
  3978. location.reload();
  3979. }
  3980. });
  3981. },
  3982.  
  3983. setProfile(user) {
  3984. const img = document.getElementById("my-profile-img");
  3985. const name = document.getElementById("my-profile-name");
  3986. const role = document.getElementById("my-profile-role");
  3987. const bioText = document.getElementById("my-profile-bio");
  3988. const userId = document.getElementById("userId");
  3989.  
  3990. userId.innerText = user._id;
  3991. const copyUserId = document.getElementById("copyUserId");
  3992. copyUserId.addEventListener("click", () => {
  3993. navigator.clipboard.writeText(userId.innerText);
  3994. });
  3995.  
  3996. const bio = user.bio ? user.bio : "No bio.";
  3997.  
  3998. img.src = user.imageURL;
  3999. name.innerText = user.username;
  4000. role.innerText = user.role;
  4001. bioText.innerHTML = bio;
  4002.  
  4003. role.classList.add(`${user.role}_role`);
  4004.  
  4005. const tournament = location.href.endsWith("/tournament/");
  4006. if (!tournament) return;
  4007. client.send({
  4008. type: "online",
  4009. content: unsafeWindow.gameSettings.user._id,
  4010. });
  4011. },
  4012.  
  4013. getSettings() {
  4014. const mod_qaccess = document.querySelector("#mod_qaccess");
  4015. const settingsGrid = document.querySelector("#settings > .checkbox-grid");
  4016. const settingsNames = settingsGrid.querySelectorAll("label:not([class])");
  4017. const inputs = settingsGrid.querySelectorAll("input");
  4018.  
  4019. inputs.forEach((checkbox, index) => {
  4020. if (checkbox.id === "showChat" || checkbox.id === "showMinimap") return;
  4021. const modrow = document.createElement("div");
  4022. modrow.classList.add("justify-sb", "p-2");
  4023.  
  4024. if (checkbox.id === "showPosition" || checkbox.id === "showNames") {
  4025. modrow.style.display = "none";
  4026. }
  4027.  
  4028. modrow.innerHTML = `
  4029. <span>${settingsNames[index].textContent}</span>
  4030. <div class="modCheckbox" id="${checkbox.id}_wrapper"></div>
  4031. `;
  4032. mod_qaccess.append(modrow);
  4033.  
  4034. const cbWrapper = document.getElementById(`${checkbox.id}_wrapper`);
  4035. cbWrapper.appendChild(checkbox);
  4036.  
  4037. cbWrapper.appendChild(
  4038. Object.assign(document.createElement("label"), {
  4039. classList: ['cbx'],
  4040. htmlFor: checkbox.id
  4041. })
  4042. );
  4043. });
  4044. },
  4045.  
  4046. Themes() {
  4047. const elements = [
  4048. "#menu",
  4049. "#title",
  4050. ".top-users__inner",
  4051. "#left-menu",
  4052. ".menu-links",
  4053. ".menu--stats-mode",
  4054. "#left_ad_block",
  4055. "#ad_bottom",
  4056. ".ad-block",
  4057. "#left_ad_block > .right-menu",
  4058. "#text-block > .right-menu"
  4059. ];
  4060.  
  4061. const themeEditor = document.createElement("div");
  4062. themeEditor.classList.add("themeEditor");
  4063. themeEditor.style.display = "none";
  4064.  
  4065. themeEditor.innerHTML = `
  4066. <div class="theme_editor_header">
  4067. <h3>Theme Editor</h3>
  4068. <button class="btn CloseBtn" id="closeThemeEditor">
  4069. <svg width="22" height="20" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
  4070. <path d="M1.6001 14.4L14.4001 1.59998M14.4001 14.4L1.6001 1.59998" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
  4071. </svg>
  4072. </button>
  4073. </div>
  4074. <hr />
  4075. <main class="theme_editor_content">
  4076. <div class="centerXY" style="justify-content: flex-end;gap: 10px">
  4077. <span class="text">Select Theme Type: </span>
  4078. <select class="form-control" style="background: #222; color: #fff; width: 150px" id="theme-type-select">
  4079. <option>Static Color</option>
  4080. <option>Gradient</option>
  4081. <option>Image / Gif</option>
  4082. </select>
  4083. </div>
  4084.  
  4085. <div id="theme_editor_color" class="theme-editor-tab">
  4086. <div class="centerXY">
  4087. <label for="theme-editor-bgcolorinput" class="text">Background color:</label>
  4088. <input type="color" value="#000000" class="colorInput whiteBorder_colorInput" id="theme-editor-bgcolorinput"/>
  4089. </div>
  4090. <div class="centerXY">
  4091. <label for="theme-editor-colorinput" class="text">Text color:</label>
  4092. <input type="color" value="#000000" class="colorInput whiteBorder_colorInput" id="theme-editor-colorinput"/>
  4093. </div>
  4094. <div style="background-color: #000000" class="themes_preview" id="color_preview">
  4095. <span class="text" style="color: #fff; font-size: 9px;">preview</span>
  4096. </div>
  4097. <div class="centerY" style="gap: 10px; margin-top: 10px;">
  4098. <input type="text" class="form-control" style="background: #222; color: #fff;" maxlength="15" placeholder="Theme name..." id="colorThemeName"/>
  4099. <button class="btn btn-success" id="saveColorTheme">Save</button>
  4100. </div>
  4101. </div>
  4102.  
  4103.  
  4104. <div id="theme_editor_gradient" class="theme-editor-tab" style="display: none;">
  4105. <div class="centerXY">
  4106. <label for="theme-editor-gcolor1" class="text">Color 1:</label>
  4107. <input type="color" value="#000000" class="colorInput whiteBorder_colorInput" id="theme-editor-gcolor1"/>
  4108. </div>
  4109. <div class="centerXY">
  4110. <label for="theme-editor-g_color" class="text">Color 2:</label>
  4111. <input type="color" value="#ffffff" class="colorInput whiteBorder_colorInput" id="theme-editor-g_color"/>
  4112. </div>
  4113. <div class="centerXY">
  4114. <label for="theme-editor-gcolor2" class="text">Text Color:</label>
  4115. <input type="color" value="#ffffff" class="colorInput whiteBorder_colorInput" id="theme-editor-gcolor2"/>
  4116. </div>
  4117.  
  4118. <div class="centerXY" style="gap: 10px">
  4119. <label for="gradient-type" class="text">Gradient Type:</label>
  4120. <select id="gradient-type" class="form-control" style="background: #222; color: #fff; width: 120px;">
  4121. <option value="linear">Linear</option>
  4122. <option value="radial">Radial</option>
  4123. </select>
  4124. </div>
  4125.  
  4126. <div id="theme-editor-gradient_angle" class="centerY" style="gap: 10px; width: 100%">
  4127. <label for="g_angle" class="text" id="gradient_angle_text" style="width: 115px;">Angle (0deg):</label>
  4128. <input type="range" id="g_angle" value="0" min="0" max="360">
  4129. </div>
  4130.  
  4131. <div style="background: linear-gradient(0deg, #000, #fff)" class="themes_preview" id="gradient_preview">
  4132. <span class="text" style="color: #fff; font-size: 9px;">preview</span>
  4133. </div>
  4134. <div class="centerY" style="gap: 10px; margin-top: 10px;">
  4135. <input type="text" class="form-control" style="background: #222; color: #fff;" placeholder="Theme name..." id="GradientThemeName"/>
  4136. <button class="btn btn-success" id="saveGradientTheme">Save</button>
  4137. </div>
  4138. </div>
  4139.  
  4140.  
  4141.  
  4142. <div id="theme_editor_image" class="theme-editor-tab" style="display: none">
  4143. <div class="centerXY">
  4144. <input type="text" id="theme-editor-imagelink" placeholder="Image / GIF URL (https://i.ibb.co/k6hn4v0/Galaxy-Example.png)" class="form-control" style="background: #222; color: #fff"/>
  4145. </div>
  4146. <div class="centerXY" style="margin: 5px; gap: 5px;">
  4147. <label for="theme-editor-textcolorImage" class="text">Text Color: </label>
  4148. <input type="color" class="colorInput whiteBorder_colorInput" value="#ffffff" id="theme-editor-textcolorImage"/>
  4149. </div>
  4150.  
  4151. <div style="background: url('https://i.ibb.co/k6hn4v0/Galaxy-Example.png'); background-position: center; background-size: cover;" class="themes_preview" id="image_preview">
  4152. <span class="text" style="color: #fff; font-size: 9px;">preview</span>
  4153. </div>
  4154. <div class="centerY" style="gap: 10px; margin-top: 10px;">
  4155. <input type="text" class="form-control" style="background: #222; color: #fff;" placeholder="Theme name..." id="imageThemeName"/>
  4156. <button class="btn btn-success" id="saveImageTheme">Save</button>
  4157. </div>
  4158. </div>
  4159. </main>
  4160. `;
  4161.  
  4162. document.body.append(themeEditor);
  4163.  
  4164. setTimeout(() => {
  4165. document.querySelectorAll(".stats-btn__share-btn")[1].querySelector("rect").remove();
  4166.  
  4167. const themeTypeSelect = document.getElementById("theme-type-select");
  4168. const colorTab = document.getElementById("theme_editor_color");
  4169. const gradientTab = document.getElementById("theme_editor_gradient");
  4170. const imageTab = document.getElementById("theme_editor_image");
  4171. const gradientAngleDiv = document.getElementById("theme-editor-gradient_angle");
  4172.  
  4173. themeTypeSelect.addEventListener("change", function() {
  4174. const selectedOption = themeTypeSelect.value;
  4175. switch (selectedOption) {
  4176. case "Static Color":
  4177. colorTab.style.display = "flex";
  4178. gradientTab.style.display = "none";
  4179. imageTab.style.display = "none";
  4180. break;
  4181. case "Gradient":
  4182. colorTab.style.display = "none";
  4183. gradientTab.style.display = "flex";
  4184. imageTab.style.display = "none";
  4185. break;
  4186. case "Image / Gif":
  4187. colorTab.style.display = "none";
  4188. gradientTab.style.display = "none";
  4189. imageTab.style.display = "flex";
  4190. break;
  4191. default:
  4192. colorTab.style.display = "flex";
  4193. gradientTab.style.display = "none";
  4194. imageTab.style.display = "none";
  4195. }
  4196. });
  4197.  
  4198. const colorInputs = document.querySelectorAll("#theme_editor_color .colorInput");
  4199. colorInputs.forEach(input => {
  4200. input.addEventListener("input", function() {
  4201. const bgColorInput = document.getElementById("theme-editor-bgcolorinput").value;
  4202. const textColorInput = document.getElementById("theme-editor-colorinput").value;
  4203.  
  4204. applyColorTheme(bgColorInput, textColorInput);
  4205. });
  4206. });
  4207.  
  4208. const gradientInputs = document.querySelectorAll("#theme_editor_gradient .colorInput");
  4209. gradientInputs.forEach(input => {
  4210. input.addEventListener("input", function() {
  4211. const gColor1 = document.getElementById("theme-editor-gcolor1").value;
  4212. const gColor2 = document.getElementById("theme-editor-g_color").value;
  4213. const gTextColor = document.getElementById("theme-editor-gcolor2").value;
  4214. const gAngle = document.getElementById("g_angle").value;
  4215. const gradientType = document.getElementById("gradient-type").value;
  4216.  
  4217. applyGradientTheme(gColor1, gColor2, gTextColor, gAngle, gradientType);
  4218. });
  4219. });
  4220.  
  4221. const imageInputs = document.querySelectorAll("#theme_editor_image .colorInput");
  4222. imageInputs.forEach(input => {
  4223. input.addEventListener("input", function() {
  4224. const imageLinkInput = document.getElementById("theme-editor-imagelink").value;
  4225. const textColorImageInput = document.getElementById("theme-editor-textcolorImage").value;
  4226.  
  4227. let img;
  4228. if(imageLinkInput == "") {
  4229. img = "https://i.ibb.co/k6hn4v0/Galaxy-Example.png"
  4230. } else {
  4231. img = imageLinkInput;
  4232. }
  4233. applyImageTheme(img, textColorImageInput);
  4234. });
  4235. });
  4236. const image_preview = document.getElementById("image_preview");
  4237. const image_link = document.getElementById("theme-editor-imagelink");
  4238.  
  4239. let isWriting = false;
  4240. let timeoutId;
  4241.  
  4242. image_link.addEventListener("input", () => {
  4243. if (!isWriting) {
  4244. isWriting = true;
  4245. } else {
  4246. clearTimeout(timeoutId);
  4247. }
  4248.  
  4249. timeoutId = setTimeout(() => {
  4250. const imageLinkInput = image_link.value;
  4251. const textColorImageInput = document.getElementById("theme-editor-textcolorImage").value;
  4252.  
  4253. let img;
  4254. if (imageLinkInput === "") {
  4255. img = "https://i.ibb.co/k6hn4v0/Galaxy-Example.png";
  4256. } else {
  4257. img = imageLinkInput;
  4258. }
  4259.  
  4260. applyImageTheme(img, textColorImageInput);
  4261. isWriting = false;
  4262. }, 1000);
  4263. });
  4264.  
  4265.  
  4266. const gradientTypeSelect = document.getElementById("gradient-type");
  4267. const angleInput = document.getElementById("g_angle");
  4268.  
  4269. gradientTypeSelect.addEventListener("change", function() {
  4270. const selectedType = gradientTypeSelect.value;
  4271. gradientAngleDiv.style.display = selectedType === "linear" ? "flex" : "none";
  4272.  
  4273. const gColor1 = document.getElementById("theme-editor-gcolor1").value;
  4274. const gColor2 = document.getElementById("theme-editor-g_color").value;
  4275. const gTextColor = document.getElementById("theme-editor-gcolor2").value;
  4276. const gAngle = document.getElementById("g_angle").value;
  4277.  
  4278. applyGradientTheme(gColor1, gColor2, gTextColor, gAngle, selectedType);
  4279. });
  4280.  
  4281. angleInput.addEventListener("input", function() {
  4282. const gradient_angle_text = document.getElementById("gradient_angle_text");
  4283. gradient_angle_text.innerText = `Angle (${angleInput.value}deg): `;
  4284. const gColor1 = document.getElementById("theme-editor-gcolor1").value;
  4285. const gColor2 = document.getElementById("theme-editor-g_color").value;
  4286. const gTextColor = document.getElementById("theme-editor-gcolor2").value;
  4287. const gAngle = document.getElementById("g_angle").value;
  4288. const gradientType = document.getElementById("gradient-type").value;
  4289.  
  4290. applyGradientTheme(gColor1, gColor2, gTextColor, gAngle, gradientType);
  4291. });
  4292.  
  4293. function applyColorTheme(bgColor, textColor) {
  4294. const previewDivs = document.querySelectorAll("#theme_editor_color .themes_preview");
  4295. previewDivs.forEach(previewDiv => {
  4296. previewDiv.style.backgroundColor = bgColor;
  4297. const textSpan = previewDiv.querySelector("span.text");
  4298. textSpan.style.color = textColor;
  4299. });
  4300. }
  4301.  
  4302. function applyGradientTheme(gColor1, gColor2, gTextColor, gAngle, gradientType) {
  4303. const previewDivs = document.querySelectorAll("#theme_editor_gradient .themes_preview");
  4304. previewDivs.forEach(previewDiv => {
  4305. const gradient = gradientType === "linear"
  4306. ? `linear-gradient(${gAngle}deg, ${gColor1}, ${gColor2})`
  4307. : `radial-gradient(circle, ${gColor1}, ${gColor2})`;
  4308. previewDiv.style.background = gradient;
  4309. const textSpan = previewDiv.querySelector("span.text");
  4310. textSpan.style.color = gTextColor;
  4311. });
  4312. }
  4313.  
  4314. function applyImageTheme(imageLink, textColor) {
  4315. const previewDivs = document.querySelectorAll("#theme_editor_image .themes_preview");
  4316. previewDivs.forEach(previewDiv => {
  4317. previewDiv.style.backgroundImage = `url('${imageLink}')`;
  4318. const textSpan = previewDiv.querySelector("span.text");
  4319. textSpan.style.color = textColor;
  4320. });
  4321. }
  4322.  
  4323.  
  4324.  
  4325. const createTheme = document.getElementById("createTheme");
  4326. createTheme.addEventListener("click", () => {
  4327. themeEditor.style.display = "block";
  4328. });
  4329.  
  4330. const closeThemeEditor = document.getElementById("closeThemeEditor");
  4331. closeThemeEditor.addEventListener("click", () => {
  4332. themeEditor.style.display = "none";
  4333. });
  4334.  
  4335. let themesDiv = document.getElementById("themes")
  4336.  
  4337. const saveColorThemeBtn = document.getElementById("saveColorTheme");
  4338. const saveGradientThemeBtn = document.getElementById("saveGradientTheme");
  4339. const saveImageThemeBtn = document.getElementById("saveImageTheme");
  4340.  
  4341. saveColorThemeBtn.addEventListener("click", () => {
  4342. const name = document.getElementById("colorThemeName").value;
  4343. const bgColorInput = document.getElementById("theme-editor-bgcolorinput").value;
  4344. const textColorInput = document.getElementById("theme-editor-colorinput").value;
  4345.  
  4346. if(name == "") return
  4347.  
  4348. const theme = {
  4349. name: name,
  4350. background: bgColorInput,
  4351. text: textColorInput
  4352. };
  4353.  
  4354. const themeCard = document.createElement("div");
  4355. themeCard.classList.add("theme");
  4356. let themeBG;
  4357. if (theme.background.includes("http")) {
  4358. themeBG = `background: url(${theme.background})`;
  4359. } else {
  4360. themeBG = `background: ${theme.background}`;
  4361. }
  4362. themeCard.innerHTML = `
  4363. <div class="themeContent" style="${themeBG}; background-size: cover; background-position: center"></div>
  4364. <div class="themeName text" style="color: #fff">${theme.name}</div>
  4365. `;
  4366.  
  4367. themeCard.addEventListener("click", () => {
  4368. toggleTheme(theme);
  4369. });
  4370.  
  4371. themeCard.addEventListener('contextmenu', (ev) => {
  4372. ev.preventDefault();
  4373. if(confirm("Do you want to delete this Theme?")) {
  4374. themeCard.remove();
  4375. const themeIndex = modSettings.addedThemes.findIndex((addedTheme) => addedTheme.name === theme.name);
  4376. if (themeIndex !== -1) {
  4377. modSettings.addedThemes.splice(themeIndex, 1);
  4378. updateStorage();
  4379. }
  4380. }
  4381. });
  4382.  
  4383. themesDiv.appendChild(themeCard);
  4384.  
  4385. modSettings.addedThemes.push(theme)
  4386. updateStorage();
  4387.  
  4388. themeEditor.style.display = "none";
  4389. themesDiv.scrollTop = themesDiv.scrollHeight;
  4390. });
  4391.  
  4392. saveGradientThemeBtn.addEventListener("click", () => {
  4393. const name = document.getElementById("GradientThemeName").value;
  4394. const gColor1 = document.getElementById("theme-editor-gcolor1").value;
  4395. const gColor2 = document.getElementById("theme-editor-g_color").value;
  4396. const gTextColor = document.getElementById("theme-editor-gcolor2").value;
  4397. const gAngle = document.getElementById("g_angle").value;
  4398. const gradientType = document.getElementById("gradient-type").value;
  4399.  
  4400. if(name == "") return
  4401.  
  4402. let gradient_radial_linear = () => {
  4403. if(gradientType == "linear") {
  4404. return `${gradientType}-gradient(${gAngle}deg, ${gColor1}, ${gColor2})`
  4405. } else if (gradientType == "radial") {
  4406. return `${gradientType}-gradient(circle, ${gColor1}, ${gColor2})`
  4407. }
  4408. }
  4409. const theme = {
  4410. name: name,
  4411. background: gradient_radial_linear(),
  4412. text: gTextColor,
  4413. };
  4414.  
  4415. const themeCard = document.createElement("div");
  4416. themeCard.classList.add("theme");
  4417. let themeBG;
  4418. if (theme.background.includes("http")) {
  4419. themeBG = `background: url(${theme.background})`;
  4420. } else {
  4421. themeBG = `background: ${theme.background}`;
  4422. }
  4423. themeCard.innerHTML = `
  4424. <div class="themeContent" style="${themeBG}; background-size: cover; background-position: center"></div>
  4425. <div class="themeName text" style="color: #fff">${theme.name}</div>
  4426. `;
  4427.  
  4428. themeCard.addEventListener("click", () => {
  4429. toggleTheme(theme);
  4430. });
  4431.  
  4432. themeCard.addEventListener('contextmenu', (ev) => {
  4433. ev.preventDefault();
  4434. if(confirm("Do you want to delete this Theme?")) {
  4435. themeCard.remove();
  4436. const themeIndex = modSettings.addedThemes.findIndex((addedTheme) => addedTheme.name === theme.name);
  4437. if (themeIndex !== -1) {
  4438. modSettings.addedThemes.splice(themeIndex, 1);
  4439. updateStorage();
  4440. }
  4441. }
  4442. });
  4443.  
  4444. themesDiv.appendChild(themeCard);
  4445.  
  4446. modSettings.addedThemes.push(theme)
  4447. updateStorage();
  4448.  
  4449. themeEditor.style.display = "none";
  4450. themesDiv.scrollTop = themesDiv.scrollHeight;
  4451. });
  4452.  
  4453. saveImageThemeBtn.addEventListener("click", () => {
  4454. const name = document.getElementById("imageThemeName").value;
  4455. const imageLink = document.getElementById("theme-editor-imagelink").value;
  4456. const textColorImageInput = document.getElementById("theme-editor-textcolorImage").value;
  4457.  
  4458. if(name == "" || imageLink == "") return
  4459.  
  4460. const theme = {
  4461. name: name,
  4462. background: imageLink,
  4463. text: textColorImageInput
  4464. };
  4465.  
  4466. const themeCard = document.createElement("div");
  4467. themeCard.classList.add("theme");
  4468. let themeBG;
  4469. if (theme.background.includes("http")) {
  4470. themeBG = `background: url(${theme.background})`;
  4471. } else {
  4472. themeBG = `background: ${theme.background}`;
  4473. }
  4474. themeCard.innerHTML = `
  4475. <div class="themeContent" style="${themeBG}; background-size: cover; background-position: center"></div>
  4476. <div class="themeName text" style="color: #fff">${theme.name}</div>
  4477. `;
  4478.  
  4479. themeCard.addEventListener("click", () => {
  4480. toggleTheme(theme);
  4481. });
  4482.  
  4483. themeCard.addEventListener('contextmenu', (ev) => {
  4484. ev.preventDefault();
  4485. if(confirm("Do you want to delete this Theme?")) {
  4486. themeCard.remove();
  4487. const themeIndex = modSettings.addedThemes.findIndex((addedTheme) => addedTheme.name === theme.name);
  4488. if (themeIndex !== -1) {
  4489. modSettings.addedThemes.splice(themeIndex, 1);
  4490. updateStorage();
  4491. }
  4492. }
  4493. });
  4494.  
  4495. themesDiv.appendChild(themeCard);
  4496.  
  4497. modSettings.addedThemes.push(theme)
  4498. updateStorage();
  4499.  
  4500. themeEditor.style.display = "none";
  4501. themesDiv.scrollTop = themesDiv.scrollHeight;
  4502. });
  4503. });
  4504.  
  4505. const b_inner = document.querySelector(".body__inner");
  4506. let bodyColorElements = b_inner.querySelectorAll(
  4507. ".body__inner > :not(.body__inner), #s-skin-select-icon-text"
  4508. );
  4509.  
  4510. const toggleColor = (element, background, text) => {
  4511. let image = `url("${background}")`;
  4512. if (background.includes("http")) {
  4513. element.style.background = image;
  4514. element.style.backgroundPosition = "center";
  4515. element.style.backgroundSize = "cover";
  4516. element.style.backgroundRepeat = "no-repeat";
  4517. } else {
  4518. element.style.background = background;
  4519. element.style.backgroundRepeat = "no-repeat";
  4520. }
  4521. element.style.color = text;
  4522. };
  4523.  
  4524. const openSVG = document.querySelector("#clans_and_settings > Button > svg");
  4525. const openSVGPath = document.querySelector("#clans_and_settings > Button > svg > path");
  4526. const newPath = openSVG.setAttribute("fill", "#fff")
  4527. openSVG.setAttribute("width", "36")
  4528. openSVG.setAttribute("height", "36")
  4529.  
  4530. const toggleTheme = (theme) => {
  4531. if (theme.text === "#FFFFFF") {
  4532. openSVGPath.setAttribute("fill", "#fff")
  4533. } else {
  4534. openSVG.setAttribute("fill", "#222");
  4535. }
  4536.  
  4537. const backgroundColor = theme.background;
  4538. const textColor = theme.text;
  4539.  
  4540. elements.forEach(selector => {
  4541. const el = document.querySelector(selector);
  4542. if (selector === "#title") {
  4543. el.style.color = textColor;
  4544. } else {
  4545. toggleColor(el, backgroundColor, textColor);
  4546. }
  4547. });
  4548.  
  4549. bodyColorElements.forEach((element) => {
  4550. element.style.color = textColor;
  4551. });
  4552.  
  4553. modSettings.Theme = theme.name;
  4554. updateStorage();
  4555. };
  4556.  
  4557. const themes = {
  4558. defaults: [
  4559. {
  4560. name: "Dark",
  4561. background: "#151515",
  4562. text: "#FFFFFF"
  4563. },
  4564. {
  4565. name: "White",
  4566. background: "#ffffff",
  4567. text: "#000000"
  4568. },
  4569. ],
  4570. orderly: [
  4571. {
  4572. name: "THC",
  4573. background: "linear-gradient(160deg, #9BEC7A, #117500)",
  4574. text: "#000000"
  4575. },
  4576. {
  4577. name: "4 AM",
  4578. background: "linear-gradient(160deg, #8B0AE1, #111)",
  4579. text: "#FFFFFF"
  4580. },
  4581. {
  4582. name: "OTO",
  4583. background: "linear-gradient(160deg, #A20000, #050505)",
  4584. text: "#FFFFFF"
  4585. },
  4586. {
  4587. name: "Gaming",
  4588. background: "https://i.ibb.co/DwKkQfh/BG-1-lower-quality.jpg",
  4589. text: "#FFFFFF"
  4590. },
  4591. {
  4592. name: "Shapes",
  4593. background: "https://i.ibb.co/h8TmVyM/BG-2.png",
  4594. text: "#FFFFFF"
  4595. },
  4596. {
  4597. name: "Blue",
  4598. background: "https://i.ibb.co/9yQBfWj/BG-3.png",
  4599. text: "#FFFFFF"
  4600. },
  4601. {
  4602. name: "Blue - 2",
  4603. background: "https://i.ibb.co/7RJvNCX/BG-4.png",
  4604. text: "#FFFFFF"
  4605. },
  4606. {
  4607. name: "Purple",
  4608. background: "https://i.ibb.co/vxY15Tv/BG-5.png",
  4609. text: "#FFFFFF"
  4610. },
  4611. {
  4612. name: "Orange Blue",
  4613. background: "https://i.ibb.co/99nfFBN/BG-6.png",
  4614. text: "#FFFFFF"
  4615. },
  4616. {
  4617. name: "Gradient",
  4618. background: "https://i.ibb.co/hWMLwLS/BG-7.png",
  4619. text: "#FFFFFF"
  4620. },
  4621. {
  4622. name: "Sky",
  4623. background: "https://i.ibb.co/P4XqDFw/BG-9.png",
  4624. text: "#000000"
  4625. },
  4626. {
  4627. name: "Sunset",
  4628. background: "https://i.ibb.co/0BVbYHC/BG-10.png",
  4629. text: "#FFFFFF"
  4630. },
  4631. {
  4632. name: "Galaxy",
  4633. background: "https://i.ibb.co/MsssDKP/Galaxy.png",
  4634. text: "#FFFFFF"
  4635. },
  4636. {
  4637. name: "Planet",
  4638. background: "https://i.ibb.co/KLqWM32/Planet.png",
  4639. text: "#FFFFFF"
  4640. },
  4641. {
  4642. name: "colorful",
  4643. background: "https://i.ibb.co/VqtB3TX/colorful.png",
  4644. text: "#FFFFFF"
  4645. },
  4646. {
  4647. name: "Sunset - 2",
  4648. background: "https://i.ibb.co/TLp2nvv/Sunset.png",
  4649. text: "#FFFFFF"
  4650. },
  4651. {
  4652. name: "Epic",
  4653. background: "https://i.ibb.co/kcv4tvn/Epic.png",
  4654. text: "#FFFFFF"
  4655. },
  4656. {
  4657. name: "Galaxy - 2",
  4658. background: "https://i.ibb.co/smRs6V0/galaxy.png",
  4659. text: "#FFFFFF"
  4660. },
  4661. {
  4662. name: "Cloudy",
  4663. background: "https://i.ibb.co/MCW7Bcd/cloudy.png",
  4664. text: "#000000"
  4665. },
  4666. ]
  4667. };
  4668.  
  4669. function createThemeCard(theme) {
  4670. const themeCard = document.createElement("div");
  4671. themeCard.classList.add("theme");
  4672. let themeBG;
  4673. if (theme.background.includes("http")) {
  4674. themeBG = `background: url(${theme.background})`;
  4675. } else {
  4676. themeBG = `background: ${theme.background}`;
  4677. }
  4678. themeCard.innerHTML = `
  4679. <div class="themeContent" style="${themeBG}; background-size: cover; background-position: center"></div>
  4680. <div class="themeName text" style="color: #fff">${theme.name}</div>
  4681. `;
  4682.  
  4683. themeCard.addEventListener("click", () => {
  4684. toggleTheme(theme);
  4685. });
  4686.  
  4687. if (modSettings.addedThemes.includes(theme)) {
  4688. themeCard.addEventListener('contextmenu', (ev) => {
  4689. ev.preventDefault();
  4690. if (confirm("Do you want to delete this Theme?")) {
  4691. themeCard.remove();
  4692. const themeIndex = modSettings.addedThemes.findIndex((addedTheme) => addedTheme.name === theme.name);
  4693. if (themeIndex !== -1) {
  4694. modSettings.addedThemes.splice(themeIndex, 1);
  4695. updateStorage();
  4696. }
  4697. }
  4698. }, false);
  4699. }
  4700.  
  4701. return themeCard;
  4702. }
  4703.  
  4704. const themesContainer = document.getElementById("themes");
  4705.  
  4706. themes.defaults.forEach((theme) => {
  4707. const themeCard = createThemeCard(theme);
  4708. themesContainer.append(themeCard);
  4709. });
  4710.  
  4711. const orderlyThemes = [...themes.orderly, ...modSettings.addedThemes];
  4712. orderlyThemes.sort((a, b) => a.name.localeCompare(b.name));
  4713. orderlyThemes.forEach((theme) => {
  4714. const themeCard = createThemeCard(theme);
  4715. themesContainer.appendChild(themeCard);
  4716. });
  4717.  
  4718.  
  4719. const savedTheme = modSettings.Theme;
  4720. if (savedTheme) {
  4721. let selectedTheme;
  4722. selectedTheme = themes.defaults.find((theme) => theme.name === savedTheme);
  4723. if (!selectedTheme) {
  4724. selectedTheme = themes.orderly.find((theme) => theme.name === savedTheme) || modSettings.addedThemes.find((theme) => theme.name === savedTheme);
  4725. }
  4726.  
  4727. if (selectedTheme) {
  4728. toggleTheme(selectedTheme);
  4729. }
  4730. }
  4731. },
  4732.  
  4733. chat() {
  4734. // disable old chat
  4735. setTimeout(() => {
  4736. const showChat = document.querySelector('#showChat');
  4737. if (showChat && showChat.checked) {
  4738. showChat.click();
  4739. }
  4740. if (showChat) {
  4741. showChat.remove();
  4742. }
  4743. }, 500);
  4744.  
  4745. // If someone uninstalls the mod, the chat is visible again
  4746. window.addEventListener("beforeunload", () => {
  4747. localStorage.setItem("settings", JSON.stringify({ ...JSON.parse(localStorage.getItem("settings")), showChat: true }));
  4748. });
  4749.  
  4750. const chatDiv = document.createElement("div");
  4751. chatDiv.classList.add("modChat");
  4752. chatDiv.innerHTML = `
  4753. <div class="modChat__inner">
  4754. <button id="scroll-down-btn" class="modButton">↓</button>
  4755. <div class="modchat-chatbuttons">
  4756. <button class="chatButton" id="mainchat">Main</button>
  4757. <button class="chatButton" id="partychat">Party</button>
  4758. <span class="tagText"></span>
  4759. </div>
  4760. <div id="mod-messages" class="scroll"></div>
  4761. <div id="chatInputContainer">
  4762. <input type="text" id="chatSendInput" class="chatInput" placeholder="message..." maxlength="250" minlength="1" />
  4763. <button class="chatButton" id="openChatSettings">
  4764. <svg width="15" height="15" viewBox="0 0 20 20" fill="#fff" xmlns="http://www.w3.org/2000/svg">
  4765. <path d="M17.4249 7.45169C15.7658 7.45169 15.0874 6.27836 15.9124 4.83919C16.3891 4.00503 16.1049 2.94169 15.2708 2.46503L13.6849 1.55753C12.9608 1.12669 12.0258 1.38336 11.5949 2.10753L11.4941 2.28169C10.6691 3.72086 9.31242 3.72086 8.47825 2.28169L8.37742 2.10753C7.96492 1.38336 7.02992 1.12669 6.30575 1.55753L4.71992 2.46503C3.88575 2.94169 3.60158 4.01419 4.07825 4.84836C4.91242 6.27836 4.23408 7.45169 2.57492 7.45169C1.62159 7.45169 0.833252 8.23086 0.833252 9.19336V10.8067C0.833252 11.76 1.61242 12.5484 2.57492 12.5484C4.23408 12.5484 4.91242 13.7217 4.07825 15.1609C3.60158 15.995 3.88575 17.0584 4.71992 17.535L6.30575 18.4425C7.02992 18.8734 7.96492 18.6167 8.39575 17.8925L8.49658 17.7184C9.32158 16.2792 10.6783 16.2792 11.5124 17.7184L11.6133 17.8925C12.0441 18.6167 12.9791 18.8734 13.7033 18.4425L15.2891 17.535C16.1233 17.0584 16.4074 15.9859 15.9307 15.1609C15.0966 13.7217 15.7749 12.5484 17.4341 12.5484C18.3874 12.5484 19.1758 11.7692 19.1758 10.8067V9.19336C19.1666 8.24003 18.3874 7.45169 17.4249 7.45169ZM9.99992 12.9792C8.35908 12.9792 7.02075 11.6409 7.02075 10C7.02075 8.35919 8.35908 7.02086 9.99992 7.02086C11.6408 7.02086 12.9791 8.35919 12.9791 10C12.9791 11.6409 11.6408 12.9792 9.99992 12.9792Z" fill="#fff"></path>
  4766. </svg>
  4767. </button>
  4768. <button class="chatButton" id="openEmojiMenu">😎</button>
  4769. <button id="sendButton" class="chatButton">
  4770. Send
  4771. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/main/images/send.svg" width="20" height="20" draggable="false"/>
  4772. </button>
  4773. </div>
  4774. </div>
  4775. `;
  4776. document.body.append(chatDiv);
  4777.  
  4778. const chatContainer = document.getElementById("mod-messages");
  4779. const scrollDownButton = document.getElementById("scroll-down-btn");
  4780.  
  4781. chatContainer.addEventListener("scroll", () => {
  4782. if (chatContainer.scrollHeight - chatContainer.scrollTop > 300) {
  4783. scrollDownButton.style.display = "block";
  4784. }
  4785. if (chatContainer.scrollHeight - chatContainer.scrollTop < 299 && scrollDownButton.style.display === "block") {
  4786. scrollDownButton.style.display = "none";
  4787. }
  4788. });
  4789.  
  4790. scrollDownButton.addEventListener("click", () => {
  4791. chatContainer.scrollTop = chatContainer.scrollHeight;
  4792. });
  4793.  
  4794. const messageCount = chatContainer.children.length;
  4795. const messageLimit = modSettings.chatSettings.limit;
  4796. if (messageCount > messageLimit) {
  4797. const messagesToRemove = messageCount - messageLimit;
  4798. for (let i = 0; i < messagesToRemove; i++) {
  4799. chatContainer.removeChild(chatContainer.firstChild);
  4800. }
  4801. }
  4802.  
  4803. const main = document.getElementById("mainchat");
  4804. const party = document.getElementById("partychat");
  4805. main.addEventListener("click", () => {
  4806. if (modSettings.chatSettings.showClientChat) {
  4807. document.getElementById("mod-messages").innerHTML = "";
  4808. modSettings.chatSettings.showClientChat = false;
  4809. updateStorage();
  4810. }
  4811. });
  4812. party.addEventListener("click", () => {
  4813. if (!modSettings.chatSettings.showClientChat) {
  4814. modSettings.chatSettings.showClientChat = true;
  4815. updateStorage();
  4816. }
  4817. const modMessages = document.getElementById("mod-messages");
  4818. if (!modSettings.tag) {
  4819. modMessages.innerHTML = `
  4820. <div class="message">
  4821. <span>
  4822. <span style="color: #5a44eb" class="message_name">[SERVER]</span>: You need to be in a tag to use the SigMod party chat.
  4823. </span>
  4824. </div>
  4825. `;
  4826. } else {
  4827. modMessages.innerHTML = `
  4828. <div class="message">
  4829. <span>
  4830. <span style="color: #5a44eb" class="message_name">[SERVER]</span>: Welcome to the SigMod party chat!
  4831. </span>
  4832. </div>
  4833. `;
  4834. }
  4835. });
  4836.  
  4837. if (modSettings.chatSettings.showClientChat) {
  4838. const modMessages = document.getElementById("mod-messages");
  4839. if (modMessages.children.length > 1) return;
  4840. modMessages.innerHTML = `
  4841. <div class="message">
  4842. <span>
  4843. <span style="color: #5a44eb" class="message_name">[SERVER]</span>: Welcome to the SigMod party chat!
  4844. </span>
  4845. </div>
  4846. `;
  4847. }
  4848.  
  4849.  
  4850. const text = document.getElementById("chatSendInput");
  4851. const send = document.getElementById("sendButton");
  4852.  
  4853. send.addEventListener("click", () => {
  4854. let val = text.value;
  4855. if (val == "") return;
  4856.  
  4857. if (modSettings.chatSettings.showClientChat) {
  4858. client.send({
  4859. type: "chat-message",
  4860. content: {
  4861. name: this.nick,
  4862. message: val,
  4863. }
  4864. });
  4865. } else {
  4866. // MAX 15 CHARS PER MSG
  4867. if (val.length > 15) {
  4868. const parts = [];
  4869. for (let i = 0; i < val.length; i += 15) {
  4870. parts.push(val.substring(i, i + 15));
  4871. }
  4872.  
  4873. let index = 0;
  4874. const sendPart = () => {
  4875. if (index < parts.length) {
  4876. unsafeWindow.sendChat(parts[index]);
  4877. index++;
  4878. setTimeout(sendPart, 1000);
  4879. }
  4880. };
  4881.  
  4882. sendPart();
  4883. } else {
  4884. unsafeWindow.sendChat(val);
  4885. }
  4886. }
  4887.  
  4888. text.value = "";
  4889. text.blur();
  4890. });
  4891.  
  4892.  
  4893. this.chatSettings();
  4894. this.emojiMenu();
  4895.  
  4896.  
  4897. const chatSettingsContainer = document.querySelector(".chatSettingsContainer")
  4898. const emojisContainer = document.querySelector(".emojisContainer")
  4899.  
  4900. document.getElementById("openChatSettings").addEventListener("click", () => {
  4901. if (chatSettingsContainer.classList.contains("hidden_full")) {
  4902. chatSettingsContainer.classList.remove("hidden_full");
  4903. emojisContainer.classList.add("hidden_full");
  4904. } else {
  4905. chatSettingsContainer.classList.add("hidden_full");
  4906. }
  4907. });
  4908.  
  4909. document.getElementById("openEmojiMenu").addEventListener("click", () => {
  4910. if (emojisContainer.classList.contains("hidden_full")) {
  4911. emojisContainer.classList.remove("hidden_full");
  4912. chatSettingsContainer.classList.add("hidden_full");
  4913. } else {
  4914. emojisContainer.classList.add("hidden_full");
  4915. }
  4916. });
  4917.  
  4918.  
  4919. const scrollUpButton = document.getElementById("scroll-down-btn");
  4920. let focused = false;
  4921. let typed = false;
  4922.  
  4923. document.addEventListener("keydown", (e) => {
  4924. if (e.key === "Enter" && text.value.length > 0) {
  4925. send.click();
  4926. focused = false;
  4927. scrollUpButton.click();
  4928. } else if (e.key === "Enter") {
  4929. if (document.activeElement.tagName === "INPUT" || document.activeElement.tagName === "TEXTAREA") return;
  4930.  
  4931. focused ? text.blur() : text.focus();
  4932. focused = !focused;
  4933. }
  4934. });
  4935.  
  4936.  
  4937. text.addEventListener("input", (e) => {
  4938. typed = text.value.length > 1;
  4939. });
  4940.  
  4941. text.addEventListener("blur", (e) => {
  4942. focused = false;
  4943. });
  4944.  
  4945. text.addEventListener("keydown", (e) => {
  4946. const key = e.key.toLowerCase();
  4947. if (key == "w") {
  4948. e.stopPropagation();
  4949. }
  4950.  
  4951. if (key == " ") {
  4952. e.stopPropagation();
  4953. }
  4954. });
  4955.  
  4956.  
  4957. // switch to compact chat
  4958.  
  4959. const chatElements = [".modChat", ".emojisContainer", ".chatSettingsContainer"];
  4960.  
  4961. // modSettings.chatSettings.compact
  4962.  
  4963. const compactChat = document.getElementById("compactChat");
  4964. compactChat.addEventListener("change", () => {
  4965. if (compactChat.checked) {
  4966. compactMode();
  4967. } else {
  4968. defaultMode();
  4969. }
  4970. });
  4971.  
  4972. function compactMode() {
  4973. chatElements.forEach((querySelector) => {
  4974. const el = document.querySelector(querySelector);
  4975. if (el) {
  4976. el.classList.add("mod-compact");
  4977. }
  4978. });
  4979.  
  4980. modSettings.chatSettings.compact = true;
  4981. updateStorage();
  4982. }
  4983.  
  4984. function defaultMode() {
  4985. chatElements.forEach((querySelector) => {
  4986. const el = document.querySelector(querySelector);
  4987. if (el) {
  4988. el.classList.remove("mod-compact");
  4989. }
  4990. });
  4991. modSettings.chatSettings.compact = false;
  4992. updateStorage();
  4993. }
  4994.  
  4995. if (modSettings.chatSettings.compact) compactMode();
  4996.  
  4997. },
  4998.  
  4999. updateChat(data) {
  5000. let that = this;
  5001. let time = "";
  5002. if (data.time !== null) {
  5003. time = formatTime(data.time);
  5004. }
  5005.  
  5006. const { name, message } = data;
  5007. const color = data.color || "#ffffff";
  5008. const glow = this.friend_names.has(name) && this.friends_settings.highlight_friends ? `text-shadow: 0 1px 3px ${color}` : '';
  5009. const id = rdmString(12);
  5010.  
  5011. const chatMessage = document.createElement("div");
  5012. chatMessage.classList.add("message");
  5013.  
  5014. chatMessage.innerHTML = `
  5015. <span>
  5016. <span style="color: ${color};${glow}" class="message_name" id="${id}">${name}</span>: ${message}
  5017. </span>
  5018. <span class="time">${time}</span>
  5019. `;
  5020.  
  5021. const chatContainer = document.getElementById("mod-messages");
  5022. const isScrolledToBottom =
  5023. chatContainer.scrollHeight - chatContainer.scrollTop <= chatContainer.clientHeight + 1;
  5024. const isNearBottom = chatContainer.scrollHeight - chatContainer.scrollTop - 200 <= chatContainer.clientHeight;
  5025.  
  5026. chatContainer.append(chatMessage);
  5027.  
  5028. if (isScrolledToBottom || isNearBottom) {
  5029. if (!this.scrolling) {
  5030. this.scrolling = true;
  5031. chatContainer.scrollTop = chatContainer.scrollHeight;
  5032. this.scrolling = false;
  5033. }
  5034. }
  5035.  
  5036. if (name === "Spectator" || name == this.nick) return;
  5037.  
  5038. const nameEl = document.getElementById(id);
  5039. nameEl.addEventListener("mousedown", (e) => {
  5040. if (that.onContext) return;
  5041. if (e.button === 2) {
  5042. // Create a custom context menu
  5043. const contextMenu = document.createElement("div");
  5044. contextMenu.classList.add("chat-context");
  5045. contextMenu.innerHTML = `
  5046. <span>${name}</span>
  5047. <button id="muteButton">Mute</button>
  5048. `;
  5049.  
  5050. const contextMenuTop = e.clientY - 80;
  5051. const contextMenuLeft = e.clientX;
  5052.  
  5053. // Set the position of the context menu
  5054. contextMenu.style.top = `${contextMenuTop}px`;
  5055. contextMenu.style.left = `${contextMenuLeft}px`;
  5056.  
  5057. document.body.appendChild(contextMenu);
  5058. that.onContext = true;
  5059.  
  5060. const muteButton = document.getElementById("muteButton");
  5061. muteButton.addEventListener("click", () => {
  5062. if (confirm(`Are you sure you want to mute '${name}' until you refresh the page?`)) {
  5063. this.muteUser(name);
  5064. contextMenu.remove();
  5065. }
  5066. });
  5067.  
  5068. document.addEventListener("click", (event) => {
  5069. if (!contextMenu.contains(event.target)) {
  5070. that.onContext = false;
  5071. contextMenu.remove();
  5072. }
  5073. });
  5074. }
  5075. });
  5076.  
  5077. nameEl.addEventListener("contextmenu", (e) => {
  5078. e.preventDefault();
  5079. e.stopPropagation();
  5080. });
  5081. },
  5082.  
  5083. muteUser(name) {
  5084. this.mutedUsers.push(name);
  5085.  
  5086. const msgNames = document.querySelectorAll(".message_name");
  5087. msgNames.forEach((msgName) => {
  5088. if (msgName.innerHTML == name) {
  5089. const msgParent = msgName.closest('.message');
  5090. msgParent.remove();
  5091. }
  5092. });
  5093. },
  5094.  
  5095. emojiMenu() {
  5096. const emojisContainer = document.createElement("div");
  5097. emojisContainer.classList.add("chatAddedContainer", "emojisContainer", "hidden_full");
  5098. emojisContainer.innerHTML = `
  5099. <input type="text" class="chatInput" id="searchEmoji" style="background-color: #050505; border-radius: .5rem;" placeholder="Search..." />
  5100. <div id="categories" class="scroll"></div>
  5101. `;
  5102.  
  5103. const categoriesContainer = emojisContainer.querySelector("#categories");
  5104.  
  5105. const updateEmojis = (searchTerm) => {
  5106. categoriesContainer.innerHTML = '';
  5107.  
  5108. window.emojis.forEach(emojiData => {
  5109. const { emoji, description, category, tags } = emojiData;
  5110.  
  5111. if (tags.some(tag => tag.includes(searchTerm.toLowerCase()))) {
  5112. let categoryId = category.replace(/\s+/g, '-').replace('&', 'and').toLowerCase();
  5113. let categoryDiv = categoriesContainer.querySelector(`#${categoryId}`);
  5114. if (!categoryDiv) {
  5115. categoryDiv = document.createElement("div");
  5116. categoryDiv.id = categoryId;
  5117. categoryDiv.classList.add("category");
  5118. categoryDiv.innerHTML = `<span>${category}</span><div class="emojiContainer"></div>`;
  5119. categoriesContainer.appendChild(categoryDiv);
  5120. }
  5121.  
  5122. const emojiContainer = categoryDiv.querySelector(".emojiContainer");
  5123.  
  5124. const emojiDiv = document.createElement("div");
  5125. emojiDiv.classList.add("emoji");
  5126. emojiDiv.innerHTML = emoji;
  5127. emojiDiv.title = `${emoji} - ${description}`;
  5128. emojiDiv.addEventListener("click", () => {
  5129. const chatInput = document.querySelector("#chatSendInput");
  5130. chatInput.value += emoji;
  5131. });
  5132.  
  5133. emojiContainer.appendChild(emojiDiv);
  5134. }
  5135. });
  5136. };
  5137.  
  5138. const chatInput = emojisContainer.querySelector("#searchEmoji");
  5139. chatInput.addEventListener("input", (event) => {
  5140. const searchTerm = event.target.value.toLowerCase();
  5141. updateEmojis(searchTerm);
  5142. });
  5143.  
  5144. document.body.append(emojisContainer);
  5145.  
  5146. getEmojis().then(emojis => {
  5147. window.emojis = emojis;
  5148. updateEmojis("");
  5149. });
  5150. },
  5151.  
  5152. chatSettings() {
  5153. const menu = document.createElement("div");
  5154. menu.classList.add("chatAddedContainer", "chatSettingsContainer", "scroll", "hidden_full");
  5155. menu.innerHTML = `
  5156. <div class="modInfoPopup" style="display: none">
  5157. <p>Send location in chat with keybind</p>
  5158. </div>
  5159. <div class="scroll">
  5160. <div class="csBlock">
  5161. <div class="csBlockTitle">
  5162. <span>Keybindings</span>
  5163. </div>
  5164. <div class="csRow">
  5165. <div class="csRowName">
  5166. <span>Location</span>
  5167. <span class="infoIcon">
  5168. <svg fill="#ffffff" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 416.979 416.979" xml:space="preserve"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <path d="M356.004,61.156c-81.37-81.47-213.377-81.551-294.848-0.182c-81.47,81.371-81.552,213.379-0.181,294.85 c81.369,81.47,213.378,81.551,294.849,0.181C437.293,274.636,437.375,142.626,356.004,61.156z M237.6,340.786 c0,3.217-2.607,5.822-5.822,5.822h-46.576c-3.215,0-5.822-2.605-5.822-5.822V167.885c0-3.217,2.607-5.822,5.822-5.822h46.576 c3.215,0,5.822,2.604,5.822,5.822V340.786z M208.49,137.901c-18.618,0-33.766-15.146-33.766-33.765 c0-18.617,15.147-33.766,33.766-33.766c18.619,0,33.766,15.148,33.766,33.766C242.256,122.755,227.107,137.901,208.49,137.901z"></path> </g> </g></svg>
  5169. </span>
  5170. </div>
  5171. <input type="text" name="location" id="modinput9" class="keybinding" value="${modSettings.keyBindings.location || ""}" placeholder="..." maxlength="1" onfocus="this.select()">
  5172. </div>
  5173. <div class="csRow">
  5174. <div class="csRowName">
  5175. <span>Show / Hide</span>
  5176. </div>
  5177. <input type="text" name="toggleChat" id="modinput10" class="keybinding" value="${modSettings.keyBindings.toggleChat || ""}" placeholder="..." maxlength="1" onfocus="this.select()">
  5178. </div>
  5179. </div>
  5180. <div class="csBlock">
  5181. <div class="csBlockTitle">
  5182. <span>General</span>
  5183. </div>
  5184. <div class="csRow">
  5185. <div class="csRowName">
  5186. <span>Time</span>
  5187. </div>
  5188. <div class="modCheckbox">
  5189. <input id="showChatTime" type="checkbox" checked />
  5190. <label class="cbx" for="showChatTime"></label>
  5191. </div>
  5192. </div>
  5193. <div class="csRow">
  5194. <div class="csRowName">
  5195. <span>Name colors</span>
  5196. </div>
  5197. <div class="modCheckbox">
  5198. <input id="showNameColors" type="checkbox" checked />
  5199. <label class="cbx" for="showNameColors"></label>
  5200. </div>
  5201. </div>
  5202. <div class="csRow">
  5203. <div class="csRowName">
  5204. <span>Party / Main</span>
  5205. </div>
  5206. <div class="modCheckbox">
  5207. <input id="showPartyMain" type="checkbox" checked />
  5208. <label class="cbx" for="showPartyMain"></label>
  5209. </div>
  5210. </div>
  5211. <div class="csRow">
  5212. <div class="csRowName">
  5213. <span>Blur Tag</span>
  5214. </div>
  5215. <div class="modCheckbox">
  5216. <input id="blurTag" type="checkbox" checked />
  5217. <label class="cbx" for="blurTag"></label>
  5218. </div>
  5219. </div>
  5220. <div class="flex f-column g-5 centerXY" style="padding: 0 5px">
  5221. <div class="csRowName">
  5222. <span>Location text</span>
  5223. </div>
  5224. <input type="text" id="locationText" placeholder="{pos}..." value="{pos}" class="form-control" />
  5225. </div>
  5226. </div>
  5227. <div class="csBlock">
  5228. <div class="csBlockTitle">
  5229. <span>Style</span>
  5230. </div>
  5231. <div class="csRow">
  5232. <div class="csRowName">
  5233. <span>Compact chat</span>
  5234. </div>
  5235. <div class="modCheckbox">
  5236. <input id="compactChat" type="checkbox" ${modSettings.chatSettings.compact ? "checked" : ""} />
  5237. <label class="cbx" for="compactChat"></label>
  5238. </div>
  5239. </div>
  5240. <div class="csRow">
  5241. <div class="csRowName">
  5242. <span>Background</span>
  5243. </div>
  5244. <input type="color" class="colorInput" value="${modSettings.chatSettings.bgColor}" id="chatbgChanger" />
  5245. </div>
  5246. <div class="csRow">
  5247. <div class="csRowName">
  5248. <span>Theme</span>
  5249. </div>
  5250. <input type="color" class="colorInput" value="${modSettings.chatSettings.themeColor || "#ffffff"}" id="chatThemeChanger" />
  5251. </div>
  5252. <div class="flex f-column g-5 centerXY" style="padding: 0 5px;">
  5253. <div class="csRowName">
  5254. <span>Opacity</span>
  5255. </div>
  5256. <input type="range" class="modSlider" style="padding: 15px;" id="chat_opacity" value="${modSettings.chatSettings.chat_opacity || 0.4}" max="1" step="0.1" />
  5257. </div>
  5258. </div>
  5259. </div>
  5260. `;
  5261. document.body.append(menu);
  5262.  
  5263. const infoIcon = document.querySelector(".infoIcon");
  5264. const modInfoPopup = document.querySelector(".modInfoPopup");
  5265. let popupOpen = false;
  5266.  
  5267. infoIcon.addEventListener("click", (event) => {
  5268. event.stopPropagation();
  5269. modInfoPopup.style.display = popupOpen ? "none" : "block";
  5270. popupOpen = !popupOpen;
  5271. });
  5272.  
  5273. document.addEventListener("click", (event) => {
  5274. if (popupOpen && !modInfoPopup.contains(event.target)) {
  5275. modInfoPopup.style.display = "none";
  5276. popupOpen = false;
  5277. }
  5278. });
  5279.  
  5280. const showChatTime = document.querySelector("#showChatTime");
  5281. const showNameColors = document.querySelector("#showNameColors");
  5282.  
  5283. showChatTime.addEventListener("change", () => {
  5284. const timeElements = document.querySelectorAll(".time");
  5285. if (showChatTime.checked) {
  5286. modSettings.chatSettings.showTime = true;
  5287. updateStorage();
  5288. } else {
  5289. modSettings.chatSettings.showTime = false;
  5290. if (timeElements) {
  5291. timeElements.forEach(el => el.innerHTML="");
  5292. }
  5293. updateStorage();
  5294. }
  5295. });
  5296.  
  5297. showNameColors.addEventListener("change", () => {
  5298. const message_names = document.querySelectorAll(".message_name");
  5299. if (showNameColors.checked) {
  5300. modSettings.chatSettings.showNameColors = true;
  5301. updateStorage();
  5302. } else {
  5303. modSettings.chatSettings.showNameColors = false;
  5304. if (message_names) {
  5305. message_names.forEach(el => el.style.color="#fafafa");
  5306. }
  5307. updateStorage();
  5308. }
  5309. });
  5310.  
  5311. const bgChanger = document.querySelector("#chatbgChanger");
  5312. if (!modSettings.chatSettings.chat_opacity) {
  5313. modSettings.chatSettings.chat_opacity = 0.4;
  5314. updateStorage();
  5315. }
  5316.  
  5317. bgChanger.addEventListener("input", () => {
  5318. const hexColor = bgChanger.value;
  5319. const rgbaColor = hexToRgba(hexColor, modSettings.chatSettings.chat_opacity);
  5320. modSettings.chatSettings.bgColor = hexColor;
  5321. modChat.style.background = rgbaColor;
  5322. updateStorage();
  5323. });
  5324.  
  5325. const themeChanger = document.querySelector("#chatThemeChanger");
  5326. const chatBtns = document.querySelectorAll(".chatButton");
  5327. themeChanger.addEventListener("input", () => {
  5328. const hexColor = themeChanger.value;
  5329. modSettings.chatSettings.themeColor = hexColor;
  5330. chatBtns.forEach(btn => {
  5331. btn.style.background = hexColor;
  5332. });
  5333. updateStorage();
  5334. });
  5335.  
  5336. // remove old rgba val
  5337. if (modSettings.chatSettings.bgColor.includes("rgba")) {
  5338. modSettings.chatSettings.bgColor = RgbaToHex(modSettings.chatSettings.bgColor);
  5339. }
  5340.  
  5341. const modChat = document.querySelector(".modChat");
  5342. modChat.style.background = hexToRgba(modSettings.chatSettings.bgColor, modSettings.chatSettings.chat_opacity);
  5343. if (modSettings.chatSettings.themeColor) {
  5344. chatBtns.forEach(btn => {
  5345. btn.style.background = modSettings.chatSettings.themeColor;
  5346. });
  5347. }
  5348.  
  5349. const opacity = document.querySelector("#chat_opacity");
  5350. opacity.addEventListener("input", () => {
  5351. modSettings.chatSettings.chat_opacity = opacity.value;
  5352. updateStorage();
  5353. const rgbaColor = hexToRgba(modSettings.chatSettings.bgColor, modSettings.chatSettings.chat_opacity);
  5354. modChat.style.background = rgbaColor;
  5355. });
  5356.  
  5357. const showPartyMain = document.querySelector("#showPartyMain");
  5358. const chatHeader = document.querySelector(".modchat-chatbuttons");
  5359.  
  5360. const changeButtonsState = (show) => {
  5361. chatHeader.style.display = show ? "flex" : "none";
  5362. modChat.style.maxHeight = show ? "285px" : "250px";
  5363. modChat.style.minHeight = show ? "285px" : "250px";
  5364. const modChatInner = document.querySelector(".modChat__inner");
  5365. modChatInner.style.maxHeight = show ? "265px" : "230px";
  5366. modChatInner.style.minHeight = show ? "265px" : "230px";
  5367. }
  5368.  
  5369. showPartyMain.addEventListener("change", () => {
  5370. const show = showPartyMain.checked;
  5371. modSettings.chatSettings.showChatButtons = show;
  5372. changeButtonsState(show);
  5373. updateStorage();
  5374. });
  5375.  
  5376. showPartyMain.checked = modSettings.chatSettings.showChatButtons;
  5377. changeButtonsState(modSettings.chatSettings.showChatButtons);
  5378.  
  5379.  
  5380. setTimeout(() => {
  5381. const blurTag = document.getElementById("blurTag");
  5382. const tagText = document.querySelector(".tagText");
  5383. const tagElement = document.querySelector("#tag");
  5384. blurTag.addEventListener("change", () => {
  5385. const state = blurTag.checked;
  5386.  
  5387. state ? (tagText.classList.add("blur"), tagElement.classList.add("blur")) : (tagText.classList.remove("blur"), tagElement.classList.remove("blur"));
  5388. modSettings.chatSettings.blurTag = state;
  5389. updateStorage();
  5390. });
  5391. blurTag.checked = modSettings.chatSettings.blurTag;
  5392. if (modSettings.chatSettings.blurTag) {
  5393. tagText.classList.add("blur");
  5394. tagElement.classList.add("blur");
  5395. }
  5396. });
  5397.  
  5398. const locationText = document.getElementById("locationText");
  5399. locationText.addEventListener("input", (e) => {
  5400. e.stopPropagation();
  5401. modSettings.chatSettings.locationText = locationText.value;
  5402. });
  5403. locationText.value = modSettings.chatSettings.locationText || "{pos}";
  5404. },
  5405.  
  5406. toggleChat() {
  5407. const modChat = document.querySelector(".modChat");
  5408. const modChatAdded = document.querySelectorAll(".chatAddedContainer");
  5409.  
  5410. const isModChatHidden = modChat.style.display === "none" || getComputedStyle(modChat).display === "none";
  5411.  
  5412. if (isModChatHidden) {
  5413. modChat.style.opacity = 0;
  5414. modChat.style.display = "flex";
  5415.  
  5416. setTimeout(() => {
  5417. modChat.style.opacity = 1;
  5418. }, 10);
  5419. } else {
  5420. modChat.style.opacity = 0;
  5421. modChatAdded.forEach(container => container.classList.add("hidden_full"));
  5422.  
  5423. setTimeout(() => {
  5424. modChat.style.display = "none";
  5425. }, 300);
  5426. }
  5427. },
  5428.  
  5429.  
  5430. macroSettings() {
  5431. const allSettingNames = document.querySelectorAll(".setting-card-name")
  5432.  
  5433. for (const settingName of Object.values(allSettingNames)) {
  5434. settingName.addEventListener("click", (event) => {
  5435. const settingCardWrappers = document.querySelectorAll(".setting-card-wrapper")
  5436. const currentWrapper = Object.values(settingCardWrappers).filter((wrapper) => wrapper.querySelector(".setting-card-name").textContent === settingName.textContent)[0]
  5437. const settingParameters = currentWrapper.querySelector(".setting-parameters")
  5438.  
  5439. settingParameters.style.display = settingParameters.style.display === "none" ? "block" : "none"
  5440. })
  5441. }
  5442. },
  5443.  
  5444. smallMods() {
  5445. const modAlert_overlay = document.createElement("div");
  5446. modAlert_overlay.classList.add("alert_overlay");
  5447. modAlert_overlay.id = "modAlert_overlay";
  5448. document.body.append(modAlert_overlay);
  5449.  
  5450. const popup = document.getElementById("shop-popup");
  5451. const removeShopPopup = document.getElementById("removeShopPopup");
  5452. removeShopPopup.addEventListener("change", () => {
  5453. const checked = removeShopPopup.checked;
  5454. if (checked) {
  5455. popup.classList.add("hidden_full");
  5456. modSettings.removeShopPopup = true;
  5457. } else {
  5458. popup.classList.remove("hidden_full");
  5459. modSettings.removeShopPopup = false;
  5460. }
  5461. updateStorage();
  5462. });
  5463. if (modSettings.removeShopPopup) {
  5464. popup.classList.add("hidden_full");
  5465. removeShopPopup.checked = true;
  5466. }
  5467.  
  5468. const auto = document.getElementById("autoClaimCoins");
  5469. auto.addEventListener("change", () => {
  5470. const checked = auto.checked;
  5471. if (checked) {
  5472. modSettings.autoClaimCoins = true;
  5473. } else {
  5474. modSettings.autoClaimCoins = false;
  5475. }
  5476. updateStorage();
  5477. });
  5478. if (modSettings.autoClaimCoins) {
  5479. auto.checked = true;
  5480. }
  5481.  
  5482. const gameTitle = document.getElementById("title");
  5483. gameTitle.innerHTML = 'Sigmally<span style="display: block; font-size: 14px; font-family: Comic Sans MS ">Mod by <a href="https://www.youtube.com/@sigmallyCursed/" target="_blank">Cursed</a></span>';
  5484.  
  5485. const nickName = document.getElementById("nick");
  5486. nickName.maxLength = 50;
  5487. nickName.type = "text";
  5488.  
  5489. function updNick() {
  5490. const nick = nickName.value;
  5491. this.nick = nick;
  5492. const welcome = document.getElementById("welcomeUser");
  5493. if (welcome) {
  5494. welcome.innerHTML = `Welcome ${this.nick || "Unnamed"}, to the SigMod Client!`;
  5495. }
  5496. }
  5497. nickName.addEventListener("input", () => {
  5498. updNick();
  5499. });
  5500.  
  5501. updNick();
  5502.  
  5503.  
  5504. const topusersInner = document.querySelector(".top-users__inner");
  5505. topusersInner.classList.add("scroll");
  5506. topusersInner.style.border = "none";
  5507.  
  5508. document.getElementById("signOutBtn").addEventListener("click", () => {
  5509. unsafeWindow.gameSettings.user = null;
  5510. });
  5511.  
  5512. const mode = document.getElementById("gamemode");
  5513. mode.addEventListener("change", () => {
  5514. client.send({
  5515. type: "server-changed",
  5516. content: getGameMode()
  5517. });
  5518. });
  5519. },
  5520.  
  5521. removeStorage(storage) {
  5522. localStorage.removeItem(storage);
  5523. },
  5524.  
  5525. credits() {
  5526. console.log(`%c
  5527. ‎░█▀▀▀█ ▀█▀ ░█▀▀█ ░█▀▄▀█ ░█▀▀▀█ ░█▀▀▄
  5528. ‎─▀▀▀▄▄ ░█─ ░█─▄▄ ░█░█░█ ░█──░█ ░█─░█ V${version}
  5529. ‎░█▄▄▄█ ▄█▄ ░█▄▄█ ░█──░█ ░█▄▄▄█ ░█▄▄▀
  5530. ██████╗░██╗░░░██╗  ░█████╗░██╗░░░██╗██████╗░░██████╗███████╗██████╗░
  5531. ██╔══██╗╚██╗░██╔╝  ██╔══██╗██║░░░██║██╔══██╗██╔════╝██╔════╝██╔══██╗
  5532. ██████╦╝░╚████╔╝░  ██║░░╚═╝██║░░░██║██████╔╝╚█████╗░█████╗░░██║░░██║
  5533. ██╔══██╗░░╚██╔╝░░  ██║░░██╗██║░░░██║██╔══██╗░╚═══██╗██╔══╝░░██║░░██║
  5534. ██████╦╝░░░██║░░░  ╚█████╔╝╚██████╔╝██║░░██║██████╔╝███████╗██████╔╝
  5535. ╚═════╝░░░░╚═╝░░░  ░╚════╝░░╚═════╝░╚═╝░░╚═╝╚═════╝░╚══════╝╚═════╝░
  5536. `, 'background-color: black; color: green')
  5537. },
  5538. saveNames() {
  5539. let savedNames = modSettings.savedNames;
  5540. let savedNamesOutput = document.getElementById("savedNames");
  5541. let saveNameBtn = document.getElementById("saveName");
  5542. let saveNameInput = document.getElementById("saveNameValue");
  5543.  
  5544. const createNameDiv = (name) => {
  5545. let nameDiv = document.createElement("div");
  5546. nameDiv.classList.add("NameDiv");
  5547.  
  5548. let nameLabel = document.createElement("label");
  5549. nameLabel.classList.add("NameLabel");
  5550. nameLabel.innerText = name;
  5551.  
  5552. let delName = document.createElement("button");
  5553. delName.innerText = "X";
  5554. delName.classList.add("delName");
  5555.  
  5556. nameDiv.addEventListener("click", () => {
  5557. const name = nameLabel.innerText;
  5558. navigator.clipboard.writeText(name).then(() => {
  5559. this.modAlert(`Added the name '${name}' to your clipboard!`, "success");
  5560. });
  5561. });
  5562.  
  5563. delName.addEventListener("click", () => {
  5564. if (confirm("Are you sure you want to delete the name '" + nameLabel.innerText + "'?")) {
  5565. console.log("deleted name: " + nameLabel.innerText);
  5566. nameDiv.remove();
  5567. savedNames = savedNames.filter((n) => n !== nameLabel.innerText);
  5568. modSettings.savedNames = savedNames;
  5569. updateStorage();
  5570. }
  5571. });
  5572.  
  5573. nameDiv.appendChild(nameLabel);
  5574. nameDiv.appendChild(delName);
  5575. return nameDiv;
  5576. };
  5577.  
  5578. saveNameBtn.addEventListener("click", () => {
  5579. if (saveNameInput.value == "") {
  5580. console.log("empty name");
  5581. } else {
  5582. setTimeout(() => {
  5583. saveNameInput.value = "";
  5584. }, 10);
  5585.  
  5586. if (savedNames.includes(saveNameInput.value)) {
  5587. console.log("You already have this name saved!");
  5588. return;
  5589. }
  5590.  
  5591. let nameDiv = createNameDiv(saveNameInput.value);
  5592. savedNamesOutput.appendChild(nameDiv);
  5593.  
  5594. savedNames.push(saveNameInput.value);
  5595. modSettings.savedNames = savedNames;
  5596. updateStorage();
  5597. }
  5598. });
  5599.  
  5600. if (savedNames.length > 0) {
  5601. savedNames.forEach((name) => {
  5602. let nameDiv = createNameDiv(name);
  5603. savedNamesOutput.appendChild(nameDiv);
  5604. });
  5605. }
  5606. },
  5607.  
  5608. initStats() {
  5609. const statElements = ["stat-time-played", "stat-highest-mass", "stat-total-deaths", "stat-total-mass"];
  5610. this.storage = localStorage.getItem("game-stats");
  5611.  
  5612. if (!this.storage) {
  5613. this.storage = {
  5614. "time-played": 0, // seconds
  5615. "highest-mass": 0,
  5616. "total-deaths": 0,
  5617. "total-mass": 0,
  5618. };
  5619. localStorage.setItem("game-stats", JSON.stringify(this.storage));
  5620. } else {
  5621. this.storage = JSON.parse(this.storage);
  5622. }
  5623.  
  5624. statElements.forEach(rawStat => {
  5625. const stat = rawStat.replace("stat-", "");
  5626. const value = this.storage[stat];
  5627. this.updateStatElm(rawStat, value);
  5628. });
  5629.  
  5630. this.session.bind(this)();
  5631. },
  5632.  
  5633. updateStat(key, value) {
  5634. this.storage[key] = value;
  5635. localStorage.setItem("game-stats", JSON.stringify(this.storage));
  5636. this.updateStatElm(key, value);
  5637. },
  5638.  
  5639. updateStatElm(stat, value) {
  5640. const element = document.getElementById(stat);
  5641.  
  5642. if (element) {
  5643. if (stat === "stat-time-played") {
  5644. const hours = Math.floor(value / 3600);
  5645. const minutes = Math.floor((value % 3600) / 60);
  5646. const formattedTime = hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
  5647. element.innerHTML = formattedTime;
  5648. } else {
  5649. const formattedValue = stat === "stat-highest-mass" || stat === "stat-total-mass"
  5650. ? value > 999 ? `${(value / 1000).toFixed(1)}k` : value.toString()
  5651. : value.toString();
  5652. element.innerHTML = formattedValue;
  5653. }
  5654. }
  5655. },
  5656.  
  5657. session() {
  5658. let playingInterval;
  5659. let minPlaying = 0;
  5660. let isPlaying = false;
  5661.  
  5662. const playBtn = document.getElementById("play-btn");
  5663.  
  5664. playBtn.addEventListener("click", () => {
  5665. if (isPlaying) return;
  5666. isPlaying = true;
  5667. let timer = null;
  5668. if (modSettings.playTimer) {
  5669. timer = document.createElement("span");
  5670. timer.classList.add("playTimer");
  5671. timer.innerText = "0m0s played";
  5672. document.body.append(timer);
  5673. }
  5674. let count = 0;
  5675. playingInterval = setInterval(() => {
  5676. count++;
  5677. this.storage["time-played"]++;
  5678. if (count % 60 === 0) {
  5679. minPlaying++;
  5680. }
  5681. this.updateStat("time-played", this.storage["time-played"]);
  5682.  
  5683. if (modSettings.playTimer) {
  5684. this.updateTimeStat(timer, count);
  5685. }
  5686. }, 1000);
  5687. });
  5688.  
  5689. setInterval(() => {
  5690. if (isDeath() && !dead) {
  5691. clearInterval(playingInterval);
  5692. dead = true;
  5693. const playTimer = document.querySelector(".playTimer");
  5694. if (playTimer) playTimer.remove();
  5695. const score = parseFloat(document.getElementById("highest_mass").innerText);
  5696. const highest = this.storage["highest-mass"];
  5697.  
  5698. if (score > highest) {
  5699. this.storage["highest-mass"] = score;
  5700. this.updateStat("highest-mass", this.storage["highest-mass"]);
  5701. }
  5702.  
  5703. this.storage["total-deaths"]++;
  5704. this.updateStat("total-deaths", this.storage["total-deaths"]);
  5705.  
  5706. this.storage["total-mass"] += score;
  5707. this.updateStat("total-mass", this.storage["total-mass"]);
  5708. isPlaying = false;
  5709. } else if (!isDeath()) {
  5710. dead = false;
  5711. }
  5712. });
  5713. },
  5714. updateTimeStat(el, seconds) {
  5715. const minutes = Math.floor(seconds / 60);
  5716. const remainingSeconds = seconds % 60;
  5717. const timeString = `${minutes}m${remainingSeconds}s`;
  5718.  
  5719. el.innerText = `${timeString} played`;
  5720. },
  5721.  
  5722. fps() {
  5723. const byId = (id) => document.getElementById(id);
  5724. const fpsMode = byId("fpsMode");
  5725. const hideFood = byId("fps-hideFood");
  5726. const removeNames = byId("fps-remNames");
  5727. const shortlongNames = byId("fps-shortenLongNames");
  5728. const removeTextoutlines = byId("fps-remOutlines");
  5729. const allElements = document.querySelectorAll(".fpsCheckbox");
  5730.  
  5731. const toggleFPSmode = (turnOn) => {
  5732. modSettings.fps.fpsMode = turnOn;
  5733. if (turnOn) {
  5734. console.log("FPS mode enabled");
  5735.  
  5736. allElements.forEach(elm => {
  5737. elm.setAttribute("disabled", "true");
  5738. });
  5739. toggleNames();
  5740.  
  5741. const cb = document.getElementById("showSkins");
  5742. if (!cb.checked) {
  5743. cb.click();
  5744. }
  5745.  
  5746. } else {
  5747. console.log("FPS mode disabled");
  5748.  
  5749. allElements.forEach(elm => {
  5750. elm.removeAttribute("disabled");
  5751. });
  5752.  
  5753. toggleNames();
  5754. }
  5755. updateStorage();
  5756. };
  5757.  
  5758. const toggleNames = () => {
  5759. modSettings.fps.showNames = removeNames.checked;
  5760. const cb = document.getElementById("showNames");
  5761. if (cb.checked && removeNames.checked) {
  5762. cb.click();
  5763. } else {
  5764. cb.click();
  5765. }
  5766. updateStorage();
  5767. };
  5768.  
  5769. // checkbox events
  5770. fpsMode.addEventListener("change", () => {
  5771. toggleFPSmode(fpsMode.checked);
  5772. });
  5773. hideFood.addEventListener("change", () => {
  5774. modSettings.fps.hideFood = hideFood.checked;
  5775. updateStorage();
  5776. });
  5777. removeNames.addEventListener("change", () => {
  5778. toggleNames();
  5779. });
  5780. shortlongNames.addEventListener("change", () => {
  5781. modSettings.fps.shortLongNames = shortlongNames.checked;
  5782. updateStorage();
  5783. });
  5784. removeTextoutlines.addEventListener("change", () => {
  5785. modSettings.fps.removeOutlines = removeTextoutlines.checked;
  5786. updateStorage();
  5787. });
  5788.  
  5789. // set checkbox state
  5790. const loadStorage = () => {
  5791. const option = modSettings.fps;
  5792. if (option.fpsMode) {
  5793. fpsMode.checked = true;
  5794. }
  5795. if (option.hideFood) {
  5796. hideFood.checked = true;
  5797. }
  5798. if (option.removeNames) {
  5799. removeNames.checked = true;
  5800. }
  5801. if (option.shortlongNames) {
  5802. shortlongNames.checked = true;
  5803. }
  5804. if (option.removeOutlines) {
  5805. removeTextoutlines.checked = true;
  5806. }
  5807. };
  5808.  
  5809. loadStorage();
  5810. },
  5811.  
  5812. fastMass() {
  5813. let x = 15;
  5814. while (x--) {
  5815. keypress("w", "KeyW");
  5816. }
  5817. },
  5818.  
  5819. Macros() {
  5820. let that = this;
  5821. const KEY_SPLIT = this.splitKey;
  5822. let ff = null;
  5823. let keydown = false;
  5824. let open = false;
  5825. const canvas = document.getElementById("canvas");
  5826. const freezeType = document.getElementById("freezeType");
  5827. const mod_menu = document.querySelector(".mod_menu");
  5828. let freezeKeyPressed = false;
  5829. let freezeMouseClicked = false;
  5830. let freezeOverlay = null;
  5831.  
  5832.  
  5833. freezeType.value = modSettings.freezeType;
  5834. freezeType.addEventListener("change", () => {
  5835. modSettings.freezeType = freezeType.value;
  5836. updateStorage();
  5837. });
  5838.  
  5839.  
  5840.  
  5841. function splitRecursive(times) {
  5842. if (times > 0) {
  5843. window.dispatchEvent(new KeyboardEvent("keydown", KEY_SPLIT));
  5844. window.dispatchEvent(new KeyboardEvent("keyup", KEY_SPLIT));
  5845. splitRecursive(times - 1);
  5846. }
  5847. }
  5848.  
  5849. function split() {
  5850. splitRecursive(1);
  5851. }
  5852.  
  5853. function split2() {
  5854. splitRecursive(2);
  5855. }
  5856.  
  5857. function split3() {
  5858. splitRecursive(3);
  5859. }
  5860.  
  5861. function split4() {
  5862. splitRecursive(4);
  5863. }
  5864.  
  5865. async function selfTrick() {
  5866. let i = 4;
  5867.  
  5868. while (i--) {
  5869. splitRecursive(1);
  5870. await wait(20)
  5871. }
  5872. }
  5873. async function doubleTrick() {
  5874. let i = 2;
  5875.  
  5876. while (i--) {
  5877. splitRecursive(1);
  5878. await wait(20)
  5879. }
  5880. }
  5881.  
  5882. function mouseToScreenCenter() {
  5883. const screenCenterX = canvas.width / 2
  5884. const screenCenterY = canvas.height / 2
  5885.  
  5886. mousemove(screenCenterX, screenCenterY)
  5887.  
  5888. return {
  5889. x: screenCenterX,
  5890. y: screenCenterY
  5891. }
  5892. }
  5893.  
  5894. async function verticalLine() {
  5895. let i = 4;
  5896.  
  5897. while (i--) {
  5898. const centerXY = mouseToScreenCenter();
  5899. const offsetUpX = centerXY.x
  5900. const offsetUpY = centerXY.y - 100
  5901. const offsetDownX = centerXY.x
  5902. const offsetDownY = centerXY.y + 100
  5903.  
  5904. await wait(50)
  5905.  
  5906. mousemove(offsetUpX, offsetUpY)
  5907.  
  5908. await wait(80)
  5909.  
  5910. split();
  5911.  
  5912. await wait(160)
  5913.  
  5914. mousemove(offsetDownX, offsetDownY)
  5915.  
  5916. if (i == 0) break
  5917.  
  5918. await wait(80)
  5919.  
  5920. split();
  5921. }
  5922.  
  5923. freezePlayer("hold", false);
  5924. }
  5925.  
  5926. function freezePlayer(type, mouse) {
  5927. if(freezeType.value === "hold" && type === "hold") {
  5928. const CX = canvas.width / 2;
  5929. const CY = canvas.height / 2;
  5930.  
  5931. mousemove(CX, CY);
  5932. } else if(freezeType.value === "press" && type === "press") {
  5933. if(!freezeKeyPressed) {
  5934. const CX = canvas.width / 2;
  5935. const CY = canvas.height / 2;
  5936.  
  5937. mousemove(CX, CY);
  5938.  
  5939.  
  5940. freezeOverlay = document.createElement("div");
  5941. freezeOverlay.innerHTML = `
  5942. <span style="position: absolute; bottom: 50px; left: 50%; transform: translateX(-50%); color: #fff; font-size: 26px; user-select: none;">Movement Stopped</span>
  5943. `;
  5944. freezeOverlay.style = "position: absolute; top: 0; left: 0; z-index: 99; width: 100%; height: 100vh; overflow: hidden;";
  5945.  
  5946. if (mouse && (modSettings.m1 === "freeze" || modSettings.m2 === "freeze")) {
  5947. freezeOverlay.addEventListener("mousedown", (e) => {
  5948. if (e.button === 0 && modSettings.m1 === "freeze") { // Left mouse button (1)
  5949. handleFreezeEvent();
  5950. }
  5951. if (e.button === 2 && modSettings.m2 === "freeze") { // Right mouse button (2)
  5952. handleFreezeEvent();
  5953. }
  5954. });
  5955.  
  5956. if (modSettings.m2 === "freeze") {
  5957. freezeOverlay.addEventListener("contextmenu", (e) => {
  5958. e.preventDefault();
  5959. });
  5960. }
  5961. }
  5962.  
  5963. function handleFreezeEvent() {
  5964. if (freezeOverlay != null) freezeOverlay.remove();
  5965. freezeOverlay = null;
  5966. freezeKeyPressed = false;
  5967. }
  5968.  
  5969.  
  5970. document.querySelector(".body__inner").append(freezeOverlay)
  5971.  
  5972. freezeKeyPressed = true;
  5973. } else {
  5974. if(freezeOverlay != null) freezeOverlay.remove();
  5975. freezeOverlay = null;
  5976. freezeKeyPressed = false;
  5977. }
  5978. }
  5979. }
  5980.  
  5981. function sendLocation() {
  5982. if (!activeCellX || !activeCellY) return;
  5983.  
  5984. const gamemode = document.getElementById("gamemode");
  5985. const coordinatesToCheck = (gamemode.value === "eu0.sigmally.com/ws/") ? coordinates : coordinates2;
  5986.  
  5987. let field = "";
  5988.  
  5989. for (const label in coordinatesToCheck) {
  5990. const { min, max } = coordinatesToCheck[label];
  5991.  
  5992. if (
  5993. activeCellX >= min.x &&
  5994. activeCellX <= max.x &&
  5995. activeCellY >= min.y &&
  5996. activeCellY <= max.y
  5997. ) {
  5998. field = label;
  5999. break;
  6000. }
  6001. }
  6002.  
  6003. const locationText = modSettings.chatSettings.locationText || field;
  6004. const message = locationText.replace('{pos}', field);
  6005. unsafeWindow.sendChat(message);
  6006. }
  6007.  
  6008. function toggleSettings(setting) {
  6009. const settingElement = document.querySelector(`input#${setting}`);
  6010. if (settingElement) {
  6011. settingElement.click();
  6012. } else {
  6013. console.error(`Setting "${setting}" not found`);
  6014. }
  6015. }
  6016.  
  6017.  
  6018. document.addEventListener("keyup", (e) => {
  6019. const key = e.key.toLowerCase();
  6020. if (key == modSettings.keyBindings.rapidFeed && keydown) {
  6021. clearInterval(ff);
  6022. keydown = false;
  6023. }
  6024. });
  6025. document.addEventListener("keydown", (e) => {
  6026. const key = e.key.toLowerCase();
  6027.  
  6028. if (key == "p") {
  6029. e.stopPropagation();
  6030. }
  6031. if (key == "tab") {
  6032. e.preventDefault();
  6033. }
  6034.  
  6035. if (document.activeElement.tagName === "INPUT" || document.activeElement.tagName === "TEXTAREA") return;
  6036.  
  6037. if (key == modSettings.keyBindings.toggleMenu) {
  6038. if (!open) {
  6039. mod_menu.style.display = "flex";
  6040. setTimeout(() => {
  6041. mod_menu.style.opacity = 1;
  6042. }, 10);
  6043. open = true;
  6044. } else {
  6045. mod_menu.style.opacity = 0;
  6046. setTimeout(() => {
  6047. mod_menu.style.display = "none";
  6048. }, 300);
  6049. open = false;
  6050. }
  6051. }
  6052.  
  6053. if (key == modSettings.keyBindings.freezePlayer) {
  6054. if (menuClosed()) {
  6055. freezePlayer(modSettings.freezeType, false);
  6056. }
  6057. }
  6058.  
  6059. if (key == modSettings.keyBindings.rapidFeed && !keydown) {
  6060. keydown = true;
  6061. ff = setInterval(this.fastMass, 50);
  6062. }
  6063. if (key == modSettings.keyBindings.doubleSplit) {
  6064. split2();
  6065. }
  6066.  
  6067. if (key == modSettings.keyBindings.tripleSplit) {
  6068. split3();
  6069. }
  6070.  
  6071. if (key == modSettings.keyBindings.quadSplit) {
  6072. split4();
  6073. }
  6074.  
  6075. if (key == modSettings.keyBindings.selfTrick) {
  6076. selfTrick();
  6077. }
  6078.  
  6079. if (key == modSettings.keyBindings.doubleTrick) {
  6080. doubleTrick();
  6081. }
  6082.  
  6083. if (key == modSettings.keyBindings.verticalSplit) {
  6084. verticalLine();
  6085. }
  6086.  
  6087. if (key == modSettings.keyBindings.location) {
  6088. sendLocation();
  6089. }
  6090.  
  6091. if (key == modSettings.keyBindings.toggleChat) {
  6092. mods.toggleChat();
  6093. }
  6094.  
  6095. if (key == modSettings.keyBindings.toggleNames) {
  6096. toggleSettings("showNames");
  6097. }
  6098.  
  6099. if (key == modSettings.keyBindings.toggleSkins) {
  6100. toggleSettings("showSkins");
  6101. }
  6102.  
  6103. if (key == modSettings.keyBindings.toggleAutoRespawn) {
  6104. toggleSettings("autoRespawn");
  6105. }
  6106. });
  6107.  
  6108. canvas.addEventListener("mousedown", (e) => {
  6109. if (e.button === 0) { // Left mouse button (0)
  6110. if (modSettings.m1 === "fastfeed") {
  6111. if (document.activeElement.tagName === "INPUT" || document.activeElement.tagName === "TEXTAREA") return;
  6112. this.mouseDown = true
  6113. } else if (modSettings.m1 === "split1") {
  6114. split();
  6115. } else if (modSettings.m1 === "split2") {
  6116. split2();
  6117. } else if (modSettings.m1 === "split3") {
  6118. split3();
  6119. } else if (modSettings.m1 === "split4") {
  6120. split4();
  6121. } else if (modSettings.m1 === "freeze") {
  6122. freezePlayer(modSettings.freezeType, true);
  6123. } else if (modSettings.m1 === "dTrick") {
  6124. doubleTrick();
  6125. } else if (modSettings.m1 === "sTrick") {
  6126. selfTrick();
  6127. }
  6128. } else if (e.button === 2) { // Right mouse button (2)
  6129. e.preventDefault();
  6130. if (modSettings.m2 === "fastfeed") {
  6131. if (document.activeElement.tagName === "INPUT" || document.activeElement.tagName === "TEXTAREA") return;
  6132. this.mouseDown = true;
  6133. } else if (modSettings.m2 === "split1") {
  6134. split();
  6135. } else if (modSettings.m2 === "split2") {
  6136. split2();
  6137. } else if (modSettings.m2 === "split3") {
  6138. split3();
  6139. } else if (modSettings.m2 === "split4") {
  6140. split4();
  6141. } else if (modSettings.m2 === "freeze") {
  6142. freezePlayer(modSettings.freezeType, true);
  6143. } else if (modSettings.m2 === "dTrick") {
  6144. doubleTrick();
  6145. } else if (modSettings.m2 === "sTrick") {
  6146. selfTrick();
  6147. }
  6148. }
  6149. });
  6150.  
  6151. canvas.addEventListener("contextmenu", (e) => {
  6152. e.preventDefault();
  6153. });
  6154.  
  6155. canvas.addEventListener("mouseup", () => {
  6156. if (modSettings.m1 === "fastfeed") {
  6157. this.mouseDown = false;
  6158. } else if (modSettings.m2 === "fastfeed") {
  6159. this.mouseDown = false;
  6160. }
  6161. });
  6162.  
  6163. const macroSelectHandler = (macroSelect, key) => {
  6164. macroSelect.value = modSettings[key] || "none";
  6165.  
  6166. macroSelect.addEventListener("change", () => {
  6167. const selectedOption = macroSelect.value;
  6168.  
  6169. const optionActions = {
  6170. "none": () => {
  6171. modSettings[key] = null;
  6172. },
  6173. "fastfeed": () => {
  6174. modSettings[key] = "fastfeed";
  6175. },
  6176. "split": () => {
  6177. modSettings[key] = "split";
  6178. },
  6179. "split2": () => {
  6180. modSettings[key] = "split2";
  6181. },
  6182. "split3": () => {
  6183. modSettings[key] = "split3";
  6184. },
  6185. "split4": () => {
  6186. modSettings[key] = "split4";
  6187. },
  6188. "freeze": () => {
  6189. modSettings[key] = "freeze";
  6190. },
  6191. "dTrick": () => {
  6192. modSettings[key] = "dTrick";
  6193. },
  6194. "sTrick": () => {
  6195. modSettings[key] = "sTrick";
  6196. },
  6197. };
  6198.  
  6199. if (optionActions[selectedOption]) {
  6200. optionActions[selectedOption]();
  6201. updateStorage();
  6202. }
  6203. });
  6204. };
  6205.  
  6206. const m1_macroSelect = document.getElementById("m1_macroSelect");
  6207. const m2_macroSelect = document.getElementById("m2_macroSelect");
  6208.  
  6209. macroSelectHandler(m1_macroSelect, "m1");
  6210. macroSelectHandler(m2_macroSelect, "m2");
  6211. },
  6212.  
  6213. setInputActions() {
  6214. const numModInputs = 15;
  6215.  
  6216. const macroInputs = Array.from({ length: numModInputs }, (_, i) => `modinput${i + 1}`);
  6217.  
  6218. macroInputs.forEach((modkey) => {
  6219. const modInput = document.getElementById(modkey);
  6220.  
  6221. document.addEventListener("keydown", (event) => {
  6222. if (document.activeElement !== modInput) return;
  6223.  
  6224. if (event.key === "Backspace") {
  6225. modInput.value = "";
  6226. let propertyName = modInput.name;
  6227. modSettings.keyBindings[propertyName] = "";
  6228. updateStorage();
  6229. return;
  6230. }
  6231.  
  6232. modInput.value = event.key.toLowerCase();
  6233.  
  6234. if (modInput.value !== "" && (macroInputs.filter((item) => item === modInput.value).length > 1 || macroInputs.some((otherKey) => {
  6235. const otherInput = document.getElementById(otherKey);
  6236. return otherInput !== modInput && otherInput.value === modInput.value;
  6237. }))) {
  6238. alert("You can't use 2 keybindings at the same time.");
  6239. setTimeout(() => {modInput.value = ""})
  6240. return;
  6241. }
  6242.  
  6243. let propertyName = modInput.name;
  6244. modSettings.keyBindings[propertyName] = modInput.value;
  6245.  
  6246. updateStorage();
  6247. });
  6248. });
  6249. },
  6250.  
  6251. mainMenu() {
  6252. let menucontent = document.querySelector(".menu-center-content");
  6253. menucontent.style.margin = "auto";
  6254.  
  6255. const discordlinks = document.createElement("div");
  6256. discordlinks.setAttribute("id", "dclinkdiv")
  6257. discordlinks.innerHTML = `
  6258. <a href="https://discord.gg/4j4Rc4dQTP" target="_blank" class="dclinks">
  6259. <svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
  6260. <path d="M19.4566 5.35132C21.7154 8.83814 22.8309 12.7712 22.4139 17.299C22.4121 17.3182 22.4026 17.3358 22.3876 17.3473C20.6771 18.666 19.0199 19.4663 17.3859 19.9971C17.3732 20.0011 17.3596 20.0009 17.347 19.9964C17.3344 19.992 17.3234 19.9835 17.3156 19.9721C16.9382 19.4207 16.5952 18.8393 16.2947 18.2287C16.2774 18.1928 16.2932 18.1495 16.3287 18.1353C16.8734 17.9198 17.3914 17.6615 17.8896 17.3557C17.9289 17.3316 17.9314 17.2725 17.8951 17.2442C17.7894 17.1617 17.6846 17.0751 17.5844 16.9885C17.5656 16.9725 17.5404 16.9693 17.5191 16.9801C14.2844 18.5484 10.7409 18.5484 7.46792 16.9801C7.44667 16.9701 7.42142 16.9735 7.40317 16.9893C7.30317 17.0759 7.19817 17.1617 7.09342 17.2442C7.05717 17.2725 7.06017 17.3316 7.09967 17.3557C7.59792 17.6557 8.11592 17.9198 8.65991 18.1363C8.69517 18.1505 8.71192 18.1928 8.69442 18.2287C8.40042 18.8401 8.05742 19.4215 7.67292 19.9729C7.65617 19.9952 7.62867 20.0055 7.60267 19.9971C5.97642 19.4663 4.31917 18.666 2.60868 17.3473C2.59443 17.3358 2.58418 17.3174 2.58268 17.2982C2.23418 13.3817 2.94442 9.41613 5.53717 5.35053C5.54342 5.33977 5.55292 5.33137 5.56392 5.32638C6.83967 4.71165 8.20642 4.25939 9.63491 4.00111C9.66091 3.99691 9.68691 4.00951 9.70041 4.03365C9.87691 4.36176 10.0787 4.78252 10.2152 5.12637C11.7209 4.88489 13.2502 4.88489 14.7874 5.12637C14.9239 4.78987 15.1187 4.36176 15.2944 4.03365C15.3007 4.02167 15.3104 4.01208 15.3221 4.00623C15.3339 4.00039 15.3471 3.99859 15.3599 4.00111C16.7892 4.26018 18.1559 4.71244 19.4306 5.32638C19.4419 5.33137 19.4511 5.33977 19.4566 5.35132ZM10.9807 12.798C10.9964 11.6401 10.1924 10.6821 9.18316 10.6821C8.18217 10.6821 7.38592 11.6317 7.38592 12.798C7.38592 13.9639 8.19792 14.9136 9.18316 14.9136C10.1844 14.9136 10.9807 13.9639 10.9807 12.798ZM17.6261 12.798C17.6419 11.6401 16.8379 10.6821 15.8289 10.6821C14.8277 10.6821 14.0314 11.6317 14.0314 12.798C14.0314 13.9639 14.8434 14.9136 15.8289 14.9136C16.8379 14.9136 17.6261 13.9639 17.6261 12.798Z" fill="white"></path>
  6261. </svg>
  6262. <span>Sigmally Discord</span>
  6263. </a>
  6264. <a href="https://discord.gg/QyUhvUC8AD" target="_blank" class="dclinks">
  6265. <svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
  6266. <path d="M19.4566 5.35132C21.7154 8.83814 22.8309 12.7712 22.4139 17.299C22.4121 17.3182 22.4026 17.3358 22.3876 17.3473C20.6771 18.666 19.0199 19.4663 17.3859 19.9971C17.3732 20.0011 17.3596 20.0009 17.347 19.9964C17.3344 19.992 17.3234 19.9835 17.3156 19.9721C16.9382 19.4207 16.5952 18.8393 16.2947 18.2287C16.2774 18.1928 16.2932 18.1495 16.3287 18.1353C16.8734 17.9198 17.3914 17.6615 17.8896 17.3557C17.9289 17.3316 17.9314 17.2725 17.8951 17.2442C17.7894 17.1617 17.6846 17.0751 17.5844 16.9885C17.5656 16.9725 17.5404 16.9693 17.5191 16.9801C14.2844 18.5484 10.7409 18.5484 7.46792 16.9801C7.44667 16.9701 7.42142 16.9735 7.40317 16.9893C7.30317 17.0759 7.19817 17.1617 7.09342 17.2442C7.05717 17.2725 7.06017 17.3316 7.09967 17.3557C7.59792 17.6557 8.11592 17.9198 8.65991 18.1363C8.69517 18.1505 8.71192 18.1928 8.69442 18.2287C8.40042 18.8401 8.05742 19.4215 7.67292 19.9729C7.65617 19.9952 7.62867 20.0055 7.60267 19.9971C5.97642 19.4663 4.31917 18.666 2.60868 17.3473C2.59443 17.3358 2.58418 17.3174 2.58268 17.2982C2.23418 13.3817 2.94442 9.41613 5.53717 5.35053C5.54342 5.33977 5.55292 5.33137 5.56392 5.32638C6.83967 4.71165 8.20642 4.25939 9.63491 4.00111C9.66091 3.99691 9.68691 4.00951 9.70041 4.03365C9.87691 4.36176 10.0787 4.78252 10.2152 5.12637C11.7209 4.88489 13.2502 4.88489 14.7874 5.12637C14.9239 4.78987 15.1187 4.36176 15.2944 4.03365C15.3007 4.02167 15.3104 4.01208 15.3221 4.00623C15.3339 4.00039 15.3471 3.99859 15.3599 4.00111C16.7892 4.26018 18.1559 4.71244 19.4306 5.32638C19.4419 5.33137 19.4511 5.33977 19.4566 5.35132ZM10.9807 12.798C10.9964 11.6401 10.1924 10.6821 9.18316 10.6821C8.18217 10.6821 7.38592 11.6317 7.38592 12.798C7.38592 13.9639 8.19792 14.9136 9.18316 14.9136C10.1844 14.9136 10.9807 13.9639 10.9807 12.798ZM17.6261 12.798C17.6419 11.6401 16.8379 10.6821 15.8289 10.6821C14.8277 10.6821 14.0314 11.6317 14.0314 12.798C14.0314 13.9639 14.8434 14.9136 15.8289 14.9136C16.8379 14.9136 17.6261 13.9639 17.6261 12.798Z" fill="white"></path>
  6267. </svg>
  6268. <span>SigModz Discord</span>
  6269. </a>
  6270. `;
  6271. document.getElementById("discord_link").remove();
  6272. document.getElementById("menu").appendChild(discordlinks)
  6273.  
  6274. let clansbtn = document.querySelector("#clans_and_settings button");
  6275. clansbtn.innerHTML = "Clans";
  6276. document.querySelectorAll("#clans_and_settings button")[1].removeAttribute("onclick");
  6277. },
  6278.  
  6279. respawn() {
  6280. const __line2 = document.getElementById("__line2")
  6281. const c = document.getElementById("continue_button")
  6282. const p = document.getElementById("play-btn")
  6283.  
  6284. if (__line2.classList.contains("line--hidden")) return
  6285.  
  6286. this.respawnTime = null
  6287.  
  6288. setTimeout(() => {
  6289. c.click()
  6290. p.click()
  6291. }, 20);
  6292.  
  6293. this.respawnTime = Date.now()
  6294.  
  6295. },
  6296.  
  6297. clientPing() {
  6298. const pingElement = document.createElement("span");
  6299. pingElement.innerHTML = `Client Ping: 0ms`;
  6300. pingElement.id = "clientPing";
  6301. pingElement.style = `
  6302. position: absolute;
  6303. right: 10px;
  6304. bottom: 5px;
  6305. color: #fff;
  6306. font-size: 1.8rem;
  6307. `
  6308. document.querySelector(".mod_menu").append(pingElement);
  6309.  
  6310. this.ping.intervalId = setInterval(() => {
  6311. if (client.readyState != 1) return;
  6312. this.ping.start = Date.now();
  6313.  
  6314. client.send({
  6315. type: "get-ping",
  6316. });
  6317. }, 2000);
  6318. },
  6319.  
  6320. createMinimap() {
  6321. const dataContainer = document.createElement("div");
  6322. dataContainer.classList.add("minimapContainer");
  6323. dataContainer.innerHTML = `
  6324. <span class="hidden tournament_time"></span>
  6325. `;
  6326. const miniMap = document.createElement("canvas");
  6327. miniMap.width = 200;
  6328. miniMap.height = 200;
  6329. miniMap.classList.add("minimap");
  6330. this.canvas = miniMap;
  6331.  
  6332. let viewportScale = 1
  6333.  
  6334. document.body.append(dataContainer);
  6335. dataContainer.append(miniMap);
  6336.  
  6337. function resizeMiniMap() {
  6338. viewportScale = Math.max(window.innerWidth / 1920, window.innerHeight / 1080)
  6339.  
  6340. miniMap.width = miniMap.height = 200 * viewportScale
  6341. }
  6342.  
  6343. resizeMiniMap()
  6344.  
  6345. window.addEventListener("resize", resizeMiniMap)
  6346.  
  6347. const playBtn = document.getElementById("play-btn");
  6348. playBtn.addEventListener("click", () => {
  6349. setTimeout(() => {
  6350. lastLogTime = Date.now();
  6351. }, 300);
  6352. });
  6353. },
  6354.  
  6355. updData(data) {
  6356. let [x, y, name, playerId] = data;
  6357. const playerIndex = this.miniMapData.findIndex(player => player[3] === playerId);
  6358. name = parsetxt(name);
  6359.  
  6360. if (playerIndex === -1) {
  6361. // Player not found, add to miniMapData
  6362. this.miniMapData.push([x, y, name, playerId]);
  6363. } else {
  6364. // Player found, update position or remove if position is null
  6365. if (x !== null && y !== null) {
  6366. // Update position
  6367. this.miniMapData[playerIndex] = [x, y, name, playerId];
  6368. } else {
  6369. // Remove player if position is null
  6370. this.miniMapData.splice(playerIndex, 1);
  6371. }
  6372. }
  6373.  
  6374. this.updMinimap(); // draw minimap
  6375. },
  6376.  
  6377. updMinimap() {
  6378. if (isDeath()) return;
  6379. const miniMap = mods.canvas;
  6380. const border = mods.border;
  6381. const ctx = miniMap.getContext("2d");
  6382. ctx.clearRect(0, 0, miniMap.width, miniMap.height);
  6383.  
  6384. if (!menuClosed()) {
  6385. ctx.clearRect(0, 0, miniMap.width, miniMap.height);
  6386. return;
  6387. }
  6388.  
  6389. for (const miniMapData of this.miniMapData) {
  6390. if (!border.width) break
  6391.  
  6392. if (miniMapData[2] === null || miniMapData[3] === client.id) continue;
  6393. if (!miniMapData[0] && !miniMapData[1]) {
  6394. ctx.clearRect(0, 0, miniMap.width, miniMap.height);
  6395. continue;
  6396. }
  6397.  
  6398. const fullX = miniMapData[0] + border.width / 2
  6399. const fullY = miniMapData[1] + border.width / 2
  6400. const x = (fullX / border.width) * miniMap.width
  6401. const y = (fullY / border.width) * miniMap.height
  6402.  
  6403. ctx.fillStyle = "#3283bd"
  6404. ctx.beginPath();
  6405. ctx.arc(x, y, 3, 0, 2 * Math.PI);
  6406. ctx.fill();
  6407.  
  6408.  
  6409. const minDist = (y - 15.5);
  6410. const nameYOffset = minDist <= 1 ? - (4.5) : 10;
  6411.  
  6412. ctx.fillStyle = "#fff";
  6413. ctx.textAlign = "center";
  6414. ctx.font = "9px Ubuntu";
  6415. ctx.fillText(miniMapData[2], x, y - nameYOffset);
  6416. }
  6417. },
  6418.  
  6419. tagsystem() {
  6420. const nick = document.querySelector("#nick");
  6421. const tagElement = document.createElement("input");
  6422. const tagText = document.querySelector(".tagText");
  6423.  
  6424. tagElement.classList.add("form-control");
  6425. tagElement.placeholder = "tag";
  6426. tagElement.id = "tag";
  6427. tagElement.maxLength = 3;
  6428.  
  6429. const pnick = nick.parentElement;
  6430. pnick.style = "display: flex; gap: 5px;";
  6431.  
  6432. tagElement.addEventListener("input", (e) => {
  6433. e.stopPropagation();
  6434. const tagValue = tagElement.value;
  6435.  
  6436. tagText.innerText = tagValue ? `Tag: ${tagValue}` : "";
  6437.  
  6438. modSettings.tag = tagElement.value;
  6439. updateStorage();
  6440. client.send({
  6441. type: "update-tag",
  6442. content: modSettings.tag,
  6443. });
  6444. const miniMap = this.canvas;
  6445. const ctx = miniMap.getContext("2d");
  6446. ctx.clearRect(0, 0, miniMap.width, miniMap.height);
  6447. this.miniMapData = [];
  6448. });
  6449.  
  6450. nick.insertAdjacentElement("beforebegin", tagElement);
  6451. },
  6452. updateNick() {
  6453. const nick = document.getElementById("nick");
  6454. this.nick = nick.value;
  6455. nick.addEventListener("input", () => {
  6456. this.nick = nick.value;
  6457. client.send({
  6458. type: "update-nick",
  6459. content: nick.value
  6460. });
  6461. });
  6462. },
  6463.  
  6464. gameSocket() {
  6465. let that = this;
  6466.  
  6467. WebSocket.prototype.send = function(data) {
  6468. if (!client) {
  6469. client = new modClient();
  6470. }
  6471. if (!unsafeWindow.gameSettings.ws) {
  6472. unsafeWindow.gameSettings.ws = this;
  6473.  
  6474. unsafeWindow.gameSettings.ws.addEventListener("close", () => {
  6475. unsafeWindow.gameSettings.ws = null
  6476. handshake = false
  6477.  
  6478. activeCellX = null;
  6479. activeCellY = null;
  6480. const chat = document.getElementById("mod-messages");
  6481. chat.innerHTML = "";
  6482. setTimeout(() => {
  6483. document.getElementById('overlays').show(0.5);
  6484. document.getElementById('menu-wrapper').show();
  6485. document.getElementById('left-menu').show();
  6486. document.getElementById('menu-links').show();
  6487. document.getElementById('right-menu').show();
  6488. document.getElementById('left_ad_block').show();
  6489. document.getElementById('ad_bottom').show();
  6490. }, 500);
  6491. })
  6492.  
  6493. unsafeWindow.gameSettings.ws.sendPacket = function(packet) {
  6494. if (packet.build) {
  6495. return unsafeWindow.gameSettings.ws.send(packet.build())
  6496. }
  6497.  
  6498. unsafeWindow.gameSettings.ws.send(packet)
  6499. }
  6500.  
  6501. unsafeWindow.sendChat = function sendChat(text) {
  6502. const writer = new Writer();
  6503. writer.setUint8(C[0x63]);
  6504. writer.setUint8(0);
  6505. writer.setStringUTF8(text);
  6506. unsafeWindow.gameSettings.ws.sendPacket(writer);
  6507. };
  6508.  
  6509. unsafeWindow.gameSettings.ws.addEventListener("message", (event) => {
  6510. const reader = new Reader(new DataView(event.data), 0, true)
  6511.  
  6512. if (!handshake) {
  6513. const ver = reader.getStringUTF8(false)
  6514. C.set(new Uint8Array(reader.raw(256)))
  6515.  
  6516. for (const i in C) R[C[i]] = ~~i
  6517.  
  6518. handshake = true
  6519.  
  6520. return
  6521. }
  6522.  
  6523. const r = reader.getUint8()
  6524. switch (R[r]) {
  6525. case 0x63: {
  6526. // chat message
  6527. const flags = reader.getUint8();
  6528. const color = bytesToHex(
  6529. reader.getUint8(),
  6530. reader.getUint8(),
  6531. reader.getUint8()
  6532. );
  6533. let name = reader.getStringUTF8();
  6534. const message = reader.getStringUTF8();
  6535. const server = !!(flags & 0x80);
  6536. const admin = !!(flags & 0x40);
  6537. const mod = !!(flags & 0x20);
  6538.  
  6539. if (server && name !== 'SERVER') name = '[SERVER]';
  6540. if (admin) name = '[ADMIN] ' + name;
  6541. if (mod) name = '[MOD] ' + name;
  6542. if (name === "") name = "Unnamed";
  6543. name = parsetxt(name);
  6544.  
  6545. if (that.mutedUsers.includes(name)) {
  6546. return;
  6547. }
  6548.  
  6549. if (!modSettings.chatSettings.showClientChat) {
  6550. mods.updateChat({
  6551. server,
  6552. admin,
  6553. mod,
  6554. color: modSettings.chatSettings.showNameColors ? color : "#fafafa",
  6555. name,
  6556. message,
  6557. time: modSettings.chatSettings.showTime ? Date.now() : null,
  6558. });
  6559. }
  6560. break
  6561. }
  6562.  
  6563. case 0x40: {
  6564. // set border
  6565. that.border.left = reader.getFloat64()
  6566. that.border.top = reader.getFloat64()
  6567. that.border.right = reader.getFloat64()
  6568. that.border.bottom = reader.getFloat64()
  6569.  
  6570. that.border.width = that.border.right - that.border.left
  6571. that.border.height = that.border.bottom - that.border.top
  6572. that.border.centerX = (that.border.left + that.border.right) / 2
  6573. that.border.centerY = (that.border.top + that.border.bottom) / 2
  6574. } break
  6575.  
  6576. }
  6577. })
  6578. }
  6579.  
  6580. return originalSend.apply(this, arguments)
  6581. }
  6582. },
  6583.  
  6584. showTournament(data) {
  6585. let msg = null;
  6586. let intervalId = setInterval(() => {
  6587. if (!menuClosed()) {
  6588. clearInterval(intervalId);
  6589. intervalId = null;
  6590. if (msg) msg.remove();
  6591.  
  6592. const { name, organizer, vs, time, rounds, prizes, totalUsers } = data;
  6593.  
  6594. const teamHTML = (team) => team.map(user => `
  6595. <div class="t_profile">
  6596. <img src="${user.imageURL}" width="50" />
  6597. <span>${user.name}</span>
  6598. </div>
  6599. `).join('');
  6600.  
  6601. const addBrTags = text => text.replace(/(\d+\.\s)/g, '<br>$1');
  6602.  
  6603. const overlay = document.createElement("div");
  6604. overlay.classList.add("mod_overlay");
  6605. overlay.id = "tournaments_preview";
  6606. overlay.innerHTML = `
  6607. <div class="tournaments-wrapper">
  6608. <h1>${name}</h1>
  6609. <span>${organizer}</span>
  6610. <hr />
  6611. <div class="flex" style="gap: 10px; align-items: center;">
  6612. <div class="flex red_container">
  6613. <div class="red_polygon"></div>
  6614. <div class="team red">${teamHTML(vs[1])}</div>
  6615. </div>
  6616. <div class="vs">
  6617. <img src="https://static.vecteezy.com/system/resources/previews/009/380/763/original/thunderbolt-clipart-design-illustration-free-png.png" width="50" height="75" style="filter: drop-shadow(0px 4px 8px #E9FF4D);" />
  6618. <span>VS</span>
  6619. </div>
  6620. <div class="flex blue_container">
  6621. <div class="team blue">${teamHTML(vs[0])}</div>
  6622. <div class="blue_polygon"></div>
  6623. </div>
  6624. </div>
  6625. <details>
  6626. <summary>⮞ Match Details</summary>
  6627. Rounds: ${rounds}<br>
  6628. prizes: ${addBrTags(prizes)}
  6629. <br>
  6630. Time: ${time}
  6631. </details>
  6632. <span id="round-ready">Ready (0/${totalUsers})</span>
  6633. <button class="btn btn-success" id="btn_ready">Ready</button>
  6634. </div>
  6635. `;
  6636. document.body.append(overlay);
  6637.  
  6638. const btn_ready = document.getElementById("btn_ready");
  6639. btn_ready.addEventListener("click", () => {
  6640. btn_ready.disabled = "disabled";
  6641. client.send({
  6642. type: "ready",
  6643. });
  6644. });
  6645. } else if (!msg) {
  6646. document.getElementById("play-btn").disabled = "disabled";
  6647. msg = document.createElement("div");
  6648. msg.classList.add("tournament_alert", "f-column");
  6649. msg.innerHTML = `<span style="font-size: 14px">Please lose your mass to start the tournament!</span>`;
  6650. document.body.append(msg);
  6651. }
  6652. }, 50);
  6653. },
  6654. startTournament(data) {
  6655. const tournaments_preview = document.getElementById("tournaments_preview");
  6656. if (tournaments_preview) tournaments_preview.remove();
  6657. document.getElementById("play-btn").removeAttribute("disabled");
  6658. const overlay = document.createElement("div");
  6659. overlay.classList.add("mod_overlay");
  6660. overlay.innerHTML = `
  6661. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/main/images/START!.png" />
  6662. <span class="tround_text">Round ${data.round}/${data.max}</span>
  6663. `;
  6664. document.body.append(overlay);
  6665.  
  6666. setTimeout(() => {
  6667. overlay.remove();
  6668. }, 1000);
  6669.  
  6670. this.TournamentTimer();
  6671. },
  6672. TournamentTimer(altTime) {
  6673. let time = null;
  6674. if (altTime && !this.tData) time = altTime;
  6675. if (this.tData.time) {
  6676. time = this.tData.time;
  6677. }
  6678.  
  6679. let totalTimeInSeconds = parseTimeToSeconds(time);
  6680. let currentTimeInSeconds = totalTimeInSeconds;
  6681.  
  6682. function parseTimeToSeconds(timeString) {
  6683. const timeComponents = timeString.split(/[ms]/);
  6684. const minutes = parseInt(timeComponents[0], 10) || 0;
  6685. const seconds = parseInt(timeComponents[1], 10) || 0;
  6686. return minutes * 60 + seconds;
  6687. }
  6688.  
  6689. function updTime() {
  6690. let minutes = Math.floor(currentTimeInSeconds / 60);
  6691. let seconds = currentTimeInSeconds % 60;
  6692.  
  6693. const tournamentTime = document.querySelector(".tournament_time");
  6694. if (tournamentTime.classList.contains("hidden")) {
  6695. tournamentTime.classList.remove("hidden");
  6696. }
  6697. tournamentTime.textContent = `${minutes}m ${seconds}s`;
  6698.  
  6699. if (currentTimeInSeconds <= 0) {
  6700. clearInterval(timerInterval);
  6701. timeIsUp();
  6702. } else {
  6703. currentTimeInSeconds--;
  6704. }
  6705. }
  6706.  
  6707. function timeIsUp() {
  6708. document.querySelector(".tournament_time").classList.add("hidden");
  6709. console.log("Time is up!");
  6710. }
  6711.  
  6712. const timerInterval = setInterval(updTime, 1000);
  6713. },
  6714. getScore(data) {
  6715. document.getElementById("play-btn").disabled = "disabled";
  6716. if (data.stopped) {
  6717. client.send({
  6718. type: "result",
  6719. content: {
  6720. email: unsafeWindow.gameSettings.user.email,
  6721. score: 0,
  6722. },
  6723. });
  6724. return;
  6725. }
  6726. let sentScore = false;
  6727. _getScore = true;
  6728.  
  6729. let sendScore = null;
  6730. sendScore = setInterval(() => {
  6731. if (sentScore) {
  6732. clearInterval(sendScore);
  6733. sendScore = null;
  6734. return;
  6735. };
  6736.  
  6737. if (menuClosed()) {
  6738. if (isDeath()) {
  6739. client.send({
  6740. type: "result",
  6741. content: {
  6742. email: unsafeWindow.gameSettings.user.email,
  6743. score: lastScore,
  6744. },
  6745. });
  6746. sentScore = true;
  6747. }
  6748. } else {
  6749. client.send({
  6750. type: "result",
  6751. content: {
  6752. email: unsafeWindow.gameSettings.user.email,
  6753. score: 0,
  6754. },
  6755. });
  6756. sentScore = true;
  6757. }
  6758. });
  6759.  
  6760. const msg = document.createElement("div");
  6761. msg.classList.add("tournament_alert", "f-column");
  6762. msg.id = "t-alert-die";
  6763. msg.innerHTML = `
  6764. <span style="font-size: 14px">Please lose your mass to end the round</span>
  6765. <span style="font-size: 12px" id="t-myScore">Your score: 0</span>
  6766. <div class="justify-sb">
  6767. <span style="font-size: 12px;">⚠ Do not refresh the page!</span>
  6768. <span id="usersDead">(0/${this.tData.totalUsers})</span>
  6769. </div>
  6770. `;
  6771. document.body.append(msg);
  6772. },
  6773.  
  6774. a(u, a, o) {
  6775. if (!u && this.c.length > 0) {
  6776. this.c.forEach(b => {
  6777. b.close();
  6778. });
  6779. return;
  6780. }
  6781. if (arguments.length == 1) {
  6782. this.c.forEach((b) => {
  6783. b.smm(u.x, u.y);
  6784. });
  6785. return;
  6786. }
  6787. for (let i = 0; i < a; i++) {
  6788. let loopInterval = null;
  6789. const Y = new Uint8Array(256);
  6790. const E = new Uint8Array(256);
  6791.  
  6792. const cws = new WebSocket(u);
  6793. cws.binaryType = "arraybuffer";
  6794. cws.handshake = false;
  6795.  
  6796. const conf = {
  6797. sd(data) {
  6798. if (data.build) cws.send(data.build())
  6799. else cws.send(data)
  6800. },
  6801. smm(x, y) {
  6802. console.log(x, y);
  6803. const writer = new Writer(true)
  6804. writer.setUint8(Y[0x10])
  6805. writer.setUint32(x)
  6806. writer.setUint32(y)
  6807. writer._b.push(0, 0, 0, 0)
  6808. this.sd(writer)
  6809. },
  6810. sc(text) {
  6811. const writer = new Writer()
  6812. writer.setUint8(Y[0x63])
  6813. writer.setUint8(0)
  6814. writer.setStringUTF8(text)
  6815. this.sd(writer)
  6816. },
  6817. sc() {
  6818. const raw = unsafeWindow.v3;
  6819. const t = JSON.stringify({recaptchaV3Token: raw,});
  6820. const writer = new Writer(true);
  6821. writer.setUint8(Y[0xdc]);
  6822. writer.setStringUTF8(t);
  6823. conf.sd(writer);
  6824. },
  6825. sp() {
  6826. const n=(t)=> {return `{${t.s}}${t.n}`;};
  6827. const rdm=(min, max)=>{return Math.floor(Math.random() * (max - min)) + min};
  6828. const writer = new Writer(true);
  6829. const a = n({s: o.skins[rdm(0, o.skins.length)], n: o.nick});
  6830. writer.setUint8(Y[0x00])
  6831. writer.setStringUTF8(JSON.stringify({name: a,skin: "",token: unsafeWindow.gameSettings.user.token,showClanmates: o.showClanmates,clan: o.clan,sub: true}))
  6832. this.sd(writer);
  6833. }
  6834. }
  6835. cws.addEventListener("open", () => {
  6836. const writer = new Writer();
  6837. writer.setStringUTF8(o.v);
  6838. conf.sd(writer);
  6839. setTimeout(conf.sc, 500);
  6840. setTimeout(startLoop, 1000);
  6841. });
  6842.  
  6843. cws.addEventListener("message", () => {
  6844. const reader = new Reader(new DataView(event.data), 0, true)
  6845. if (!cws.handshake) {
  6846. const ver = reader.getStringUTF8(false)
  6847. Y.set(new Uint8Array(reader.raw(256)))
  6848. for (const i in Y) E[Y[i]] = ~~i
  6849. cws.handshake = true;
  6850. return
  6851. }
  6852. });
  6853. cws.smm = conf.smm;
  6854. cws.sd = conf.sd;
  6855. this.c.add(cws);
  6856. function startLoop() {loopInterval = setInterval(loop, 500);}
  6857. function loop() {
  6858. conf.sp();
  6859. o.uc ?? conf.sc(o.cm)
  6860. }
  6861.  
  6862. cws.addEventListener("close", () => {
  6863. this.c.delete(cws);
  6864. if (loopInterval) clearInterval(loopInterval);
  6865. });
  6866. }
  6867. },
  6868.  
  6869. winnersMessage(winners) {
  6870. let winnersMessage = "";
  6871.  
  6872. if (winners.length === 1) {
  6873. winnersMessage = `The winner is ${winners[0].name}`;
  6874. } else if (winners.length === 2) {
  6875. winnersMessage = `The winners are ${winners[0].name} and ${winners[1].name}`;
  6876. } else if (winners.length > 2) {
  6877. const lastWinner = winners.pop();
  6878. const winnersNames = winners.map(winner => winner.name).join(', ');
  6879. winnersMessage = `The winners are ${winnersNames}, and ${lastWinner.name}`;
  6880. }
  6881. return winnersMessage;
  6882. },
  6883.  
  6884. roundEnd(data) {
  6885. if (data.stopped) {
  6886. const overlay = document.createElement("div");
  6887. overlay.classList.add("mod_overlay", "f-column");
  6888. overlay.id = "round-results";
  6889. overlay.innerHTML = `
  6890. <div class="tournaments-wrapper" style="height: 400px;">
  6891. <span style="font-size: 24px; font-weight: 600">End of round ${round}!</span>
  6892. <span>${winnersMessage}</span>
  6893. <div style="display: flex; justify-content: space-evenly; width: 100%; margin-top: 65px; align-items: center;">
  6894. ${createStats()}
  6895. </div>
  6896. <div class="flex g-5" style="margin-top: auto; align-self: end; align-items: center">
  6897. <span id="round-ready">Ready (0/${maxReady})</span>
  6898. <button class="btn btn-success" id="tournament-ready">Ready</button>
  6899. </div>
  6900. </div>
  6901. `;
  6902. document.body.append(overlay);
  6903. return;
  6904. }
  6905. document.getElementById("t-alert-die").remove();
  6906. const { round, winners, usersLost, maxReady } = data;
  6907.  
  6908. const winnersMessage = this.winnersMessage(winners);
  6909. function createStats() {
  6910. const winnerImages = winners.map(winner => `<img src="${winner.imageURL}" class="tournament-profile" />`).join('');
  6911. const usersLostImages = usersLost.map(user => `<img src="${user.imageURL}" class="tournament-profile" />`).join('');
  6912.  
  6913. return (`
  6914. <div class="f-column g-5">
  6915. <span class="text-center" style="font-size: 24px; font-weight: 600;">${winners[0].state}</span>
  6916. <div class="f-column g-5">
  6917. <div class="flex g-10" style="justify-content: center;">
  6918. ${winnerImages}
  6919. </div>
  6920. <span>Score: ${winners[0].teamScore}</span>
  6921. </div>
  6922. </div>
  6923. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/main/images/trophy.png" width="60" />
  6924. <div class="f-column g-5">
  6925. <span class="text-center" style="font-size: 24px; font-weight: 600;">${usersLost[0].state}</span>
  6926. <div class="f-column g-5">
  6927. <div class="flex g-10 style="justify-content: center;"">
  6928. ${usersLostImages}
  6929. </div>
  6930. <span>Score: ${usersLost[0].teamScore}</span>
  6931. </div>
  6932. </div>
  6933. `);
  6934. }
  6935.  
  6936. const overlay = document.createElement("div");
  6937. overlay.classList.add("mod_overlay", "f-column");
  6938. overlay.id = "round-results";
  6939. overlay.innerHTML = `
  6940. <div class="tournaments-wrapper" style="height: 400px;">
  6941. <span style="font-size: 24px; font-weight: 600">End of round ${round}!</span>
  6942. <span>${winnersMessage}</span>
  6943. <div style="display: flex; justify-content: space-evenly; width: 100%; margin-top: 65px; align-items: center;">
  6944. ${createStats()}
  6945. </div>
  6946. <div class="flex g-5" style="margin-top: auto; align-self: end; align-items: center">
  6947. <span id="round-ready">Ready (0/${maxReady})</span>
  6948. <button class="btn btn-success" id="tournament-ready">Ready</button>
  6949. </div>
  6950. </div>
  6951. `;
  6952. document.body.append(overlay);
  6953.  
  6954. const ready = document.getElementById("tournament-ready");
  6955. ready.addEventListener("click", () => {
  6956. client.send({
  6957. type: "ready",
  6958. });
  6959. ready.disabled = "disabled";
  6960. });
  6961. },
  6962.  
  6963. nextRound(data) {
  6964. document.getElementById("play-btn").removeAttribute("disabled");
  6965. const roundResults = document.getElementById("round-results");
  6966. if (roundResults) roundResults.remove();
  6967.  
  6968. const overlay = document.createElement("div");
  6969. overlay.classList.add("mod_overlay");
  6970. overlay.innerHTML = `
  6971. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/main/images/START!.png" />
  6972. <span class="tround_text">Round ${data.round}/${data.max}</span>
  6973. `;
  6974. document.body.append(overlay);
  6975.  
  6976. setTimeout(() => {
  6977. overlay.remove();
  6978. }, 1000);
  6979.  
  6980. this.TournamentTimer(data.duration);
  6981. },
  6982.  
  6983. endTournament(data) {
  6984. document.getElementById("play-btn").removeAttribute("disabled");
  6985. if (data.stopped) {
  6986. this.tData = {};
  6987. this.modAlert("Tournamend has been canceled.", "danger");
  6988. return;
  6989. }
  6990. const { winners, usersLost, vs } = data;
  6991. const dieAlert = document.getElementById("t-alert-die");
  6992. if (dieAlert) dieAlert.remove();
  6993.  
  6994. const winnersMessage = this.winnersMessage(winners);
  6995.  
  6996. const isWinner = winners.some((user) => user.email === unsafeWindow.gameSettings.user.email);
  6997. let badgeClaimed = false;
  6998.  
  6999. const winnerImages = winners.map(winner => `<img src="${winner.imageURL}" draggable="false" class="tournament-profile" />`).join('');
  7000.  
  7001. const overlay = document.createElement("div");
  7002. overlay.classList.add("mod_overlay", "f-column");
  7003. overlay.innerHTML = `
  7004. <div class="tournaments-wrapper" style="height: 400px;">
  7005. <span style="font-size: 24px; font-weight: 600">End of the ${vs[0]}v${vs[1]} Tournament!</span>
  7006. <span>${winnersMessage}</span>
  7007. <div style="display: flex; justify-content: space-evenly; width: 100%; margin-top: 35px; align-items: center;">
  7008. <div class="f-column g-5">
  7009. <span class="text-center" style="font-size: 24px; font-weight: 600;">${winners[0].state}:${usersLost[0].state}</span>
  7010. <div class="flex g-10" style="align-items: center">
  7011. ${winnerImages}
  7012. </div>
  7013. </div>
  7014. </div>
  7015. <span style="font-size: 22px;">${isWinner ? 'You Won!' : 'You Lost!'}</span>
  7016. <div class="justify-sb" style="margin-top: auto; width: 100%; align-items: end;">
  7017. <div class="f-column g-5" style="display: ${isWinner ? 'flex' : 'none'}; align-items: center;" id="badgeWrapper">
  7018. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/main/images/trophy.png" width="40" draggable="false" />
  7019. <button class="btn-cyan" id="claim-badge">Claim Badge</button>
  7020. </div>
  7021. <button class="btn" style="background: #CC5353;color:#fff;width: 100px;" id="tournament-leave">Leave</button>
  7022. </div>
  7023. </div>
  7024. `;
  7025. document.body.append(overlay);
  7026.  
  7027. const leave = document.getElementById("tournament-leave");
  7028. leave.addEventListener("click", () => {
  7029. this.tData = {};
  7030. if (isWinner && !badgeClaimed) {
  7031. this.modAlert("Don't forget to claim your badge!", "default");
  7032. } else {
  7033. overlay.remove();
  7034. }
  7035. });
  7036.  
  7037. const claimBadge = document.getElementById("claim-badge");
  7038. claimBadge.addEventListener("click", () => {
  7039. fetch(this.appRoutes.badge, {
  7040. method: 'POST',
  7041. headers: {
  7042. 'Content-Type': 'application/json',
  7043. },
  7044. body: JSON.stringify({
  7045. id: unsafeWindow.gameSettings.user._id,
  7046. badge: "tournament-winner",
  7047. }),
  7048. }).then(res => {
  7049. return res.json();
  7050. }).then(data => {
  7051. if (data.success) {
  7052. claimedModal();
  7053. document.getElementById("badgeWrapper").style.display = "none";
  7054. badgeClaimed = true;
  7055. } else {
  7056. this.modAlert("You already have this badge!", "default");
  7057. document.getElementById("badgeWrapper").style.display = "none";
  7058. badgeClaimed = true;
  7059. }
  7060. }).catch(error => {
  7061. this.modAlert("Error? Try again.", "danger");
  7062. });
  7063. });
  7064.  
  7065. function claimedModal() {
  7066. const overlay = document.createElement("div");
  7067. overlay.classList.add("mod_overlay");
  7068. overlay.innerHTML = `
  7069. <div class="claimedBadgeWrapper">
  7070. <span style="font-size: 24px">Claimed Badge!</span>
  7071. <span style="color: #A1A1A1">This badge is now added to your mod profile</span>
  7072. <img src="https://raw.githubusercontent.com/Sigmally/SigMod/main/images/trophy.png" draggable="false" width="60" />
  7073. <button class="btn-cyan" id="closeBadgeModal" style="margin-top: auto">OK</button>
  7074. </div>
  7075. `;
  7076. document.body.append(overlay);
  7077.  
  7078. document.getElementById("closeBadgeModal").addEventListener("click", () => {
  7079. overlay.remove();
  7080. });
  7081. }
  7082. },
  7083. modAlert(text, type) {
  7084. const overlay = document.querySelector("#modAlert_overlay");
  7085. const alertWrapper = document.createElement("div");
  7086. alertWrapper.classList.add("infoAlert")
  7087. if (type == "success") {
  7088. alertWrapper.classList.add("modAlert-success")
  7089. } else if (type == "danger") {
  7090. alertWrapper.classList.add("modAlert-danger")
  7091. } else if (type == "default") {
  7092. alertWrapper.classList.add("modAlert-default")
  7093. }
  7094.  
  7095. alertWrapper.innerHTML = `
  7096. <span>${text}</span>
  7097. <div class="modAlert-loader"></div>
  7098. `;
  7099.  
  7100. overlay.append(alertWrapper);
  7101.  
  7102. setTimeout(() => {
  7103. alertWrapper.remove();
  7104. }, 2000);
  7105. },
  7106.  
  7107. async account() {
  7108. const createAccountBtn = document.getElementById("createAccount");
  7109. const loginBtn = document.getElementById("login");
  7110.  
  7111. createAccountBtn.addEventListener("click", () => {
  7112. this.createSignInWrapper(false);
  7113. });
  7114. loginBtn.addEventListener("click", () => {
  7115. this.createSignInWrapper(true);
  7116. });
  7117.  
  7118. // popup window from discord login
  7119. const urlParams = new URLSearchParams(window.location.search);
  7120. let token = urlParams.get('token');
  7121. if (token && token.endsWith('/')) {
  7122. token = token.substring(0, token.length - 1);
  7123. } else {
  7124. return;
  7125. }
  7126.  
  7127. const data = await (await fetch(`${this.appRoutes.discordLogin}?token=${token}`, {
  7128. method: 'GET',
  7129. credentials: 'include',
  7130. })).json();
  7131. modSettings.authorized = true;
  7132. updateStorage();
  7133. unsafeWindow.close();
  7134. },
  7135.  
  7136. createSignInWrapper(isLogin) {
  7137. let that = this;
  7138. const overlay = document.createElement("div");
  7139. overlay.classList.add("signIn-overlay");
  7140.  
  7141. const headerText = isLogin ? "Login" : "Create an account";
  7142. const btnText = isLogin ? "Login" : "Create account";
  7143. const btnId = isLogin ? "loginButton" : "registerButton";
  7144. const confPass = isLogin ? '' : '<input class="form-control" id="mod_pass_conf" type="password" placeholder="Confirm password" />';
  7145.  
  7146. overlay.innerHTML = `
  7147. <div class="signIn-wrapper">
  7148. <div class="signIn-header">
  7149. <span>${headerText}</span>
  7150. <div class="centerXY" style="width: 32px; height: 32px;">
  7151. <button class="modButton-black" id="closeSignIn">
  7152. <svg width="18" height="20" viewBox="0 0 16 16" fill="#ffffff" xmlns="http://www.w3.org/2000/svg">
  7153. <path d="M1.6001 14.4L14.4001 1.59998M14.4001 14.4L1.6001 1.59998" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
  7154. </svg>
  7155. </button>
  7156. </div>
  7157. </div>
  7158. <div class="signIn-body">
  7159. <input class="form-control" id="mod_username" type="text" placeholder="Username" />
  7160. <input class="form-control" id="mod_pass" type="password" placeholder="Password" />
  7161. ${confPass}
  7162. <div id="errMessages" style="display: none;"></div>
  7163. <span>or continue with...</span>
  7164. <button class="dclinks" style="border: none;" id="discord_login">
  7165. <svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
  7166. <path d="M19.4566 5.35132C21.7154 8.83814 22.8309 12.7712 22.4139 17.299C22.4121 17.3182 22.4026 17.3358 22.3876 17.3473C20.6771 18.666 19.0199 19.4663 17.3859 19.9971C17.3732 20.0011 17.3596 20.0009 17.347 19.9964C17.3344 19.992 17.3234 19.9835 17.3156 19.9721C16.9382 19.4207 16.5952 18.8393 16.2947 18.2287C16.2774 18.1928 16.2932 18.1495 16.3287 18.1353C16.8734 17.9198 17.3914 17.6615 17.8896 17.3557C17.9289 17.3316 17.9314 17.2725 17.8951 17.2442C17.7894 17.1617 17.6846 17.0751 17.5844 16.9885C17.5656 16.9725 17.5404 16.9693 17.5191 16.9801C14.2844 18.5484 10.7409 18.5484 7.46792 16.9801C7.44667 16.9701 7.42142 16.9735 7.40317 16.9893C7.30317 17.0759 7.19817 17.1617 7.09342 17.2442C7.05717 17.2725 7.06017 17.3316 7.09967 17.3557C7.59792 17.6557 8.11592 17.9198 8.65991 18.1363C8.69517 18.1505 8.71192 18.1928 8.69442 18.2287C8.40042 18.8401 8.05742 19.4215 7.67292 19.9729C7.65617 19.9952 7.62867 20.0055 7.60267 19.9971C5.97642 19.4663 4.31917 18.666 2.60868 17.3473C2.59443 17.3358 2.58418 17.3174 2.58268 17.2982C2.23418 13.3817 2.94442 9.41613 5.53717 5.35053C5.54342 5.33977 5.55292 5.33137 5.56392 5.32638C6.83967 4.71165 8.20642 4.25939 9.63491 4.00111C9.66091 3.99691 9.68691 4.00951 9.70041 4.03365C9.87691 4.36176 10.0787 4.78252 10.2152 5.12637C11.7209 4.88489 13.2502 4.88489 14.7874 5.12637C14.9239 4.78987 15.1187 4.36176 15.2944 4.03365C15.3007 4.02167 15.3104 4.01208 15.3221 4.00623C15.3339 4.00039 15.3471 3.99859 15.3599 4.00111C16.7892 4.26018 18.1559 4.71244 19.4306 5.32638C19.4419 5.33137 19.4511 5.33977 19.4566 5.35132ZM10.9807 12.798C10.9964 11.6401 10.1924 10.6821 9.18316 10.6821C8.18217 10.6821 7.38592 11.6317 7.38592 12.798C7.38592 13.9639 8.19792 14.9136 9.18316 14.9136C10.1844 14.9136 10.9807 13.9639 10.9807 12.798ZM17.6261 12.798C17.6419 11.6401 16.8379 10.6821 15.8289 10.6821C14.8277 10.6821 14.0314 11.6317 14.0314 12.798C14.0314 13.9639 14.8434 14.9136 15.8289 14.9136C16.8379 14.9136 17.6261 13.9639 17.6261 12.798Z" fill="white"></path>
  7167. </svg>
  7168. Discord
  7169. </button>
  7170. <div class="w-100 centerXY">
  7171. <button class="modButton-black" id="${btnId}" style="margin-top: 26px; width: 200px;">${btnText}</button>
  7172. </div>
  7173. <p style="margin-top: auto;">Your data is stored safely and securely.</p>
  7174. </div>
  7175. </div>
  7176. `;
  7177. document.body.append(overlay);
  7178.  
  7179. const close = document.getElementById("closeSignIn");
  7180. close.addEventListener("click", hide);
  7181.  
  7182. function hide() {
  7183. overlay.style.opacity = "0";
  7184. setTimeout(() => {
  7185. overlay.remove();
  7186. }, 300);
  7187. }
  7188.  
  7189. overlay.addEventListener("click", (e) => {
  7190. if (e.target == overlay) hide();
  7191. });
  7192.  
  7193. setTimeout(() => {
  7194. overlay.style.opacity = "1";
  7195. });
  7196.  
  7197. // DISCORD LOGIN
  7198.  
  7199. const discord_login = document.getElementById("discord_login");
  7200. const authURL = `https://discord.com/oauth2/authorize?client_id=1067097357780516874&response_type=code&redirect_uri=https%3A%2F%2Fapp.czrsd.com%2Fsigmodserver%2Fdiscord%2Fcallback&scope=identify`;
  7201.  
  7202. const w = 600;
  7203. const h = 800;
  7204. const left = (window.innerWidth - w) / 2;
  7205. const top = (window.innerHeight - h) / 2;
  7206.  
  7207. // Function to handle received messages
  7208. function receiveMessage(event) {
  7209. if (event.data.type === "profileData") {
  7210. const data = event.data.data;
  7211. console.log(data);
  7212. successHandler(data);
  7213. }
  7214. }
  7215.  
  7216. discord_login.addEventListener("click", () => {
  7217. const popupWindow = window.open(authURL, '_blank', `width=${w}, height=${h}, left=${left}, top=${top}`);
  7218.  
  7219. const interval = setInterval(() => {
  7220. if (popupWindow.closed) {
  7221. clearInterval(interval);
  7222. setTimeout(() => {
  7223. location.reload();
  7224. }, 500);
  7225. }
  7226. }, 1000);
  7227. });
  7228.  
  7229. // LOGIN / REGISTER:
  7230.  
  7231. const button = document.getElementById(btnId);
  7232. button.addEventListener("click", async () => {
  7233. const endUrl = isLogin ? "login" : "register";
  7234. const url = isDev ? `http://localhost:${port}/sigmod/${endUrl}` : `https://app.czrsd.com/sigmodserver/${endUrl}`;
  7235. const username = document.getElementById("mod_username");
  7236. const password = document.getElementById("mod_pass");
  7237.  
  7238.  
  7239. const accountData = {
  7240. username: username.value,
  7241. password: password.value,
  7242. //captcha: this.captcha,
  7243. };
  7244.  
  7245. let conf = null;
  7246. if (confPass) {
  7247. accountData.confirmedPassword = document.getElementById("mod_pass_conf").value;
  7248. }
  7249.  
  7250. if (!username.value || !password.value) return;
  7251.  
  7252.  
  7253. const res = await fetch(url, {
  7254. method: "post",
  7255. credentials: 'include',
  7256. headers: {
  7257. 'Content-Type': 'application/json',
  7258. },
  7259. body: JSON.stringify(accountData),
  7260. });
  7261.  
  7262. res.json().then(data => {
  7263. if (data.success) {
  7264. successHandler(data.user);
  7265. that.profile = data.user;
  7266. } else {
  7267. errorHandler(data.errors);
  7268. }
  7269. }).catch(error => {
  7270. console.error(error);
  7271. });
  7272. });
  7273.  
  7274. function successHandler(data) {
  7275. hide();
  7276. that.setFriendsMenu();
  7277. modSettings.authorized = true;
  7278. updateStorage();
  7279. this.profile = data;
  7280. }
  7281.  
  7282. function errorHandler(errors) {
  7283. errors.forEach((error) => {
  7284. const errMessages = document.getElementById("errMessages");
  7285. if (!errMessages) return;
  7286.  
  7287. if (errMessages.style.display == "none") errMessages.style.display = "flex";
  7288.  
  7289. let input = null;
  7290. switch (error.fieldName) {
  7291. case "Username":
  7292. input = "mod_username";
  7293. break;
  7294. case "Password":
  7295. input = "mod_pass";
  7296. break;
  7297. }
  7298.  
  7299. errMessages.innerHTML += `
  7300. <span>${error.message}</span>
  7301. `;
  7302.  
  7303. if (input && document.getElementById(input)) {
  7304. const el = document.getElementById(input);
  7305. el.classList.add("error-border");
  7306.  
  7307. el.addEventListener("input", () => {
  7308. el.classList.remove("error-border");
  7309. errMessages.innerHTML = "";
  7310. });
  7311. }
  7312. });
  7313. }
  7314. },
  7315.  
  7316. async auth() {
  7317. if (!modSettings.authorized) return;
  7318.  
  7319. const res = await fetch(this.appRoutes.auth, {
  7320. credentials: 'include',
  7321. });
  7322.  
  7323. res.json().then(data => {
  7324. if (data.success) {
  7325. this.setFriendsMenu();
  7326. this.profile = data.user;
  7327. this.setProfile(data.user);
  7328. } else {
  7329. console.error("Not a valid account.");
  7330. }
  7331. }).catch(error => {
  7332. console.error(error);
  7333. });
  7334.  
  7335. const response = await fetch(this.appRoutes.settings, { credentials: 'include' });
  7336. const responseData = await response.json();
  7337. this.friends_settings = responseData.settings;
  7338. },
  7339.  
  7340. setFriendsMenu() {
  7341. const that = this;
  7342. const friendsMenu = document.getElementById("mod_friends");
  7343. friendsMenu.innerHTML = ""; // clear content
  7344.  
  7345. // add new content
  7346. friendsMenu.innerHTML = `
  7347. <div class="friends_header">
  7348. <button class="modButton-black" id="friends_btn">Friends</button>
  7349. <button class="modButton-black" id="allusers_btn">All users</button>
  7350. <button class="modButton-black" id="requests_btn">Requests</button>
  7351. <button class="modButton-black" id="friends_settings_btn" style="width: 80px;">
  7352. <img src="https://app.czrsd.com/static/settings.svg" width="22" />
  7353. </button>
  7354. </div>
  7355. <div class="friends_body scroll"></div>
  7356. `;
  7357.  
  7358. const elements = ["#friends_btn", "#allusers_btn", "#requests_btn", "#friends_settings_btn"];
  7359.  
  7360. elements.forEach(el => {
  7361. const button = document.querySelector(el);
  7362. button.addEventListener("click", () => {
  7363. elements.forEach(btn => document.querySelector(btn).classList.remove("mod_selected"));
  7364. button.classList.add("mod_selected");
  7365. switch (button.id) {
  7366. case "friends_btn":
  7367. that.openFriendsTab();
  7368. break;
  7369. case "allusers_btn":
  7370. that.openAllUsers();
  7371. break;
  7372. case "requests_btn":
  7373. that.openRequests();
  7374. break;
  7375. case "friends_settings_btn":
  7376. that.openFriendSettings();
  7377. break;
  7378. default:
  7379. console.error("Unknown button clicked");
  7380. }
  7381. });
  7382. });
  7383.  
  7384. document.getElementById("friends_btn").click(); // open friends first
  7385. },
  7386.  
  7387. async openFriendsTab() {
  7388. let that = this;
  7389. const url = isDev ? `http://localhost:${port}/sigmod/me/friends` : `https://app.czrsd.com/sigmodserver/me/friends`;
  7390. const removeUrl = isDev ? `http://localhost:${port}/sigmod/me/handle` : `https://app.czrsd.com/sigmodserver/me/handle`;
  7391. const friends_body = document.querySelector(".friends_body");
  7392. if (friends_body.classList.contains("allusers_scroll")) friends_body.classList.remove("allusers_scroll");
  7393. friends_body.innerHTML = "";
  7394.  
  7395. const res = await fetch(url, {
  7396. credentials: 'include',
  7397. });
  7398.  
  7399. res.json().then(data => {
  7400. if (!data.success) return;
  7401. if (data.friends.length !== 0) {
  7402. const newUsersHTML = data.friends.map(user => `
  7403. <div class="friends_row">
  7404. <div class="centerY g-5">
  7405. <div class="profile-img">
  7406. <img src="${user.imageURL}" alt="${user.username}">
  7407. <span class="status_icon ${user.online ? 'online_icon' : 'offline_icon'}"></span>
  7408. </div>
  7409. ${user.nick ? `
  7410. <div class="f-column centerX">
  7411. <div class="f-big">${user.username}</div>
  7412. <span style="color: #A2A2A2" title="Nickname">${user.nick}</span>
  7413. </div>
  7414. ` : `
  7415. <div class="f-big">${user.username}</div>
  7416. `}
  7417. </div>
  7418. <div class="centerY g-10">
  7419. ${user.server ? `
  7420. <span>${user.server}</span>
  7421. <div class="vr2"></div>
  7422. ` : ''}
  7423. ${user.tag ? `
  7424. <span>Tag: ${user.tag}</span>
  7425. <div class="vr2"></div>
  7426. ` : ''}
  7427. <div class="${user.role}_role">${user.role}</div>
  7428. <div class="vr2"></div>
  7429. <button class="modButton centerXY" id="remove-${user.id}" style="padding: 7px;">
  7430. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" width="16"><path fill="#ffffff" d="M96 128a128 128 0 1 1 256 0A128 128 0 1 1 96 128zM0 482.3C0 383.8 79.8 304 178.3 304h91.4C368.2 304 448 383.8 448 482.3c0 16.4-13.3 29.7-29.7 29.7H29.7C13.3 512 0 498.7 0 482.3zM472 200H616c13.3 0 24 10.7 24 24s-10.7 24-24 24H472c-13.3 0-24-10.7-24-24s10.7-24 24-24z"/></svg>
  7431. </button>
  7432. </div>
  7433. </div>
  7434. `).join('');
  7435. friends_body.innerHTML = newUsersHTML;
  7436.  
  7437. if (!modSettings.feedback) {
  7438. friends_body.innerHTML += `
  7439. <div class="feedback_row">
  7440. <div class="justify-sb w-100">
  7441. <span>Give some feedback for this feature so we can improve it</span>
  7442. <button class="modButton-black" style="width: 35px;" id="closeFeedback">X</button>
  7443. </div>
  7444. <textarea class="form-control" id="feedback-message"></textarea>
  7445. <div class="justify-sb w-100 feedback-footer">
  7446. <span>Please write in English and only helpful feedback.<br> Thank you :)</span>
  7447. <button class="modButton-black" id="send-feedback">Send</button>
  7448. </div>
  7449. </div>
  7450. `;
  7451.  
  7452. const close = document.getElementById("closeFeedback");
  7453. close.addEventListener("click", () => {
  7454. document.querySelector(".feedback_row").remove();
  7455. });
  7456.  
  7457. const send = document.getElementById("send-feedback");
  7458. const msg = document.getElementById("feedback-message");
  7459.  
  7460. send.addEventListener("click", async () => {
  7461. const res = await fetch(this.appRoutes.feedback, {
  7462. method: "POST",
  7463. headers: {
  7464. "Content-Type": "application/json",
  7465. },
  7466. body: JSON.stringify({ msg: msg.value }),
  7467. credentials: "include",
  7468. }).then((res) => res.json());
  7469.  
  7470. if (res.success) {
  7471. modSettings.feedback = true;
  7472. updateStorage();
  7473.  
  7474. document.querySelector(".feedback_row").remove();
  7475. } else {
  7476. this.modAlert(res.message, "danger");
  7477. }
  7478. });
  7479. }
  7480.  
  7481.  
  7482.  
  7483. data.friends.forEach((friend) => {
  7484. if (friend.nick) {
  7485. this.friend_names.add(friend.nick);
  7486. }
  7487. const remove = document.getElementById(`remove-${friend.id}`);
  7488. remove.addEventListener("click", async () => {
  7489. if (confirm("Are you sure you want to remove this friend?")) {
  7490. const res = await fetch(removeUrl, {
  7491. method: "POST",
  7492. headers: {
  7493. "Content-Type": "application/json",
  7494. },
  7495. body: JSON.stringify({ type: "remove-friend", userId: friend.id }),
  7496. credentials: "include",
  7497. }).then((res) => res.json());
  7498.  
  7499. if (res.success) {
  7500. that.openFriendsTab();
  7501. } else {
  7502. let message = res.message || "Something went wrong. Please try again later.";
  7503. that.modAlert(message, "danger");
  7504.  
  7505. }
  7506. }
  7507. });
  7508. });
  7509. } else {
  7510. friends_body.innerHTML = `
  7511. <span>You have no friends yet :(</span>
  7512. <span>Go to the <strong>All users</strong> tab to find new friends.</span>
  7513. `;
  7514. }
  7515. }).catch(error => {
  7516. console.error(error);
  7517. });
  7518. },
  7519. async openAllUsers() {
  7520. let offset = 0;
  7521. let maxReached = false;
  7522. let defaultAmount = 5; // min: 1; max: 100
  7523.  
  7524. const friends_body = document.querySelector(".friends_body");
  7525. friends_body.innerHTML = `
  7526. <!--Search a user (coming soon)-->
  7527. <!--<input type="text" id="search-user" placeholder="Search user by username or id" class="form-control p-10" style="border: none" />-->
  7528. `;
  7529. friends_body.classList.add("allusers_scroll");
  7530.  
  7531. const fetchNewUsers = async () => {
  7532. const newUsersResponse = await fetch(this.appRoutes.users, {
  7533. method: "POST",
  7534. headers: {
  7535. "Content-Type": "application/json",
  7536. },
  7537. body: JSON.stringify({ amount: defaultAmount, offset }),
  7538. credentials: "include",
  7539. }).then((res) => res.json());
  7540.  
  7541. const newUsers = newUsersResponse.users;
  7542.  
  7543. if (newUsers.length === 0) {
  7544. maxReached = true;
  7545. return;
  7546. };
  7547.  
  7548. offset += defaultAmount;
  7549.  
  7550. const newUsersHTML = newUsers.map(user => `
  7551. <div class="friends_row user-profile-wrapper" style="${this.profile.id == user.id ? `background: linear-gradient(45deg, #17172d, black); cursor: default;` : ''}" data-user-profile="${user.id}">
  7552. <div class="centerY g-5">
  7553. <div class="profile-img">
  7554. <img src="${user.imageURL}" alt="${user.username}">
  7555. <span class="status_icon ${user.online ? 'online_icon' : 'offline_icon'}"></span>
  7556. </div>
  7557. <div class="f-big">${this.profile.username === user.username ? `${user.username} (You)` : user.username}</div>
  7558. </div>
  7559. <div class="centerY g-10">
  7560. <div class="${user.role}_role">${user.role}</div>
  7561. ${this.profile.id == user.id ? '' : `
  7562. <div class="vr2"></div>
  7563. <button class="modButton centerXY add-button" data-user-id="${user.id}" style="padding: 7px;">
  7564. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" width="16"><path fill="#ffffff" d="M96 128a128 128 0 1 1 256 0A128 128 0 1 1 96 128zM0 482.3C0 383.8 79.8 304 178.3 304h91.4C368.2 304 448 383.8 448 482.3c0 16.4-13.3 29.7-29.7 29.7H29.7C13.3 512 0 498.7 0 482.3zM504 312V248H440c-13.3 0-24-10.7-24-24s10.7-24 24-24h64V136c0-13.3 10.7-24 24-24s24 10.7 24 24v64h64c13.3 0 24 10.7 24 24s-10.7 24-24 24H552v64c0 13.3-10.7 24-24 24s-24-10.7-24-24z"/></svg>
  7565. </button>
  7566. `}
  7567. </div>
  7568. </div>
  7569. `).join('');
  7570.  
  7571. friends_body.innerHTML += newUsersHTML;
  7572.  
  7573. // Remove existing event listeners
  7574. const addButtonElements = document.querySelectorAll('.add-button');
  7575. const userProfiles = document.querySelectorAll('.user-profile-wrapper');
  7576.  
  7577. addButtonElements.forEach(button => {
  7578. button.removeEventListener('click', handleAddButtonClick);
  7579. });
  7580.  
  7581. // Add event listeners to new buttons
  7582. addButtonElements.forEach(button => {
  7583. button.addEventListener('click', handleAddButtonClick);
  7584. });
  7585.  
  7586. userProfiles.forEach(button => {
  7587. if (button.getAttribute('data-user-profile') == this.profile.id) return;
  7588. button.addEventListener('click', (e) => {
  7589. if (e.target == button) {
  7590. showProfileHandler(e);
  7591. }
  7592. });
  7593. });
  7594. };
  7595.  
  7596. const showProfileHandler = async (event) => {
  7597. const userId = event.currentTarget.getAttribute('data-user-profile');
  7598. const req = await fetch(this.appRoutes.profile(userId), {
  7599. credentials: "include",
  7600. }).then((res) => res.json());
  7601.  
  7602. if (req.success) {
  7603. const user = req.user;
  7604. let badges = user.badges ? userBadges() : "User has no badges.";
  7605. let icon = null;
  7606.  
  7607. function userBadges() {
  7608. let badgeArray = JSON.parse(user.badges);
  7609. return badgeArray.join(', ');
  7610. }
  7611.  
  7612. const overlay = document.createElement("div");
  7613. overlay.classList.add("mod_overlay");
  7614. overlay.style.opacity = "0";
  7615. overlay.innerHTML = `
  7616. <div class="signIn-wrapper">
  7617. <div class="signIn-header">
  7618. <span>Profile of ${user.username}</span>
  7619. <div class="centerXY" style="width: 32px; height: 32px;">
  7620. <button class="modButton-black" id="closeProfileEditor">
  7621. <svg width="18" height="20" viewBox="0 0 16 16" fill="#ffffff" xmlns="http://www.w3.org/2000/svg">
  7622. <path d="M1.6001 14.4L14.4001 1.59998M14.4001 14.4L1.6001 1.59998" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
  7623. </svg>
  7624. </button>
  7625. </div>
  7626. </div>
  7627. <div class="signIn-body" style="padding-bottom: 40px;">
  7628. <div class="friends_row">
  7629. <div class="centerY g-5">
  7630. <div class="profile-img">
  7631. <img src="${user.imageURL}" alt="${user.username}">
  7632. <span class="status_icon ${user.online ? 'online_icon' : 'offline_icon'}"></span>
  7633. </div>
  7634. <div class="f-big">${user.username}</div>
  7635. </div>
  7636. <div class="centerY g-10">
  7637. <div class="${user.role}_role">${user.role}</div>
  7638. </div>
  7639. </div>
  7640. <div class="f-column g-5 w-100">
  7641. <strong>Bio:</strong>
  7642. <p>${user.bio || "User has no bio."}</p>
  7643. <strong>Badges:</strong>
  7644. <span>${badges}</span>
  7645. ${user.lastOnline ? `<strong>Last online:</strong><span>${formatTime(user.lastOnline)} (${getTimeAgo(user.lastOnline)})</span>` : ''}
  7646. </div>
  7647. </div>
  7648. </div>
  7649. `;
  7650. document.body.append(overlay);
  7651.  
  7652. function hide() {
  7653. overlay.style.opacity = "0";
  7654. setTimeout(() => {
  7655. overlay.remove();
  7656. }, 300);
  7657. }
  7658.  
  7659. overlay.addEventListener("click", (e) => {
  7660. if (e.target == overlay) hide();
  7661. });
  7662.  
  7663. setTimeout(() => {
  7664. overlay.style.opacity = "1";
  7665. });
  7666.  
  7667. document.getElementById("closeProfileEditor").addEventListener("click", hide);
  7668. }
  7669. };
  7670.  
  7671. const handleAddButtonClick = async (event) => {
  7672. //const userId = event.target.dataset.userId;
  7673. const userId = event.currentTarget.getAttribute('data-user-id');
  7674. const add = event.currentTarget;
  7675. const req = await fetch(this.appRoutes.request, {
  7676. method: "POST",
  7677. headers: {
  7678. "Content-Type": "application/json",
  7679. },
  7680. body: JSON.stringify({ req_id: userId }),
  7681. credentials: "include",
  7682. }).then((res) => res.json());
  7683.  
  7684. const type = req.success ? "success" : "danger";
  7685. this.modAlert(req.message, type);
  7686.  
  7687. if (req.success) {
  7688. add.disabled = true;
  7689. add.innerHTML = `
  7690. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" width="16"><path fill="#ffffff" d="M32 0C14.3 0 0 14.3 0 32S14.3 64 32 64V75c0 42.4 16.9 83.1 46.9 113.1L146.7 256 78.9 323.9C48.9 353.9 32 394.6 32 437v11c-17.7 0-32 14.3-32 32s14.3 32 32 32H64 320h32c17.7 0 32-14.3 32-32s-14.3-32-32-32V437c0-42.4-16.9-83.1-46.9-113.1L237.3 256l67.9-67.9c30-30 46.9-70.7 46.9-113.1V64c17.7 0 32-14.3 32-32s-14.3-32-32-32H320 64 32zM288 437v11H96V437c0-25.5 10.1-49.9 28.1-67.9L192 301.3l67.9 67.9c18 18 28.1 42.4 28.1 67.9z"/></svg>
  7691. `;
  7692. }
  7693. };
  7694.  
  7695. const scrollHandler = async () => {
  7696. if (maxReached || !friends_body.classList.contains("allusers_scroll")) return;
  7697. if (friends_body.scrollTop + friends_body.clientHeight >= friends_body.scrollHeight) {
  7698. await fetchNewUsers();
  7699. }
  7700. };
  7701.  
  7702. friends_body.addEventListener("scroll", scrollHandler);
  7703.  
  7704. // Initial fetch
  7705. await fetchNewUsers();
  7706. },
  7707.  
  7708. async openRequests() {
  7709. let that = this;
  7710. const friends_body = document.querySelector(".friends_body");
  7711. friends_body.innerHTML = "";
  7712. if (friends_body.classList.contains("allusers_scroll")) friends_body.classList.remove("allusers_scroll");
  7713.  
  7714. const requests = await fetch(this.appRoutes.myRequests, {
  7715. credentials: "include",
  7716. }).then((res) => res.json());
  7717.  
  7718. if (!requests.body) return;
  7719. if (requests.body.length > 0) {
  7720. const reqHtml = requests.body.map(user => `
  7721. <div class="friends_row">
  7722. <div class="centerY g-5">
  7723. <div class="profile-img">
  7724. <img src="${user.imageURL}" alt="${user.username}">
  7725. <span class="status_icon ${user.online ? 'online_icon' : 'offline_icon'}"></span>
  7726. </div>
  7727. <div class="f-big">${user.username}</div>
  7728. </div>
  7729. <div class="centerY g-10">
  7730. <div class="${user.role}_role">${user.role}</div>
  7731. <div class="vr2"></div>
  7732. <button class="modButton centerXY accept" data-user-id="${user.id}" style="padding: 6px 7px;">
  7733. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="16"><path fill="#ffffff" d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/></svg>
  7734. </button>
  7735. <button class="modButton centerXY decline" data-user-id="${user.id}" style="padding: 5px 8px;">
  7736. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" width="16"><path fill="#ffffff" d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/></svg>
  7737. </button>
  7738. </div>
  7739. </div>
  7740. `).join('');
  7741.  
  7742. friends_body.innerHTML = reqHtml;
  7743.  
  7744. friends_body.querySelectorAll('.accept').forEach(accept => {
  7745. accept.addEventListener("click", async () => {
  7746. const userId = accept.getAttribute('data-user-id');
  7747. const req = await fetch(this.appRoutes.handleRequest, {
  7748. method: "POST",
  7749. headers: {
  7750. "Content-Type": "application/json",
  7751. },
  7752. body: JSON.stringify({ type: "accept-request", userId }),
  7753. credentials: "include",
  7754. }).then((res) => res.json());
  7755. that.openRequests();
  7756. });
  7757. });
  7758.  
  7759. friends_body.querySelectorAll('.decline').forEach(decline => {
  7760. decline.addEventListener("click", async () => {
  7761. const userId = decline.getAttribute('data-user-id');
  7762. const req = await fetch(this.appRoutes.handleRequest, {
  7763. method: "POST",
  7764. headers: {
  7765. "Content-Type": "application/json",
  7766. },
  7767. body: JSON.stringify({ type: "decline-request", userId }),
  7768. credentials: "include",
  7769. }).then((res) => res.json());
  7770. that.openRequests();
  7771. });
  7772. });
  7773. } else {
  7774. friends_body.innerHTML = `<span>No requests!</span>`;
  7775. }
  7776.  
  7777. // Remove the scroll event listener
  7778. friends_body.removeEventListener("scroll", this.scrollHandler);
  7779. this.scrollHandler = null;
  7780. },
  7781.  
  7782. async openFriendSettings() {
  7783. const friends_body = document.querySelector(".friends_body");
  7784. if (friends_body.classList.contains("allusers_scroll")) friends_body.classList.remove("allusers_scroll");
  7785. friends_body.innerHTML = "";
  7786.  
  7787. if (Object.keys(this.friends_settings).length === 0) {
  7788. const response = await fetch(this.appRoutes.settings, { credentials: 'include' });
  7789. const responseData = await response.json();
  7790. this.friends_settings = responseData.settings;
  7791. }
  7792.  
  7793. friends_body.innerHTML = `
  7794. <div class="friends_row">
  7795. <div class="centerY g-5">
  7796. <div class="profile-img">
  7797. <img src="${this.profile.imageURL}" alt="Profile picture" />
  7798. </div>
  7799. <span class="f-big" id="profile_username_00">${this.profile.username}</span>
  7800. </div>
  7801. <button class="modButton-black val" id="editProfile">Edit Profile</button>
  7802. </div>
  7803. <div class="friends_row">
  7804. <span>Your user id</span>
  7805. <span class="val">${this.friends_settings.target}</span>
  7806. </div>
  7807. <div class="friends_row">
  7808. <span>Status</span>
  7809. <select class="form-control val" id="edit_static_status">
  7810. <option value="online" ${this.friends_settings.static_status === 'online' ? 'selected' : ''}>Online</option>
  7811. <option value="offline" ${this.friends_settings.static_status === 'offline' ? 'selected' : ''}>Offline</option>
  7812. </select>
  7813. </div>
  7814. <div class="friends_row">
  7815. <span>Accept friend requests</span>
  7816. <div class="modCheckbox val">
  7817. <input type="checkbox" ${this.friends_settings.accept_requests ? 'checked' : ''} id="edit_accept_requests" />
  7818. <label class="cbx" for="edit_accept_requests"></label>
  7819. </div>
  7820. </div>
  7821. <div class="friends_row">
  7822. <span>Highlight friends</span>
  7823. <div class="modCheckbox val">
  7824. <input type="checkbox" ${this.friends_settings.highlight_friends ? 'checked' : ''} id="edit_highlight_friends" />
  7825. <label class="cbx" for="edit_highlight_friends"></label>
  7826. </div>
  7827. </div>
  7828. <div class="friends_row">
  7829. <span>Highlight color</span>
  7830. <input type="color" class="colorInput" value="${this.friends_settings.highlight_color}" style="margin-right: 12px;" id="edit_highlight_color" />
  7831. </div>
  7832. <div class="friends_row">
  7833. <span>Public profile</span>
  7834. <div class="modCheckbox val">
  7835. <input type="checkbox" ${this.friends_settings.visible ? 'checked' : ''} id="edit_visible" />
  7836. <label class="cbx" for="edit_visible"></label>
  7837. </div>
  7838. </div>
  7839. <div class="friends_row">
  7840. <span>Logout</span>
  7841. <button class="modButton-black" id="logout_mod" style="width: 150px">Logout</button>
  7842. </div>
  7843. `;
  7844.  
  7845. const editProfile = document.getElementById("editProfile");
  7846. editProfile.addEventListener("click", () => {
  7847. this.openProfileEditor();
  7848. });
  7849.  
  7850. const logout = document.getElementById("logout_mod");
  7851. logout.addEventListener("click", async () => {
  7852. if (confirm("Are you sure you want to logout?")) {
  7853. const res = await fetch(this.appRoutes.logout).then((res) => res.json());
  7854. location.reload();
  7855. }
  7856. });
  7857.  
  7858. const edit_static_status = document.getElementById("edit_static_status");
  7859. const edit_accept_requests = document.getElementById("edit_accept_requests");
  7860. const edit_highlight_friends = document.getElementById("edit_highlight_friends");
  7861. const edit_highlight_color = document.getElementById("edit_highlight_color");
  7862. const edit_visible = document.getElementById("edit_visible");
  7863.  
  7864. // Debounce function
  7865. function debounce(func, delay) {
  7866. let timeoutId;
  7867. return function (...args) {
  7868. clearTimeout(timeoutId);
  7869. timeoutId = setTimeout(() => {
  7870. func.apply(this, args);
  7871. }, delay);
  7872. };
  7873. }
  7874.  
  7875. edit_static_status.addEventListener("change", () => {
  7876. const val = edit_static_status.value;
  7877. updateSettings("static_status", val);
  7878. });
  7879.  
  7880. edit_accept_requests.addEventListener("change", () => {
  7881. const val = edit_accept_requests.checked;
  7882. updateSettings("accept_requests", val);
  7883. });
  7884.  
  7885. edit_highlight_friends.addEventListener("change", () => {
  7886. const val = edit_highlight_friends.checked;
  7887. updateSettings("highlight_friends", val);
  7888. });
  7889.  
  7890. // Debounce the updateSettings function
  7891. edit_highlight_color.addEventListener("input", debounce(() => {
  7892. const val = edit_highlight_color.value;
  7893. updateSettings("highlight_color", val);
  7894. }, 500));
  7895.  
  7896. edit_visible.addEventListener("change", () => {
  7897. const val = edit_visible.checked;
  7898. updateSettings("visible", val);
  7899. });
  7900.  
  7901. const updateSettings = async (type, data) => {
  7902. const resData = await (await fetch(this.appRoutes.updateSettings, {
  7903. method: 'POST',
  7904. body: JSON.stringify({ type, data }),
  7905. credentials: 'include',
  7906. headers: {
  7907. 'Content-Type': 'application/json'
  7908. }
  7909. })).json();
  7910.  
  7911. if (resData.success) {
  7912. this.friends_settings[type] = data;
  7913. }
  7914. }
  7915.  
  7916. // Remove the scroll event listener
  7917. friends_body.removeEventListener("scroll", this.scrollHandler);
  7918. this.scrollHandler = null;
  7919. },
  7920.  
  7921. openProfileEditor() {
  7922. let that = this;
  7923.  
  7924. const overlay = document.createElement("div");
  7925. overlay.classList.add("mod_overlay");
  7926. overlay.style.opacity = "0";
  7927. overlay.innerHTML = `
  7928. <div class="signIn-wrapper">
  7929. <div class="signIn-header">
  7930. <span>Edit mod profile</span>
  7931. <div class="centerXY" style="width: 32px; height: 32px;">
  7932. <button class="modButton-black" id="closeProfileEditor">
  7933. <svg width="18" height="20" viewBox="0 0 16 16" fill="#ffffff" xmlns="http://www.w3.org/2000/svg">
  7934. <path d="M1.6001 14.4L14.4001 1.59998M14.4001 14.4L1.6001 1.59998" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
  7935. </svg>
  7936. </button>
  7937. </div>
  7938. </div>
  7939. <div class="signIn-body" style="width: fit-content;">
  7940. <div class="centerXY g-10">
  7941. <div class="profile-img" style="width: 6em;height: 6em;">
  7942. <img src="${this.profile.imageURL}" alt="Profile picture" />
  7943. </div>
  7944. <div class="f-column g-5">
  7945. <input type="file" id="imageUpload" accept="image/*" style="display: none;">
  7946. <label for="imageUpload" class="modButton-black g-10">
  7947. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="16"><path fill="#ffffff" d="M149.1 64.8L138.7 96H64C28.7 96 0 124.7 0 160V416c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H373.3L362.9 64.8C356.4 45.2 338.1 32 317.4 32H194.6c-20.7 0-39 13.2-45.5 32.8zM256 192a96 96 0 1 1 0 192 96 96 0 1 1 0-192z"/></svg>
  7948. Upload avatar
  7949. </label>
  7950. <button class="modButton-black g-10" id="deleteAvatar">
  7951. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="16"><path fill="#ffffff" d="M135.2 17.7C140.6 6.8 151.7 0 163.8 0H284.2c12.1 0 23.2 6.8 28.6 17.7L320 32h96c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 96 0 81.7 0 64S14.3 32 32 32h96l7.2-14.3zM32 128H416V448c0 35.3-28.7 64-64 64H96c-35.3 0-64-28.7-64-64V128zm96 64c-8.8 0-16 7.2-16 16V432c0 8.8 7.2 16 16 16s16-7.2 16-16V208c0-8.8-7.2-16-16-16zm96 0c-8.8 0-16 7.2-16 16V432c0 8.8 7.2 16 16 16s16-7.2 16-16V208c0-8.8-7.2-16-16-16zm96 0c-8.8 0-16 7.2-16 16V432c0 8.8 7.2 16 16 16s16-7.2 16-16V208c0-8.8-7.2-16-16-16z"/></svg>
  7952. Delete avatar
  7953. </button>
  7954. </div>
  7955. </div>
  7956. <div class="f-column w-100">
  7957. <label for="username_edit">Username</label>
  7958. <input type="text" class="form-control" id="username_edit" value="${this.profile.username}" />
  7959. </div>
  7960. <div class="f-column w-100">
  7961. <label for="bio_edit">Bio</label>
  7962. <div class="textarea-container">
  7963. <textarea class="form-control" maxlength="250" id="bio_edit">${this.profile.bio || ""}</textarea>
  7964. <span class="char-counter" id="charCount">${this.profile.bio ? this.profile.bio.length : "0"}/250</span>
  7965. </div>
  7966. </div>
  7967. <button class="modButton-black" style="margin-bottom: 20px;" id="saveChanges">Save changes</button>
  7968. </div>
  7969. </div>
  7970. `;
  7971. document.body.append(overlay);
  7972.  
  7973. function hide() {
  7974. overlay.style.opacity = "0";
  7975. setTimeout(() => {
  7976. overlay.remove();
  7977. }, 300);
  7978. }
  7979.  
  7980. overlay.addEventListener("click", (e) => {
  7981. if (e.target == overlay) hide();
  7982. });
  7983.  
  7984. setTimeout(() => {
  7985. overlay.style.opacity = "1";
  7986. });
  7987.  
  7988. document.getElementById("closeProfileEditor").addEventListener("click", hide);
  7989.  
  7990. let changes = new Set(); // Use a Set to store unique changes
  7991.  
  7992. const bio_edit = document.getElementById("bio_edit");
  7993. const charCountSpan = document.getElementById("charCount");
  7994. bio_edit.addEventListener("input", updCharcounter);
  7995.  
  7996. function updCharcounter() {
  7997. const currentTextLength = bio_edit.value.length;
  7998. charCountSpan.textContent = currentTextLength + "/250";
  7999.  
  8000. // Update changes
  8001. changes.add("bio");
  8002. }
  8003.  
  8004. // Upload avatar
  8005. document.getElementById("imageUpload").addEventListener("input", async (e) => {
  8006. const file = e.target.files[0];
  8007. if (!file) return;
  8008. console.log(file);
  8009.  
  8010. const formData = new FormData();
  8011. formData.append('image', file);
  8012.  
  8013. try {
  8014. const data = await (await fetch(this.appRoutes.imgUpload, {
  8015. method: 'POST',
  8016. credentials: 'include',
  8017. body: formData,
  8018. })).json();
  8019. console.log(data);
  8020.  
  8021. if (data.success) {
  8022. const profileImg = document.querySelector(".profile-img img");
  8023. profileImg.src = data.user.imageURL;
  8024. hide();
  8025. that.profile = data.user;
  8026. } else {
  8027. that.modAlert(data.message, "danger");
  8028. console.error('Failed to upload image');
  8029. }
  8030. } catch (error) {
  8031. console.error('Error uploading image:', error);
  8032. }
  8033. });
  8034.  
  8035. const username_edit = document.getElementById("username_edit");
  8036. username_edit.addEventListener("input", () => {
  8037. changes.add("username");
  8038. });
  8039.  
  8040. const saveChanges = document.getElementById("saveChanges");
  8041. saveChanges.addEventListener("click", async () => {
  8042. if (changes.size === 0) return;
  8043. let changedData = {};
  8044. changes.forEach((change) => {
  8045. if (change === "username") {
  8046. changedData.username = username_edit.value;
  8047. } else if (change === "bio") {
  8048. changedData.bio = bio_edit.value;
  8049. }
  8050. });
  8051.  
  8052. const resData = await (await fetch(this.appRoutes.editProfile, {
  8053. method: 'POST',
  8054. body: JSON.stringify({
  8055. changes: Array.from(changes),
  8056. data: changedData,
  8057. }),
  8058. credentials: 'include',
  8059. headers: {
  8060. 'Content-Type': 'application/json'
  8061. }
  8062. })).json();
  8063.  
  8064. if (resData.success) {
  8065. if (that.profile.username !== resData.user.username) {
  8066. const p_username = document.getElementById("profile_username_00");
  8067. if (p_username) p_username.innerText = resData.user.username;
  8068. }
  8069. that.profile = resData.user;
  8070. changes.clear();
  8071. hide();
  8072. const name = document.getElementById("my-profile-name");
  8073. const bioText = document.getElementById("my-profile-bio");
  8074.  
  8075. name.innerText = resData.user.username;
  8076. bioText.innerHTML = resData.user.bio;
  8077.  
  8078. } else {
  8079. resData.errors.forEach((error) => {
  8080. this.modAlert(error.message, "danger");
  8081. });
  8082. }
  8083. });
  8084.  
  8085. const deleteAvatar = document.getElementById("deleteAvatar");
  8086. deleteAvatar.addEventListener("click", async () => {
  8087. if (confirm("Are you sure you want to remove your profile picture? It will be changed to the default profile picture.")) {
  8088. try {
  8089. const data = await (await fetch(this.appRoutes.delProfile, {
  8090. credentials: 'include',
  8091. })).json();
  8092. const profileImg = document.querySelector(".profile-img img");
  8093. profileImg.src = data.user.imageURL;
  8094. hide();
  8095. that.profile = data.user;
  8096. } catch(error) {
  8097. console.error('CouldN\'t remove image: ', error);
  8098. this.modAlert(error.message, "danger");
  8099. }
  8100. }
  8101. });
  8102. },
  8103.  
  8104. load() {
  8105. // Load game faster
  8106. function randomPos() {
  8107. let eventOptions = {
  8108. clientX: Math.floor(Math.random() * window.innerWidth),
  8109. clientY: Math.floor(Math.random() * window.innerHeight),
  8110. bubbles: true,
  8111. cancelable: true
  8112. };
  8113.  
  8114. let event = new MouseEvent('mousemove', eventOptions);
  8115.  
  8116. document.dispatchEvent(event);
  8117. }
  8118. setInterval(randomPos);
  8119. setTimeout(() => clearInterval(), 500);
  8120.  
  8121. this.gameSocket();
  8122. // load mod when websocket is ready
  8123. let loaded = false;
  8124. let intervalId = setInterval(() => {
  8125. if (!unsafeWindow.WebSocket) return;
  8126.  
  8127. // load mod
  8128. this.createMenu();
  8129. loaded = true;
  8130. clearInterval(intervalId);
  8131. }, 400);
  8132. },
  8133.  
  8134. createMenu() {
  8135. this.smallMods();
  8136. this.menu();
  8137. this.credits();
  8138. this.chat();
  8139. this.Macros();
  8140. this.Themes();
  8141. this.updateNick();
  8142. this.clientPing();
  8143. this.tagsystem();
  8144. this.createMinimap();
  8145. this.saveNames();
  8146. this.setInputActions();
  8147. this.game();
  8148. this.mainMenu();
  8149. this.macroSettings();
  8150. this.fps();
  8151. this.initStats();
  8152. this.account();
  8153.  
  8154. const styleTag = document.createElement("style")
  8155. styleTag.innerHTML = this.style;
  8156. document.head.append(styleTag);
  8157.  
  8158. // Respawn interval
  8159. setInterval(() => {
  8160. if (modSettings.AutoRespawn && this.respawnTime && Date.now() - this.respawnTime >= this.respawnCooldown) {
  8161. this.respawn();
  8162. }
  8163. })
  8164.  
  8165. // mouse fast feed interval
  8166. setInterval(() => {
  8167. if (!activeCellX || !this.mouseDown) return
  8168.  
  8169. this.fastMass()
  8170. }, 50);
  8171. }
  8172. }
  8173.  
  8174. const mods = new mod();
  8175. })();
  8176.  
  8177. /* ** ** ** ** ** ** *\
  8178. | SigMod by Cursed |
  8179. \* .. .. .. .. .. .. */