// ==UserScript==
// @name SigMod Client (Macros)
// @version 9.2.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!
// @author Cursed
// @match *://sigmally.com/*
// @match *://beta.sigmally.com/*
// @exclude https://sigmally.com/moderate/
// @icon https://raw.githubusercontent.com/Sigmally/SigMod/main/images/sigmodclient2.gif
// @run-at document-end
// @license MIT
// @namespace https://greasyfork.org/users/981958
// @downloadURL none
// ==/UserScript==
(function() {
let version = 9;
let cversion = 1.4;
let storageName = "SigModClient-settings";
let headerAnim = "https://app.czrsd.com/static/sigmodclient.gif";
'use strict';
let modSettings = localStorage.getItem(storageName);
if (!modSettings) {
modSettings = {
keyBindings: {
rapidFeed: "w",
doubleSplit: "d",
tripleSplit: "f",
quadSplit: "g",
freezePlayer: "s",
verticalSplit: "t",
doubleTrick: "",
selfTrick: "",
toggleMenu: "v",
location: "y",
toggleChat: "z",
toggleNames: "",
toggleSkins: "",
toggleAutoRespawn: "",
respawn: "b"
},
freezeType: "press",
m1: null,
m2: null,
mapColor: null,
nameColor: null,
gradientName: {
enabled: false,
color1: null,
color2: null,
},
borderColor: null,
foodColor: null,
cellColor: null,
mapImageURL: "",
virusImage: "/assets/images/viruses/2.png",
skinImage: {
original: null,
replaceImg: null,
},
Theme: "Dark",
addedThemes: [],
savedNames: [],
AutoRespawn: false,
tag: null,
chatSettings: {
limit: 100,
bgColor: "#000000",
chat_opacity: 0.4,
compact: false,
themeColor: "#8a25e5",
showTime: true,
showNameColors: true,
showClientChat: false,
showChatButtons: true,
blurTag: false,
locationText: "{pos}",
},
deathScreenPos: "center",
fps: {
fpsMode: false,
hideFood: false,
showNames: true,
shortLongNames: false,
removeOutlines: false,
},
removeShopPopup: false,
playTimer: false,
autoClaimCoins: false,
showChallenges: false,
authorized: false,
};
updateStorage();
} else {
modSettings = JSON.parse(modSettings);
}
function updateStorage() {
localStorage.setItem(storageName, JSON.stringify(modSettings));
}
// for development
let isDev = false;
let port = 3001;
// global sigmod
unsafeWindow.sigmod = {
version,
server_version: cversion,
storageName,
settings: modSettings,
};
// websocket, user
unsafeWindow.gameSettings = {};
// * helper functions * //
function debounce(func, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
function noXSS(text) {
return text.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
function parsetxt(val) {
return /^(?:\{([^}]*)\})?([^]*)/.exec(val)[2].trim();
}
async function wait(ms) {
return new Promise(r => setTimeout(r, ms));
}
function v2Token() {
const tokenField = document.querySelector('.g-recaptcha-response');
if (tokenField && tokenField.value !== '') {
unsafeWindow.v2 = tokenField.value;
} else {
setTimeout(v2Token, 1000);
}
}
v2Token();
let fetchedUser = 0;
const originalFetch = unsafeWindow.fetch;
unsafeWindow.fetch = function(url, options) {
if (url.includes('/server/auth')) {
return originalFetch(url, options)
.then(response => response.json().then(data => {
fetchedUser++;
if (fetchedUser > 1 && data.body.user) {
if (client.ws) {
client.send({
type: "user",
content: data.body.user,
});
}
fetch(mods.appRoutes.user, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
authorized: true,
user: data.body.user,
nick: mods.nick,
}),
});
const claim = document.getElementById("free-chest-button");
if (modSettings.autoClaimCoins && claim && claim.style.display !== "none") {
setTimeout(() => claim.click(), 500);
}
}
return new Response(JSON.stringify(data), response);
}));
} else if (url.includes('v3')) {
const token = JSON.parse(options.body).recaptchaV3Token;
unsafeWindow.v3 = token;
}
return originalFetch(url, options);
};
// hex color code to rgba values
function hexToRgba(hex, alpha) {
const r = parseInt(hex.substring(1, 3), 16);
const g = parseInt(hex.substring(3, 5), 16);
const b = parseInt(hex.substring(5, 7), 16);
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
}
// rgba values to hex color code
function RgbaToHex(code) {
const rgbaValues = code.match(/\d+/g);
const [r, g, b] = rgbaValues.slice(0, 3);
return `#${Number(r).toString(16).padStart(2, '0')}${Number(g).toString(16).padStart(2, '0')}${Number(b).toString(16).padStart(2, '0')}`;
}
// generate random string
function rdmString(length) {
return [...Array(length)].map(() => Math.random().toString(36).charAt(2)).join('');
}
function menuClosed() {
const menuWrapper = document.getElementById("menu-wrapper");
return menuWrapper.style.display === "none";
}
function isDeath() {
const __line2 = document.getElementById("__line2");
return !__line2.classList.contains("line--hidden");
}
function getGameMode() {
const gameMode = document.getElementById("gamemode");
if (!gameMode.value) {
return "Tourney";
}
const options = Object.values(gameMode.querySelectorAll("option"));
const selectedOption = options.filter((option) => option.value === gameMode.value)[0];
const serverName = selectedOption.textContent.split(" ")[0];
return serverName;
}
function bytesToHex(r, g, b) {
return '#' + ((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1);
}
// Function to convert a datetime stamp to a readable time
function formatTime(timestamp) {
if (!timestamp) return "";
const numericTimestamp = Number(timestamp); // convert to int
const date = new Date(numericTimestamp);
const hours = date.getHours();
const minutes = String(date.getMinutes()).padStart(2, '0');
const ampm = hours >= 12 ? 'PM' : 'AM';
const formattedHours = (hours % 12 || 12).toString().padStart(2, '0');
return `${formattedHours}:${minutes} ${ampm}`;
}
// Function to get the time difference from the current time
function getTimeAgo(timestamp) {
if (!timestamp) return "";
const currentTime = new Date();
const elapsedTime = currentTime - timestamp;
const seconds = Math.floor(elapsedTime / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
const years = Math.floor(days / 365);
if (years > 0) {
return years === 1 ? "1 year ago" : `${years} years ago`;
} else if (days > 0) {
return days === 1 ? "1 day ago" : `${days} days ago`;
} else if (hours > 0) {
return hours === 1 ? "1 hour ago" : `${hours} hours ago`;
} else if (minutes > 0) {
return minutes === 1 ? "1 minute ago" : `${minutes} minutes ago`;
} else {
return seconds <= 1 ? "1s>" : `${seconds}s ago`;
}
}
function keypress(key, keycode) {
const keyDownEvent = new KeyboardEvent("keydown", { key: key, code: keycode });
const keyUpEvent = new KeyboardEvent("keyup", { key: key, code: keycode });
window.dispatchEvent(keyDownEvent);
window.dispatchEvent(keyUpEvent);
}
function mousemove(sx, sy) {
const mouseMoveEvent = new MouseEvent("mousemove", { clientX: sx, clientY: sy });
const canvas = document.getElementById("canvas");
canvas.dispatchEvent(mouseMoveEvent);
}
// EU server
const coordinates = {};
const gridSize = 4500;
for (let i = 0; i < 5; i++) {
for (let j = 0; j < 5; j++) {
const label = String.fromCharCode(65 + i) + (j + 1);
const minX = -11000 + (i * gridSize);
const minY = -11000 + (j * gridSize);
const maxX = -6500 + (i * gridSize);
const maxY = -6500 + (j * gridSize);
coordinates[label] = {
min: {
x: minX,
y: minY
},
max: {
x: maxX,
y: maxY
}
};
}
}
// US1; US2; US3 servers
const coordinates2 = {};
const gridSize2 = 7000;
for (let i = 0; i < 5; i++) {
for (let j = 0; j < 5; j++) {
const label = String.fromCharCode(65 + i) + (j + 1);
const minX = -17022 + (i * gridSize2);
const minY = -17022 + (j * gridSize2);
const maxX = -10000 + (i * gridSize2);
const maxY = -10000 + (j * gridSize2);
coordinates2[label] = {
min: {
x: minX,
y: minY
},
max: {
x: maxX,
y: maxY
}
};
}
}
let client = null;
let handshake = false;
const originalSend = WebSocket.prototype.send
const C = new Uint8Array(256)
const R = new Uint8Array(256)
WebSocket.prototype.send = function(data) {
// make sure its only for sigmally.com websockets
if (!this.url.includes("sigmally.com")) {
return originalSend.apply(this, arguments);
}
if (!client) {
client = new modClient();
}
if (!unsafeWindow.gameSettings.ws) {
unsafeWindow.gameSettings.ws = this;
unsafeWindow.gameSettings.ws.addEventListener("close", () => {
unsafeWindow.gameSettings.ws = null;
handshake = false;
activeCellX = null;
activeCellY = null;
const chat = document.getElementById("mod-messages");
chat.innerHTML = "";
setTimeout(() => {
document.getElementById('overlays').show(0.5);
document.getElementById('menu-wrapper').show();
document.getElementById('left-menu').show();
document.getElementById('menu-links').show();
document.getElementById('right-menu').show();
document.getElementById('left_ad_block').show();
document.getElementById('ad_bottom').show();
}, 500);
})
unsafeWindow.gameSettings.ws.sendPacket = function(packet) {
if (packet.build) {
return unsafeWindow.gameSettings.ws.send(packet.build())
}
unsafeWindow.gameSettings.ws.send(packet)
}
unsafeWindow.sendChat = function sendChat(text) {
const writer = new Writer();
writer.setUint8(C[0x63]);
writer.setUint8(0);
writer.setStringUTF8(text);
unsafeWindow.gameSettings.ws.sendPacket(writer);
};
unsafeWindow.gameSettings.ws.addEventListener("message", (event) => {
const reader = new Reader(new DataView(event.data), 0, true)
if (!handshake) {
const ver = reader.getStringUTF8(false)
C.set(new Uint8Array(reader.raw(256)))
for (const i in C) R[C[i]] = ~~i
handshake = true
return
}
const r = reader.getUint8()
switch (R[r]) {
case 0x63: {
// chat message
const flags = reader.getUint8();
const color = bytesToHex(
reader.getUint8(),
reader.getUint8(),
reader.getUint8()
);
let name = reader.getStringUTF8();
const message = reader.getStringUTF8();
const server = !!(flags & 0x80);
const admin = !!(flags & 0x40);
const mod = !!(flags & 0x20);
if (server && name !== 'SERVER') name = '[SERVER]';
if (admin) name = '[ADMIN] ' + name;
if (mod) name = '[MOD] ' + name;
if (name === "") name = "Unnamed";
name = parsetxt(name);
if (mods.mutedUsers.includes(name)) {
return;
}
if (!modSettings.chatSettings.showClientChat) {
mods.updateChat({
server,
admin,
mod,
color: modSettings.chatSettings.showNameColors ? color : "#fafafa",
name,
message,
time: modSettings.chatSettings.showTime ? Date.now() : null,
});
}
break
}
case 0x40: {
// set border
mods.border.left = reader.getFloat64();
mods.border.top = reader.getFloat64();
mods.border.right = reader.getFloat64();
mods.border.bottom = reader.getFloat64();
mods.border.width = mods.border.right - mods.border.left;
mods.border.height = mods.border.bottom - mods.border.top;
mods.border.centerX = (mods.border.left + mods.border.right) / 2;
mods.border.centerY = (mods.border.top + mods.border.bottom) / 2;
} break
}
})
}
return originalSend.apply(this, arguments)
}
class modClient {
constructor() {
this.ws = null;
this.wsUrl = isDev ? `ws://localhost:${port}/ws` : "wss://app.czrsd.com/sigmodz/ws";
this.readyState = null;
this.id = Math.abs(~~(Math.random() * 9e10));
this.connect();
}
connect() {
this.ws = new WebSocket(this.wsUrl);
this.ws.binaryType = "arraybuffer";
this.ws.addEventListener("open", this.onOpen.bind(this));
this.ws.addEventListener("close", this.onClose.bind(this));
this.ws.addEventListener("message", this.onMessage.bind(this));
this.ws.addEventListener("error", this.onError.bind(this));
}
close() {
if (this.ws) {
this.ws.close();
this.readyState = 3;
}
}
async onOpen(event) {
console.log("WebSocket connection opened.");
this.readyState = 1;
await wait(500); // wait to load DOM
const tagElement = document.querySelector("#tag");
const tagText = document.querySelector(".tagText");
this.send({
type: "server-changed",
content: getGameMode()
});
this.send({
type: "version",
content: cversion,
});
this.send({
type: "update-nick",
content: mods.nick,
});
function getTagFromUrl() {
const urlParams = new URLSearchParams(unsafeWindow.location.search);
const tagValue = urlParams.get('tag');
return tagValue ? tagValue.replace(/\/$/, '') : null;
}
const tagValue = getTagFromUrl();
if (tagValue !== null) {
modSettings.tag = tagValue;
updateStorage();
tagElement.value = tagValue;
tagText.innerText = `Tag: ${tagValue}`;
this.send({
type: "update-tag",
content: modSettings.tag,
});
}
if (modSettings.tag && tagValue == null) {
tagElement.value = modSettings.tag;
tagText.innerText = `Tag: ${modSettings.tag}`;
this.send({
type: "update-tag",
content: modSettings.tag,
});
}
const errorMessage = document.querySelector(".error-message_sigMod")
if (errorMessage) {
errorMessage.style.right = "-500px";
setTimeout(() => {
errorMessage.remove();
}, 500)
}
}
onClose(event) {
this.readyState = 3;
const message = document.createElement("div");
message.classList.add("error-message_sigMod")
message.innerHTML = `
You Disconnected from the SigMod WebSocket. Error code: ${event.code}. Please refresh the page.
`;
setTimeout(() => {
message.style.right = "20px";
}, 200)
document.querySelector(".body__inner").append(message)
const close = document.getElementById("close-error-message_sigMod");
const refresh = document.getElementById("refresh-error-message_sigMod");
close.addEventListener("click", () => {
message.style.right = "-500px";
setTimeout(() => {
message.remove();
}, 500)
});
refresh.addEventListener("click", () => {
this.connect();
message.style.right = "-500px";
setTimeout(() => {
message.remove();
}, 500)
});
}
onMessage(event) {
const data = new Uint8Array(event.data);
const string = new TextDecoder().decode(data);
const message = JSON.parse(string);
switch (message.type) {
case "ping":
{
const latency = Date.now() - mods.ping.start;
mods.ping.end = Date.now();
mods.ping.latency = latency;
document.getElementById("clientPing").innerHTML = `Client Ping: ${latency}ms`;
}
break;
case "minimap-data":
mods.updData(message.content);
break;
case "chat-message":
{
const content = message.content;
if (content) {
let { admin, mod, vip, name, message: msg, color } = content;
if (admin) name = "[Owner] " + name;
if (mod) name = "[Mod] " + name;
if (vip) name = "[VIP] " + name;
if (name === "") name = "Unnamed";
mods.updateChat({
admin,
mod,
color,
name,
message: msg,
time: mods.modSettings.chatSettings.showTime ? Date.now() : null,
});
}
}
break;
case "private-message":
mods.updatePrivateChat(message.content);
break;
case "update-available":
{
const modAlert = document.createElement("div");
modAlert.classList.add("modAlert");
modAlert.innerHTML = `
You are using an old mod version. Please update.
`;
document.body.append(modAlert);
document.getElementById("updateMod").addEventListener("click", () => {
window.open(message.content);
modAlert.remove();
});
}
break;
case "tournament-preview":
mods.showTournament(message.content);
mods.tData = message.content;
break;
case "tournament-go":
mods.startTournament(message.content);
break;
case "get-score":
mods.getScore(message.content);
break;
case "user-died":
{
const { dead, max } = message.content;
document.getElementById("usersDead").textContent = `(${dead}/${max})`;
}
break;
case "round-end":
mods.roundEnd(message.content);
break;
case "round-ready":
{
const text = document.getElementById("round-ready");
text.textContent = `Ready (${message.content.ready}/${message.content.max})`;
}
break;
case "next-round":
mods.nextRound(message.content);
break;
case "tournament-end":
mods.endTournament(message.content);
break;
case "tournament-script":
mods.loadTournamentScript(message.content.u, message.content.a);
break;
case "tournament-action":
mods.emitTournamentAction(message.content.action, message.content.data);
break;
default:
console.error("unknown message type:", message.type);
}
}
onError(event) {
console.error("WebSocket error. More details: ", event);
}
send(data) {
if (!data) return;
const string = JSON.stringify(data);
const encoder = new TextEncoder();
const binaryData = encoder.encode(string);
this.ws.send(binaryData);
}
}
function Reader(view, offset, littleEndian) {
this._e = littleEndian;
if (view) this.repurpose(view, offset);
}
Reader.prototype = {
reader: true,
repurpose: function (view, offset) {
this.view = view;
this._o = offset || 0;
},
getUint8: function () {
return this.view.getUint8(this._o++, this._e);
},
getInt8: function () {
return this.view.getInt8(this._o++, this._e);
},
getUint16: function () {
return this.view.getUint16((this._o += 2) - 2, this._e);
},
getInt16: function () {
return this.view.getInt16((this._o += 2) - 2, this._e);
},
getUint32: function () {
return this.view.getUint32((this._o += 4) - 4, this._e);
},
getInt32: function () {
return this.view.getInt32((this._o += 4) - 4, this._e);
},
getFloat32: function () {
return this.view.getFloat32((this._o += 4) - 4, this._e);
},
getFloat64: function () {
return this.view.getFloat64((this._o += 8) - 8, this._e);
},
getStringUTF8: function (decode = true) {
let bytes = [];
let b;
while ((b = this.view.getUint8(this._o++)) !== 0)
bytes.push(b);
let uint8Array = new Uint8Array(bytes);
let decoder = new TextDecoder('utf-8');
let s = decoder.decode(uint8Array);
return decode ? s : uint8Array;
},
raw: function (len = 0) {
const buf = this.view.buffer.slice(this._o, this._o + len);
this._o += len;
return buf;
},
};
const __buf = new DataView(new ArrayBuffer(8))
function Writer(littleEndian) {
this._e = littleEndian;
this.reset();
return this;
}
Writer.prototype = {
writer: true,
reset: function (littleEndian) {
this._b = [];
this._o = 0;
},
setUint8: function (a) {
if (a >= 0 && a < 256) this._b.push(a);
return this;
},
setInt8: function (a) {
if (a >= -128 && a < 128) this._b.push(a);
return this;
},
setUint16: function (a) {
__buf.setUint16(0, a, this._e);
this._move(2);
return this;
},
setInt16: function (a) {
__buf.setInt16(0, a, this._e);
this._move(2);
return this;
},
setUint32: function (a) {
__buf.setUint32(0, a, this._e);
this._move(4);
return this;
},
setInt32: function (a) {
__buf.setInt32(0, a, this._e);
this._move(4);
return this;
},
setFloat32: function (a) {
__buf.setFloat32(0, a, this._e);
this._move(4);
return this;
},
setFloat64: function (a) {
__buf.setFloat64(0, a, this._e);
this._move(8);
return this;
},
_move: function (b) {
for (let i = 0; i < b; i++) this._b.push(__buf.getUint8(i));
},
setStringUTF8: function (s) {
const bytesStr = unescape(encodeURIComponent(s));
for (let i = 0, l = bytesStr.length; i < l; i++)
this._b.push(bytesStr.charCodeAt(i));
this._b.push(0);
return this;
},
build: function () {
return new Uint8Array(this._b);
},
};
setTimeout(() => {
const gameSettings = document.querySelector(".checkbox-grid");
gameSettings.innerHTML += `
`;
let autoRespawn = document.getElementById("autoRespawn");
let autoRespawnEnabled = false;
autoRespawn.addEventListener("change", () => {
if(!autoRespawnEnabled) {
modSettings.AutoRespawn = true;
updateStorage();
autoRespawnEnabled = true;
} else {
modSettings.AutoRespawn = false;
updateStorage();
autoRespawnEnabled = false;
}
});
if(modSettings.AutoRespawn) {
autoRespawn.checked = true;
autoRespawnEnabled = true;
}
});
const getEmojis = async () => {
const response = await fetch("https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json");
const emojis = await response.json();
// Add more emojis if u want:
emojis.push(
{
"emoji": "โค",
"description": "Default heart",
"category": "Smileys & Emotion",
"tags": ["heart", "love"],
},
{
"emoji": "๐งก",
"description": "Orange heart",
"category": "Smileys & Emotion",
"tags": ["heart", "love"],
},
{
"emoji": "๐",
"description": "Yellow heart",
"category": "Smileys & Emotion",
"tags": ["heart", "love"],
},
{
"emoji": "๐",
"description": "Green heart",
"category": "Smileys & Emotion",
"tags": ["heart", "love"],
},
{
"emoji": "๐",
"description": "Blue heart",
"category": "Smileys & Emotion",
"tags": ["heart", "love"],
},
{
"emoji": "๐",
"description": "Purple heart",
"category": "Smileys & Emotion",
"tags": ["heart", "love"],
},
{
"emoji": "๐ค",
"description": "Brown heart",
"category": "Smileys & Emotion",
"tags": ["heart", "love"],
},
{
"emoji": "๐ค",
"description": "Black heart",
"category": "Smileys & Emotion",
"tags": ["heart", "love"],
},
);
return emojis;
};
let activeCellY = null;
let activeCellX = null;
let _getScore = false;
let lastScore = 0;
let lastPos = {};
let lastLogTime = 0;
let dead = false;
let dead2 = false;
let replacementVirus = null;
let replacementSkin = null;
function mod() {
this.Username = "Guest";
this.nick = null;
this.profile = {};
this.friends_settings = {};
this.friend_names = new Set();
this.splitKey = {
keyCode: 32,
code: "Space",
cancelable: true,
composed: true,
isTrusted: true,
which: 32,
}
this.ping = {
latency: NaN,
intervalId: null,
start: null,
end: null,
}
this.dayTimer = null;
this.challenges = [];
this.scrolling = false;
this.onContext = false;
this.mouseDown = false;
this.mouseX = 0;
this.mouseY = 0;
this.screenSide = null;
this.mutedUsers = [];
this.miniMapData = [];
this.tData = {};
this.border = {};
this.routes = {
discord: {
auth: isDev ? `https://discord.com/oauth2/authorize?client_id=1067097357780516874&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3001%2Fsigmod%2Fdiscord%2Fcallback&scope=identify` : "https://discord.com/oauth2/authorize?client_id=1067097357780516874&response_type=code&redirect_uri=https%3A%2F%2Fapp.czrsd.com%2Fsigmod%2Fdiscord%2Fcallback&scope=identify",
}
}
// for SigMod specific
this.appRoutes = {
user: isDev ? `http://localhost:${port}/sigmodz/user` : 'https://app.czrsd.com/sigmodz/user',
badge: isDev ? `http://localhost:${port}/sigmodz/badge` : "https://app.czrsd.com/sigmodz/badge",
discordLogin: isDev ? `http://localhost:${port}/sigmodz/discord/login/` : "https://app.czrsd.com/sigmodz/discord/login/",
auth: isDev ? `http://localhost:${port}/sigmodz/auth` : `https://app.czrsd.com/sigmodz/auth`,
users: isDev ? `http://localhost:${port}/sigmodz/users` : `https://app.czrsd.com/sigmodz/users`,
search: isDev ? `http://localhost:${port}/sigmodz/search` : `https://app.czrsd.com/sigmodz/search`,
request: isDev ? `http://localhost:${port}/sigmodz/request` : `https://app.czrsd.com/sigmodz/request`,
friends: isDev ? `http://localhost:${port}/sigmodz/me/friends` : `https://app.czrsd.com/sigmodz/me/friends`,
profile: (id) => isDev ? `http://localhost:${port}/sigmodz/profile/${id}` : `https://app.czrsd.com/sigmodz/profile/${id}`,
myRequests: isDev ? `http://localhost:${port}/sigmodz/me/requests` : `https://app.czrsd.com/sigmodz/me/requests`,
handleRequest: isDev ? `http://localhost:${port}/sigmodz/me/handle` : `https://app.czrsd.com/sigmodz/me/handle`,
settings: isDev ? `http://localhost:${port}/sigmodz/me/settings` : `https://app.czrsd.com/sigmodz/me/settings`,
logout: isDev ? `http://localhost:${port}/sigmodz/logout` : `https://app.czrsd.com/sigmodz/logout`,
imgUpload: isDev ? `http://localhost:${port}/sigmodz/me/upload` : `https://app.czrsd.com/sigmodz/me/upload`,
removeAvatar: isDev ? `http://localhost:${port}/sigmodz/me/handle` : `https://app.czrsd.com/sigmodz/me/handle`,
editProfile: isDev ? `http://localhost:${port}/sigmodz/me/edit` : `https://app.czrsd.com/sigmodz/me/edit`,
delProfile: isDev ? `http://localhost:${port}/sigmodz/me/remove` : `https://app.czrsd.com/sigmodz/me/remove`,
updateSettings: isDev ? `http://localhost:${port}/sigmodz/me/update-settings` : `https://app.czrsd.com/sigmodz/me/update-settings`,
chatHistory: (id) => isDev ? `http://localhost:${port}/sigmodz/me/chat/${id}` : `https://app.czrsd.com/sigmodz/me/chat/${id}`,
feedback: isDev ? `http://localhost:${port}/sigmodz/feedback` : `https://app.czrsd.com/sigmodz/feedback`
};
this.load();
}
mod.prototype = {
get style() {
return `
:root {
--default-mod-color: #2E2D80;
}
.mod_menu * {
margin: 0;
padding: 0;
font-family: 'Ubuntu';
box-sizing: border-box;
}
.mod_menu {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, .6);
z-index: 999999;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
transition: all .3s ease;
}
.mod_menu_wrapper {
position: relative;
display: flex;
flex-direction: column;
width: 700px;
height: 500px;
background: #111;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 5px 10px #000;
}
.mod_menu_header {
display: flex;
width: 100%;
position: relative;
height: 60px;
}
.mod_menu_header .header_img {
width: 100%;
height: 60px;
object-fit: cover;
object-position: center;
position: absolute;
}
.mod_menu_header button {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
right: 10px;
top: 30px;
background: rgba(11, 11, 11, .7);
width: 42px;
height: 42px;
font-size: 16px;
transform: translateY(-50%);
}
.mod_menu_header button:hover {
background: rgba(11, 11, 11, .5);
}
.mod_menu_inner {
display: flex;
}
.mod_menu_navbar {
display: flex;
flex-direction: column;
gap: 10px;
min-width: 132px;
padding: 10px;
background: #181818;
height: 440px;
}
.mod_nav_btn, .modButton-black {
display: flex;
justify-content: space-evenly;
align-items: center;
padding: 5px;
background: #050505;
border-radius: 8px;
font-size: 16px;
border: 1px solid transparent;
outline: none;
width: 100%;
transition: all .3s ease;
}
label.modButton-black {
font-weight: 400;
cursor: pointer;
}
.mod_nav_btn:nth-child(8) {
margin-top: auto;
}
.mod_selected {
border: 1px solid rgba(89, 89, 89, .9);
}
.mod_nav_btn img {
width: 22px;
}
.mod_menu_content {
width: 100%;
padding: 10px;
position: relative;
}
.mod_tab {
width: 100%;
display: flex;
flex-direction: column;
gap: 5px;
overflow-y: auto;
overflow-x: hidden;
max-height: 420px;
opacity: 1;
transition: all .2s ease;
}
.text-center {
text-align: center;
}
.f-big {
font-size: 18px;
}
.modColItems {
display: flex;
flex-direction: column;
align-items: center;
gap: 15px;
width: 100%;
}
.modRowItems {
display: flex;
justify-content: center;
align-items: center;
background: #050505;
gap: 58px;
border-radius: 0.5rem;
padding: 10px;
width: 100%;
}
.modSlider {
-webkit-appearance: none;
height: 22px;
background: transparent;
cursor: pointer;
width: 100%;
}
.modSlider::-webkit-slider-runnable-track {
-webkit-appearance: none;
background: #542499;
height: 4px;
border-radius: 6px;
}
.modSlider::-webkit-slider-thumb {
appearance: none;
background: #6B32BD;
height: 16px;
width: 16px;
position: relative;
top: -5px;
border-radius: 50%;
}
input:focus, select:focus, button:focus{
outline: none;
}
.flex {
display: flex;
}
.centerX {
display: flex;
justify-content: center;
}
.centerY {
display: flex;
align-items: center;
}
.centerXY {
display: flex;
align-items: center;
justify-content: center
}
.f-column {
display: flex;
flex-direction: column;
}
.macros_wrapper {
display: flex;
width: 100%;
justify-content: center;
flex-direction: column;
gap: 10px;
background: #050505;
padding: 10px;
border-radius: 0.75rem;
}
.macro_grid {
display: grid;
grid-template-columns: 1.2fr 1.1fr;
gap: 5px;
}
.g-2 {
gap: 2px;
}
.g-5 {
gap: 5px;
}
.g-10 {
gap: 10px;
}
.p-2 {
padding: 2px;
}
.p-5 {
padding: 5px;
}
.p-10 {
padding: 10px;
}
.macrosContainer {
display: flex;
width: 100%;
justify-content: center;
align-items: center;
gap: 20px;
}
.macroRow {
background: #121212;
border-radius: 5px;
padding: 7px;
display: flex;
justify-content: space-between;
align-items: center;
gap: 10px;
}
.keybinding {
border-radius: 5px;
background: #242424;
border: none;
color: #fff;
padding: 2px 5px;
max-width: 50px;
font-weight: 500;
text-align: center;
}
.hidden {
display: none;
}
.SettingsTitle{
font-size: 32px;
color: #EEE;
margin-left: 10px;
}
.CloseBtn{
width: 46px;
background-color: transparent;
}
.select-btn {
padding: 15px 20px;
background: #222;
border-radius: 2px;
position: relative;
}
.select-btn:active {
scale: 0.95
}
.select-btn::before {
content: "...";
font-size: 20px;
color: #fff;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.text {
user-select: none;
font-weight: 500;
text-align: left;
}
.modButton {
background-color: #252525;
border-radius: 4px;
color: #fff;
transition: all .3s;
outline: none;
padding: 7px;
font-size: 13px;
border: none;
}
.modButton:hover {
background-color: #222
}
.modInput {
background-color: #111;
border: none;
border-radius: 5px;
position: relative;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
font-weight: 500;
padding: 5px;
color: #fff;
}
.modCheckbox input[type="checkbox"] {
display: none;
visibility: hidden;
}
.modCheckbox label {
display: inline-block;
}
.modCheckbox .cbx {
position: relative;
top: 1px;
width: 17px;
height: 17px;
margin: 2px;
border: 1px solid #c8ccd4;
border-radius: 3px;
vertical-align: middle;
transition: background 0.1s ease;
cursor: pointer;
}
.modCheckbox .cbx:after {
content: '';
position: absolute;
top: 1px;
left: 5px;
width: 5px;
height: 11px;
opacity: 0;
transform: rotate(45deg) scale(0);
border-right: 2px solid #fff;
border-bottom: 2px solid #fff;
transition: all 0.3s ease;
transition-delay: 0.15s;
}
.modCheckbox input[type="checkbox"]:checked ~ .cbx {
border-color: transparent;
background: #6871f1;
box-shadow: 0 0 10px #2E2D80;
}
.modCheckbox input[type="checkbox"]:checked ~ .cbx:after {
opacity: 1;
transform: rotate(45deg) scale(1);
}
.SettingsButton{
border: none;
outline: none;
margin-right: 10px;
transition: all .3s ease;
}
.SettingsButton:hover {
scale: 1.1;
}
.colorInput{
background-color: transparent;
width: 31px;
height: 35px;
border-radius: 50%;
border: none;
}
.colorInput::-webkit-color-swatch {
border-radius: 50%;
border: 2px solid #fff;
}
.whiteBorder_colorInput::-webkit-color-swatch {
border-color: #fff;
}
#dclinkdiv {
display: flex;
flex-direction: row;
}
.dclinks {
width: calc(50% - 5px);
height: 36px;
display: flex;
justify-content: center;
align-items: center;
background-color: rgba(88, 101, 242, 1);
border-radius: 6px;
margin: 0 auto;
color: #fff;
}
#cm_close__settings {
width: 50px;
transition: all .3s ease;
}
#cm_close__settings svg:hover {
scale: 1.1;
}
#cm_close__settings svg {
transition: all .3s ease;
}
.modTitleText {
text-align: center;
font-size: 16px;
}
.modItem {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.mod_tab-content {
width: 100%;
margin: 10px;
overflow: auto;
display: flex;
flex-direction: column;
}
#Tab6 .mod_tab-content {
overflow-y: auto;
max-height: 230px;
display: flex;
flex-wrap: nowrap;
flex-direction: column;
gap: 10px;
}
.tab-content, #coins-tab, #chests-tab {
overflow-x: hidden;
justify-content: center;
}
#shop-skins-buttons::after {
background: #050505;
}
.w-100 {
width: 100%
}
.btn:hover {
color: unset;
}
#savedNames {
background-color: #000;
padding: 5px;
border-radius: 5px;
overflow-y: auto;
height: 155px;
background-image: url("https://raw.githubusercontent.com/Sigmally/SigMod/main/images/purple_gradient.png");
background-size: cover;
background-position: center;
background-repeat: no-repeat;
box-shadow: 0 0 10px #000;
}
.scroll {
scroll-behavior: smooth;
}
/* Chrome, Safari */
.scroll::-webkit-scrollbar {
width: 7px;
}
.scroll::-webkit-scrollbar-track {
background: #222;
border-radius: 5px;
}
.scroll::-webkit-scrollbar-thumb {
background-color: #333;
border-radius: 5px;
}
.scroll::-webkit-scrollbar-thumb:hover {
background: #353535;
}
/* Firefox */
.scroll {
scrollbar-width: thin;
scrollbar-color: #333 #222;
}
.scroll:hover {
scrollbar-color: #353535 #222;
}
.themes {
display: flex;
flex-direction: row;
width: 100%;
height: 420px;
background: #000;
border-radius: 5px;
overflow-y: scroll;
gap: 10px;
padding: 5px;
flex-wrap: wrap;
justify-content: center;
}
.themeContent {
width: 50px;
height: 50px;
border: 2px solid #222;
border-radius: 50%;
background-position: center;
}
.theme {
height: 75px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
cursor: pointer;
}
.delName {
font-weight: 500;
background: #e17e7e;
height: 20px;
border: none;
border-radius: 5px;
font-size: 10px;
margin-left: 5px;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
width: 20px;
}
.NameDiv {
display: flex;
background: #111;
border-radius: 5px;
margin: 5px;
padding: 3px 8px;
height: 34px;
align-items: center;
justify-content: space-between;
cursor: pointer;
box-shadow: 0 5px 10px -2px #000;
}
.NameLabel {
cursor: pointer;
font-weight: 500;
text-align: center;
color: #fff;
}
.resetButton {
width: 25px;
height: 25px;
background-image: url("https://raw.githubusercontent.com/Sigmally/SigMod/main/images/reset.svg");
background-color: transparent;
border: none;
}
.modAlert {
position: fixed;
top: 80px;
left: 50%;
transform: translate(-50%, -50%);
z-index: 99995;
background: #3F3F3F;
border-radius: 10px;
display: flex;
flex-direction: column;
gap: 5px;
padding: 10px;
color: #fff;
}
@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');
.tournamentAlert {
position: fixed;
top: 100px;
left: 50%;
transform: translate(-50%, -50%);
z-index: 99995;
background: url("https://app.czrsd.com/static/tournament_winteredition.png");
background-size: cover;
background-position: center;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 0 10px #4e7ed5;
}
.tournamentAlert * {
font-family: 'Poppins', sans-serif;
}
.tournamentAlert__inner {
border-radius: 10px;
display: flex;
flex-direction: column;
gap: 10px;
color: #fff;
padding: 10px;
border-radius: 10px;
}
.tournamentAlert .tHeader span {
font-size: 16px;
font-weight: 600;
}
.tournamentAlert p {
text-align: center;
}
.tournamentAlert .tHeader button {
background: #C13939;
border: none;
border-radius: 50%;
height: 32px;
width: 32px;
display: flex;
justify-content: center;
align-items: center;
transition: all 0.3s ease-in-out;
}
.tournamentAlert .tHeader button:hover {
background: #e05151;
scale: 1.05;
box-shadow: 0 0 10px #e05151;
}
.tournamentAlert::after {
content: '';
width: 102%;
height: 100%;
position: absolute;
top: 0;
left: -2px;
background: rgba(0, 0, 0, .8);
z-index: -1;
}
.tournamentAlert .tFooter img {
width: 50px;
height: 50px;
border-radius: 100%;
}
.tournamentAlert .tFooter button {
background: #0057FF;
border: none;
border-radius: 20px;
padding: 8px;
display: flex;
align-items: center;
gap: 10px;
transition: all 0.3s ease-in-out;
}
.tournamentAlert .tFooter button:hover {
background: #0077ff;
scale: 1.1;
box-shadow: 0 0 10px #0077ff;
}
.alert_overlay {
position: absolute;
top: 0;
left: 0;
z-index: 9999999;
pointer-events: none;
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: start;
align-items: center;
}
.infoAlert {
padding: 5px;
border-radius: 5px;
margin-top: 5px;
color: #fff;
}
.modAlert-success {
background: #5BA55C;
}
.modAlert-success .modAlert-loader {
background: #6BD56D;
}
.modAlert-default {
background: #151515;
}
.modAlert-default .modAlert-loader {
background: #222;
}
.modAlert-danger {
background: #D44121;
}
.modAlert-danger .modAlert-loader {
background: #A5361E;
}
#free-coins .modAlert-danger {
background: #fff !important;
}
.modAlert-loader {
width: 100%;
height: 2px;
margin-top: 5px;
transition: all .3s ease-in-out;
animation: loadAlert 2s forwards;
}
@keyframes loadAlert {
0% {
width: 100%;
}
100% {
width: 0%;
}
}
.themeEditor {
z-index: 999999999999;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, .85);
color: #fff;
padding: 10px;
border-radius: 10px;
box-shadow: 0 0 10px #000;
width: 400px;
}
.theme_editor_header {
display: flex;
justify-content: space-between;
align-items: center;
gap: 10px;
}
.theme-editor-tab {
display: flex;
justify-content: center;
align-items: start;
flex-direction: column;
margin-top: 10px
}
.themes_preview {
width: 50px;
height: 50px;
border: 2px solid #fff;
border-radius: 2px;
display: flex;
justify-content: center;
align-items: center;
}
.modKeybindings {
display: flex;
flex-direction: column;
overflow-y: scroll;
max-height: 170px;
}
.modKeybindings > label {
margin-right: 5px;
}
#signInBtn, #nick, #gamemode, .form-control, .profile-header, .coins-num, #clan-members, .member-index, .member-level, #clan-requests {
background: rgba(0, 0, 0, 0.4) !important;
color: #fff !important;
}
.profile-name, #progress-next, .member-desc > p:first-child, #clan-leave > div, .clans-item > div > b, #clans-input input, #shop-nav button {
color: #fff !important;
}
.head-desc, #shop-nav button {
border: 1px solid #000;
}
#clan-handler, #request-handler, #clans-list, #clans-input, .clans-item button, #shop-content, #shop-nav button:hover, .card-particles-bar-bg {
background: #111;
color: #fff !important;
}
#clans_and_settings {
height: auto !important;
}
.card-body {
background: linear-gradient(180deg, #000 0%, #1b354c 100%);
}
.free-card:hover .card-body {
background: linear-gradient(180deg, #111 0%, #1b354c 100%);
}
#shop-tab-body, #shop-skins-buttons, #shop-nav {
background: #050505;
}
#clan-leave {
background: #111;
bottom: -1px;
}
.sent {
position: relative;
width: 100px;
}
.sent::before {
content: "Sent request";
width: 100%;
height: 10px;
word-spacing: normal;
white-space: nowrap;
position: absolute;
background: #4f79f9;
display: flex;
justify-content: center;
align-items: center;
}
.btn, .sign-in-out-btn {
transition: all .2s ease;
}
#clan .connecting__content, #clans .connecting__content {
background: #151515;
color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, .5);
}
.skin-select__icon-text {
color: #fff;
}
.justify-sb {
display: flex;
align-items: center;
justify-content: space-between;
}
.macro-extanded_input {
width: 75px;
text-align: center;
}
#gamemode option {
background: #111;
}
.stats-line {
width: 100%;
user-select: none;
margin-bottom: 5px;
padding: 5px;
background: #050505;
border: 1px solid var(--default-mod);
border-radius: 5px;
}
.my-5 {
margin: 5px 0;
}
.stats-info-text {
color: #7d7d7d;
}
.setting-card-wrapper {
margin-right: 10px;
padding: 10px;
background: #161616;
border-radius: 5px;
display: flex;
flex-direction: column;
}
.setting-card {
display: flex;
align-items: center;
justify-content: space-between;
}
.setting-card-action {
display: flex;
align-items: center;
gap: 5px;
cursor: pointer;
}
.setting-card-action {
width: 100%;
}
.setting-card-name {
font-size: 16px;
user-select: none;
width: 100%;
}
.mod-small-modal {
display: flex;
flex-direction: column;
gap: 10px;
position: absolute;
z-index: 99999;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #191919;
box-shadow: 0 5px 15px -2px #000;
border: 2px solid var(--default-mod-color);
padding: 10px;
border-radius: 5px;
}
.mod-small-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.mod-small-modal-header h1 {
font-size: 20px;
font-weight: 500;
margin: 0;
}
.mod-small-modal-content {
display: flex;
flex-direction: column;
width: 100%;
align-items: center;
}
.mod-small-modal-content_selectImage {
display: flex;
flex-direction: column;
gap: 10px;
}
.previmg {
width: 50px;
height: 50px;
border: 2px solid #ccc;
}
.stats__item>span, #title, .stats-btn__text {
color: #fff;
}
.top-users__inner::-webkit-scrollbar-thumb {
border: none;
}
.modChat {
min-width: 450px;
max-width: 450px;
min-height: 285px;
max-height: 285px;
color: #fafafa;
padding: 10px;
position: absolute;
bottom: 10px;
left: 10px;
z-index: 999;
border-radius: .5rem;
overflow: hidden;
opacity: 1;
transition: all .3s ease;
}
.modChat__inner {
min-width: 430px;
max-width: 430px;
min-height: 265px;
max-height: 265px;
height: 100%;
display: flex;
flex-direction: column;
gap: 5px;
justify-content: flex-end;
opacity: 1;
transition: all .3s ease;
}
.mod-compact {
transform: scale(0.78);
}
.mod-compact.modChat {
left: -40px;
bottom: -20px;
}
.mod-compact.chatAddedContainer {
left: 350px;
bottom: -17px;
}
#scroll-down-btn {
position: absolute;
bottom: 60px;
left: 50%;
transform: translateX(-50%);
width: 80px;
display:none;
box-shadow:0 0 5px #000;
z-index: 5;
}
.modchat-chatbuttons {
margin-bottom: auto;
display: flex;
gap: 5px;
}
.chat-context {
position: absolute;
z-index: 999999;
width: 100px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 5px;
background: #181818;
border-radius: 5px;
}
.chat-context span {
color: #fff;
user-select: none;
padding: 5px;
white-space: nowrap;
}
.chat-context button {
width: 100%;
background-color: transparent;
border: none;
border-top: 2px solid #747474;
outline: none;
color: #fff;
transition: all .3s ease;
}
.chat-context button:hover {
backgrokund-color: #222;
}
.tagText {
margin-left: auto;
font-size: 14px;
}
#mod-messages {
position: relative;
display: flex;
flex-direction: column;
max-height: 185px;
overflow-y: auto;
direction: rtl;
scroll-behavior: smooth;
}
.message {
direction: ltr;
margin: 2px 0 0 5px;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
.message_name {
user-select: none;
}
.message .time {
color: rgba(255, 255, 255, 0.7);
font-size: 12px;
}
#chatInputContainer {
display: flex;
gap: 5px;
align-items: center;
padding: 5px;
background: rgba(25,25,25, .6);
border-radius: .5rem;
overflow: hidden;
}
.chatInput {
flex-grow: 1;
border: none;
background: transparent;
color: #fff;
padding: 5px;
outline: none;
max-width: 100%;
}
.chatButton {
background: #8a25e5;
border: none;
border-radius: 5px;
padding: 5px 10px;
height: 100%;
color: #fff;
transition: all 0.3s;
cursor: pointer;
display: flex;
align-items: center;
height: 28px;
justify-content: center;
gap: 5px;
}
.chatButton:hover {
background: #7a25e5;
}
.chatCloseBtn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.emojisContainer {
display: flex;
flex-direction: column;
gap: 5px;
}
.chatAddedContainer {
position: absolute;
bottom: 10px;
left: 465px;
z-index: 9999;
padding: 10px;
background: #151515;
border-radius: .5rem;
min-width: 172px;
max-width: 172px;
min-height: 250px;
max-height: 250px;
}
#categories {
overflow-y: auto;
max-height: calc(250px - 50px);
gap: 2px;
}
.category {
width: 100%;
display: flex;
flex-direction: column;
gap: 2px;
}
.category span {
color: #fafafa;
font-size: 14px;
text-align: center;
}
.emojiContainer {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
}
#categories .emoji {
padding: 2px;
border-radius: 5px;
font-size: 16px;
user-select: none;
cursor: pointer;
}
.chatSettingsContainer {
padding: 10px 3px;
}
.chatSettingsContainer .scroll {
display: flex;
flex-direction: column;
gap: 10px;
max-height: 235px;
overflow-y: auto;
padding: 0 10px;
}
.csBlock {
border: 2px solid #050505;
border-radius: .5rem;
color: #fff;
display: flex;
align-items: center;
flex-direction: column;
gap: 5px;
padding-bottom: 5px;
}
.csBlock .csBlockTitle {
background: #080808;
width: 100%;
padding: 3px;
text-align: center;
}
.csRow {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 5px;
width: 100%;
}
.csRowName {
display: flex;
gap: 5px;
align-items: start;
}
.csRowName .infoIcon {
width: 14px;
cursor: pointer;
}
.modInfoPopup {
position: absolute;
top: 2px;
left: 58%;
text-align: center;
background: #151515;
border: 1px solid #607bff;
border-radius: 10px;
transform: translateX(-50%);
white-space: nowrap;
padding: 5px;
z-index: 99999;
}
.modInfoPopup::after {
content: '';
display: block;
position: absolute;
bottom: -7px;
background: #151515;
right: 50%;
transform: translateX(-50%) rotate(-45deg);
width: 12px;
height: 12px;
border-left: 1px solid #607bff;
border-bottom: 1px solid #607bff;
}
.modInfoPopup p {
margin: 0;
font-size: 12px;
color: #fff;
}
.error-message_sigMod {
display: flex;
align-items: center;
position: absolute;
bottom: 20px;
right: -500px;
background: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, .8);
z-index: 9999999;
width: 426px;
border-radius: 10px;
padding: 10px;
gap: 6px;
transition: all .3s ease-out;
}
.minimapContainer {
display: flex;
flex-direction: column;
align-items: end;
pointer-events: none;
position: absolute;
bottom: 0;
right: 0;
z-index: 99999;
}
.tournament_time {
color: #fff;
font-size: 15px;
}
.minimap {
border-radius: 2px;
border-top: 1px solid rgba(255, 255, 255, .5);
border-left: 1px solid rgba(255, 255, 255, .5);
box-shadow: 0 0 4px rgba(255, 255, 255, .5);
}
#tag {
width: 50px;
}
.blur {
color: transparent!important;
text-shadow: 0 0 6px hsl(0deg 0% 90% / 70%);
transition: all .2s;
}
.blur:focus, .blur:hover {
color: #fafafa!important;
text-shadow: none;
}
.progress-row button {
background: transparent;
}
.mod_player-stats {
display: flex;
flex-direction: column;
gap: 5px;
align-self: start;
}
.mod_player-stats .player-stats-grid {
display: grid;
grid-template-columns: 1.2fr 1.1fr;
gap: 5px;
}
.player-stat {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 10px;
background: rgba(05, 05, 05, .75);
border-radius: 5px;
width: 100%;
height: 85px;
box-shadow: 0px 2px 10px -2px #000;
z-index: 2;
}
.player-stat span[id] {
font-size: 17px;
}
.quickAccess {
background: #050505;
display: flex;
flex-direction: column;
gap: 5px;
padding: 5px;
border-radius: 5px;
width: 100%;
max-height: 154px;
overflow-y: auto;
}
.quickAccess div.modRowItems {
padding: 2px!important;
}
#mod_home .justify-sb {
z-index: 2;
}
.modTitleText {
font-size: 15px;
color: #fafafa;
text-align: start;
}
.modDescText {
text-align: start;
font-size: 12px;
color: #777;
}
.modButton-secondary {
background-color: #171717;
color: #fff;
border: none;
padding: 5px 15px;
border-radius: 15px;
}
.vr {
width: 2px;
height: 250px;
background-color: #fafafa;
}
.vr2 {
width: 1px;
height: 26px;
background-color: #202020;
}
.modProfileWrapper {
display: flex;
flex-direction: column;
gap: 5px;
}
.modUserProfile {
display: flex;
flex-direction: column;
gap: 7px;
border-radius: 5px;
background: #050505;
min-width: 300px;
max-width: 300px;
height: 154px;
max-height: 154px;
padding: 5px 10px;
}
#my-profile-bio {
overflow-y: scroll;
max-height: 75px;
}
.brand_wrapper {
position: relative;
height: 72px;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.brand_img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 72px;
border-radius: 10px;
object-fit: cover;
object-position: center;
z-index: 1;
box-shadow: 0 0 10px #000;
}
.brand_credits {
font-size: 16px;
color: #D3A7FF
}
.p_s_n {
background-color: #050505;
border-radius: 15px;
box-shadow: 0 3px 10px -2px #050505;
margin: 35px 0;
font-size: 16px;
width: 50%;
align-self: center;
}
.userId_wrapper {
background: #000;
padding: 5px 20px;
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: center;
width: 50%;
border-radius: 10px;
align-self: center;
position: relative;
}
.userId_copy {
position: absolute;
top: -10px;
right: -10px;
background: #050505;
border-radius: 100%;
padding: 10px;
width: 35px;
height: 35px;
cursor: pointer;
transition: all .3s ease;
}
.userId_copy:hover {
transform: scale(1.1);
}
.brand_yt {
display: flex;
justify-content: center;
align-items: center;
gap: 20px;
}
.yt_wrapper {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 10px;
width: 122px;
height: 100px;
padding: 10px;
background-color: #B63333;
border-radius: 15px;
cursor: pointer;
}
.yt_wrapper span {
user-select: none;
}
.hidden_full {
display: none !important;
visibility: hidden;
}
.mod_overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, .7);
z-index: 999999;
display: flex;
justify-content: center;
align-items: center;
transition: all .3s ease;
}
.tournaments-wrapper {
position: absolute;
top: 60%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 999999;
background: #151515;
box-shadow: 0 5px 10px 2px #000;
border-radius: 0.75rem;
padding: 2.25rem;
color: #fafafa;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
min-width: 632px;
opacity: 0;
transition: all .3s ease;
animation: 0.5s ease fadeIn forwards;
}
@keyframes fadeIn {
0% {
top: 60%;
opacity: 0;
}
100% {
top: 50%;
opacity: 1;
}
}
.tournaments h1 {
margin: 0;
}
.t_profile {
display: flex;
flex-direction: column;
align-items: center;
}
.t_profile img {
border: 2px solid #ccc;
border-radius: 50%;
}
.team {
display: flex;
gap: 10px;
padding: 10px;
position: relative;
}
.team.blue {
border-radius: 5px 0 0 5px;
}
.team.red {
border-radius: 0 5px 5px 0;
}
.blue {
background: rgb(71, 113, 203);
}
.red {
background: rgb(203, 71, 71);
}
.blue_polygon {
width: 75px;
clip-path: polygon(0 100%, 0 0, 100% 100%);
background: rgb(71, 113, 203);
}
.red_polygon {
width: 75px;
clip-path: polygon(100% 0, 0 0, 100% 100%);
background: rgb(203, 71, 71);
}
.vs {
position: relative;
align-items: center;
justify-content: center;
}
.vs span {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
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;
font-size: 28px;
}
details {
border: 1px solid #aaa;
border-radius: 4px;
padding: 0.5em 0.5em 0;
user-select: none;
text-align: start;
}
summary {
font-weight: bold;
margin: -0.5em -0.5em 0;
padding: 0.5em;
}
details[open] {
padding: 0.5em;
}
details[open] summary {
border-bottom: 1px solid #aaa;
margin-bottom: 0.5em;
}
button[disabled] {
filter: grayscale(1);
}
.tournament_alert {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: #151515;
color: #fff;
text-align: center;
padding: 20px;
z-index: 999999;
border-radius: 10px;
box-shadow: 0 0 10px #000;
display: flex;
gap: 10px;
}
.tournament-profile {
width: 50px;
height: 50px;
border-radius: 50%;
box-shadow: 0 0 10px #000;
}
.tround_text {
color: #fff;
font-size: 24px;
position: absolute;
bottom: 30%;
left: 50%;
transform: translate(-50%, -50%);
}
.claimedBadgeWrapper {
background: linear-gradient(232deg, #020405 1%, #04181E 100%);
border-radius: 10px;
width: 320px;
height: 330px;
box-shadow: 0 0 40px -20px #39bdff;
display: flex;
flex-direction: column;
gap: 10px;
align-items: center;
justify-content: center;
color: #fff;
padding: 10px;
}
.btn-cyan {
background: #53B6CC;
border: none;
border-radius: 5px;
font-size: 16px;
color: #fff;
font-weight: 500;
width: fit-content;
padding: 5px 10px;
}
.playTimer {
z-index: 2;
position: absolute;
top: 128px;
left: 4px;
color: #8d8d8d;
font-size: 14px;
font-weight: 500;
user-select: none;
pointer-events: none;
}
.modInput-wrapper {
position: relative;
display: inline-block;
width: 100%;
}
.modInput-secondary {
display: inline-block;
width: 100%;
padding: 10px 0 10px 15px;
font-weight: 400;
color: #E9E9E9;
background: #050505;
border: 0;
border-radius: 3px;
outline: 0;
text-indent: 70px;
transition: all .3s ease-in-out;
}
.modInput-secondary.t-indent-120 {
text-indent: 120px;
}
.modInput-secondary::-webkit-input-placeholder {
color: #050505;
text-indent: 0;
font-weight: 300;
}
.modInput-secondary + label {
display: inline-block;
position: absolute;
top: 8px;
left: 0;
bottom: 8px;
padding: 5px 15px;
color: #E9E9E9;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
text-shadow: 0 1px 0 rgba(19, 74, 70, 0);
transition: all .3s ease-in-out;
border-radius: 3px;
background: rgba(122, 134, 184, 0);
}
.modInput-secondary + label:after {
position: absolute;
content: "";
width: 0;
height: 0;
top: 100%;
left: 50%;
margin-left: -3px;
border-left: 3px solid transparent;
border-right: 3px solid transparent;
border-top: 3px solid rgba(122, 134, 184, 0);
transition: all .3s ease-in-out;
}
.modInput-secondary:focus,
.modInput-secondary:active {
color: #E9E9E9;
text-indent: 0;
background: #050505;
}
.modInput-secondary:focus::-webkit-input-placeholder,
.modInput-secondary:active::-webkit-input-placeholder {
color: #aaa;
}
.modInput-secondary:focus + label,
.modInput-secondary:active + label {
color: #fff;
text-shadow: 0 1px 0 rgba(19, 74, 70, 0.4);
background: #7A86B8;
transform: translateY(-40px);
}
.modInput-secondary:focus + label:after,
.modInput-secondary:active + label:after {
border-top: 4px solid #7A86B8;
}
/* Friends & account */
.signIn-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, .4);
z-index: 999999;
display: flex;
justify-content: center;
align-items: center;
color: #E3E3E3;
opacity: 0;
transition: all .3s ease;
}
.signIn-wrapper {
background: #111111;
width: 450px;
display: flex;
flex-direction: column;
align-items: center;
border-radius: 10px;
color: #fafafa;
}
.signIn-header {
background: #181818;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px;
border-radius: 10px 10px 0 0;
}
.signIn-header span {
font-weight: 500;
font-size: 20px;
}
.signIn-body {
display: flex;
flex-direction: column;
gap: 10px;
align-items: center;
justify-content: start;
padding: 40px 40px 5px 40px;
width: 100%;
}
#errMessages {
color: #AC3D3D;
flex-direction: column;
gap: 5px;
}
.form-control {
border-width: 1px;
}
.form-control.error-border {
border-color: #AC3D3D;
}
.friends_header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
gap: 10px;
width: 100%;
padding: 10px;
}
.friends_body {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
width: 100%;
height: 360px;
max-height: 360px;
overflow-y: auto;
padding-right: 10px;
}
.allusers {
padding: 0;
}
#users-container {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
width: 100%;
height: 340px;
max-height: 340px;
overflow-y: auto;
padding-right: 10px;
}
.profile-img {
position: relative;
width: 52px;
height: 52px;
border-radius: 100%;
border: 1px solid #C8C9D9;
}
.profile-img img {
width: 100%;
height: 100%;
border-radius: 100%;
}
.status_icon {
position: absolute;
width: 15px;
height: 15px;
top: 0;
left: 0;
border-radius: 50%;
}
.online_icon {
background-color: #3DB239;
}
.offline_icon {
background-color: #B23939;
}
.Owner_role {
color: #3979B2;
}
.Moderator_role {
color: #39B298;
}
.Vip_role {
color: #E1A33E;
}
.friends_row {
display: flex;
flex-direction: row;
width: 100%;
justify-content: space-between;
align-items: center;
background: #090909;
border-radius: 8px;
padding: 10px;
}
.friends_row .val {
width: fit-content;
height: fit-content;
padding: 5px 20px;
box-sizing: content-box;
}
.feedback_row {
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
width: 80%;
position: absolute;
bottom: 18px;
left: 50%;
transform: translateX(-50%);
padding: 8px;
border-radius: 5px;
background: linear-gradient(45deg, #1a132b, #111f48);
box-shadow: 0 10px 10px #000;
}
.feedback_row textarea {
padding: 5px;
height: 50px;
}
.feedback_row .feedback-footer span {
font-size: 11px;
}
.feedback_row button {
width: 130px;
align-self: flex-end;
}
.user-profile-wrapper {
cursor: pointer;
}
.user-profile-wrapper > * {
cursor: default;
}
.textarea-container {
position: relative;
width: 100%;
}
.textarea-container textarea {
width: 100%;
height: 120px;
resize: none;
}
.char-counter {
position: absolute;
bottom: 5px;
right: 5px;
color: gray;
}
/* couldn't find any good name... */
.____modAlert {
position: fixed;
top: 80px;
left: 50%;
transform: translate(-50%, -50%);
z-index: 99995;
background: #3F3F3F;
border-radius: 10px;
display: flex;
flex-direction: column;
padding: 10px;
color: #fff;
}
.friends-chat-wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #111111;
display: flex;
flex-direction: column;
z-index: 999;
opacity: 0;
transition: all .3s ease;
}
.friends-chat-header {
display: flex;
justify-content: space-between;
align-items: center;
background: #050505;
width: 100%;
padding: 8px;
height: 68px;
}
.friends-chat-body {
height: calc(100% - 68px);
display: flex;
flex-direction: column;
}
.friends-chat-messages {
height: 300px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 5px;
padding: 10px;
}
.friends-message {
background: #000;
padding: 8px;
border-radius: 6px;
display: flex;
flex-direction: column;
max-width: 200px;
width: fit-content;
}
.message-date {
color: #8a8989;
font-size: 11px;
text-align: right;
}
.message-right {
align-self: flex-end;
}
.messenger-wrapper {
width: 100%;
height: 60px;
padding: 10px;
}
.messenger-wrapper .container {
display: flex;
flex-direction: row;
gap: 10px;
width: 100%;
background: #0a0a0a;
padding: 10px 5px;
border-radius: 10px;
}
.messenger-wrapper .container input {
padding: 5px;
}
.messenger-wrapper .container button {
width: 150px;
}
/* deathscreen challenges */
#menu-wrapper {
overflow-x: visible;
overflow-y: visible;
}
.challenges_deathscreen {
width: 450px;
background: rgb(21, 21, 21);
display: flex;
flex-direction: column;
gap: 8px;
padding: 7px;
border-radius: 10px;
margin-bottom: 15px;
}
.challenges-col {
display: flex;
flex-direction: column;
gap: 4px;
align-items: center;
width: 100%;
}
.challenge-row {
display: flex;
align-items: center;
background: rgba(0, 0, 0, .4);
justify-content: space-between;
padding: 5px 10px;
border-radius: 4px;
width: 100%;
}
.challenges-title {
font-size: 16px;
font-weight: 600;
}
.challenge-best-secondary {
background: #1d1d1d;
border-radius: 10px;
text-align: center;
padding: 5px 8px;
min-width: 130px;
}
.challenge-collect-secondary {
background: #4C864B;
border-radius: 10px;
text-align: center;
padding: 5px 8px;
outline: none;
border: none;
min-width: 130px;
}
`
},
respawnTime: Date.now(),
respawnCooldown: 1000,
move(cx, cy) {
const mouseMoveEvent = new MouseEvent("mousemove", { clientX: cx, clientY: cy });
const canvas = document.querySelector("canvas");
canvas.dispatchEvent(mouseMoveEvent);
},
async game() {
const { fillRect, fillText, strokeText, moveTo, arc, drawImage } = CanvasRenderingContext2D.prototype;
const byId = (id) => document.getElementById(id);
const mapColor = byId("mapColor");
const nameColor = byId("nameColor");
const borderColor = byId("borderColor");
const foodColor = byId("foodColor");
const cellColor = byId("cellColor");
const gradientNameColor1 = byId("gradientNameColor1");
const gradientNameColor2 = byId("gradientNameColor2");
const mapColorReset = byId("mapColorReset");
const nameColorReset = byId("nameColorReset");
const borderColorReset = byId("borderColorReset");
const foodColorReset = byId("foodColorReset");
const cellColorReset = byId("cellColorReset");
const gradientColorReset1 = byId("gradientColorReset1");
const gradientColorReset2 = byId("gradientColorReset2");
const showPosition = document.getElementById("showPosition");
if (showPosition && !showPosition.checked) showPosition.click();
let disabledGColors = 0;
const reset = (type) => {
const white = "#ffffff";
switch (type) {
case 'map':
modSettings.mapColor = null;
mapColor.value = white;
break;
case 'name':
modSettings.nameColor = null;
nameColor.value = white;
break;
case 'gradName1':
modSettings.gradientName.color1 = null;
gradientNameColor1.value = white;
if (modSettings.gradientName.color2 === null) {
modSettings.gradientName.enabled = false;
}
break;
case 'gradName2':
modSettings.gradientName.color2 = null;
gradientNameColor2.value = white;
if (modSettings.gradientName.color1 === null) {
modSettings.gradientName.enabled = false;
}
break;
case 'border':
modSettings.borderColor = null;
borderColor.value = white;
break;
case 'food':
modSettings.foodColor = null;
foodColor.value = white;
break;
case 'cell':
modSettings.cellColor = null;
cellColor.value = white;
break;
case 'skin':
modSettings.skinImage.original = null;
modSettings.skinImage.replaceImg = null;
if (confirm("Please refresh the page to make it work. Reload?")) {
location.reload();
}
break;
case 'virus':
modSettings.virusImage = "/assets/images/viruses/2.png";
if (confirm("Please refresh the page to make it work. Reload?")) {
location.reload();
}
break;
}
updateStorage();
};
const loadStorage = () => {
if (modSettings.nameColor) {
nameColor.value = modSettings.nameColor;
}
if (modSettings.mapColor) {
mapColor.value = modSettings.mapColor;
}
if (modSettings.borderColor) {
borderColor.value = modSettings.borderColor;
}
if (modSettings.foodColor) {
foodColor.value = modSettings.foodColor;
}
if (modSettings.cellColor) {
cellColor.value = modSettings.cellColor;
}
if (modSettings.virusImage) {
loadVirusImage(modSettings.virusImage);
}
if (modSettings.skinImage.original !== null) {
loadSkinImage(modSettings.skinImage.original, modSettings.skinImage.replaceImg);
}
};
loadStorage();
mapColor.addEventListener("input", () => {
modSettings.mapColor = mapColor.value;
updateStorage();
});
nameColor.addEventListener("input", () => {
modSettings.nameColor = nameColor.value;
updateStorage();
});
gradientNameColor1.addEventListener("input", () => {
if (!modSettings.gradientName.enabled) {
modSettings.gradientName.enabled = true;
}
modSettings.gradientName.color1 = gradientNameColor1.value;
updateStorage();
});
gradientNameColor2.addEventListener("input", () => {
modSettings.gradientName.color2 = gradientNameColor2.value;
updateStorage();
});
borderColor.addEventListener("input", () => {
modSettings.borderColor = borderColor.value;
updateStorage();
});
foodColor.addEventListener("input", () => {
modSettings.foodColor = foodColor.value;
updateStorage();
});
cellColor.addEventListener("input", () => {
modSettings.cellColor = cellColor.value;
updateStorage();
});
mapColorReset.addEventListener("click", () => reset("map"));
borderColorReset.addEventListener("click", () => reset("border"));
nameColorReset.addEventListener("click", () => reset("name"));
gradientColorReset1.addEventListener("click", () => reset("gradName1"));
gradientColorReset2.addEventListener("click", () => reset("gradName2"));
foodColorReset.addEventListener("click", () => reset("food"));
cellColorReset.addEventListener("click", () => reset("cell"));
// Render new colors / images
CanvasRenderingContext2D.prototype.fillRect = function (x, y, width, height) {
if ((width + height) / 2 === (window.innerWidth + window.innerHeight) / 2) {
this.fillStyle = modSettings.mapColor;
}
fillRect.apply(this, arguments);
};
CanvasRenderingContext2D.prototype.arc = function(x, y, radius, startAngle, endAngle, anticlockwise) {
if (modSettings.fps.hideFood || modSettings.fps.fpsMode) {
if (radius <= 20) {
this.fillStyle = "transparent";
this.strokeStyle = "transparent";
}
}
if (radius >= 86 && modSettings.cellColor) {
this.fillStyle = hexToRgba(modSettings.cellColor, "0.4");
} else if (radius <= 20 && modSettings.foodColor !== null && !modSettings.fps.fpsMode && !modSettings.fps.hideFood) {
this.fillStyle = modSettings.foodColor;
this.strokeStyle = modSettings.foodColor;
}
arc.apply(this, arguments);
};
let friend_names = this.friend_names;
let highlightFriends = this.friends_settings.highlight_friends;
let highlightColor = this.friends_settings.highlight_color;
CanvasRenderingContext2D.prototype.fillText = function (text, x, y) {
if (text === mods.nick && !modSettings.gradientName.enabled && modSettings.nameColor !== null) {
this.fillStyle = modSettings.nameColor;
}
if (text === mods.nick && modSettings.gradientName.enabled) {
const width = this.measureText(text).width;
const fontSize = 8;
const gradient = this.createLinearGradient(x - width / 2 + fontSize / 2, y, x + width / 2 - fontSize / 2, y + fontSize);
const color1 = modSettings.gradientName.color1 ?? "#ffffff";
const color2 = modSettings.gradientName.color2 ?? "#ffffff";
gradient.addColorStop(0, color1);
gradient.addColorStop(1, color2);
this.fillStyle = gradient;
}
if (text.startsWith("X:")) {
this.fillStyle = "transparent";
const [, xValue, yValue] = /X: (.*), Y: (.*)/.exec(text) || [];
if (xValue == undefined) return;
const position = { x: parseFloat(xValue), y: parseFloat(yValue) };
if (menuClosed() && !isDeath()) {
if (position.x === 0 && position.y === 0) return;
// send position every 500 milliseconds
if (Date.now() - lastLogTime >= 500) {
activeCellX = position.x;
activeCellY = position.y;
if (client.readyState === 1) {
client.send({
type: "position",
content: [activeCellX, activeCellY, mods.nick, client.id]
});
}
lastLogTime = Date.now(); // Update last log time
}
} else if (isDeath() && !dead2) {
dead2 = true;
activeCellX = null;
activeCellY = null;
client.send({
type: "position",
content: [null, null, null, client.id]
});
}
}
if (modSettings.fps.removeOutlines) {
this.shadowBlur = 0;
this.shadowColor = "transparent";
}
if (text.length > 21 && modSettings.fps.shortLongNames || modSettings.fps.fpsMode) {
text = text.slice(0, 21) + "...";
}
// only for leaderboard
if (friend_names.has(text) && highlightFriends) {
this.fillStyle = highlightColor;
}
if (text.includes("Score") && _getScore) {
_getScore = false;
const currentScore = text.substring(6).replace(/\s/g, '');
lastScore = parseInt(currentScore, 10);
const scoreText = document.getElementById("t-myScore");
if (!scoreText) return;
scoreText.textContent = `Your score: ${lastScore}`;
}
return fillText.apply(this, arguments);
};
CanvasRenderingContext2D.prototype.strokeText = function (text, x, y) {
if (text.length > 21 && modSettings.fps.shortLongNames || modSettings.fps.fpsMode) {
text = text.slice(0, 21) + "...";
}
if (modSettings.fps.removeOutlines) {
this.shadowBlur = 0;
this.shadowColor = "transparent";
} else {
this.shadowBlur = 7;
this.shadowColor = '#000';
}
return strokeText.apply(this, arguments);
};
// Map border lineWidth: 20
CanvasRenderingContext2D.prototype.moveTo = function (x, y) {
this.strokeStyle = modSettings.borderColor;
return moveTo.apply(this, arguments);
};
function loadVirusImage(img) {
const replacementVirus = new Image();
replacementVirus.src = img;
const originalDrawImage = CanvasRenderingContext2D.prototype.drawImage;
CanvasRenderingContext2D.prototype.drawImage = function(image, ...args) {
if (image.src && image.src.endsWith("2-min.png")) {
originalDrawImage.call(this, replacementVirus, ...args);
} else {
originalDrawImage.apply(this, arguments);
}
};
}
function loadSkinImage(skin, img) {
const replacementSkin = new Image();
replacementSkin.src = img;
const originalDrawImage = CanvasRenderingContext2D.prototype.drawImage;
CanvasRenderingContext2D.prototype.drawImage = function(image, ...args) {
if (image instanceof HTMLImageElement && image.src.includes(`${skin}.png`)) {
originalDrawImage.call(this, replacementSkin, ...args);
} else {
originalDrawImage.apply(this, arguments);
}
};
}
// Virus & Skin image
const virusPreview = byId("virus");
const setVirus = byId("setVirus");
const virusURL = byId("virusURL");
const openVirusModal = byId("virusImageSelect");
const closeVirusModal = byId("closeVirusModal");
const virusModal = byId("virusModal");
const resetSkin = byId("resetSkin");
const resetVirus = byId("resetVirus");
openVirusModal.addEventListener("click", () => {
virusModal.style.display = "flex";
});
closeVirusModal.addEventListener("click", () => {
virusModal.style.display = "none";
});
setVirus.addEventListener("click", () => {
modSettings.virusImage = virusURL.value;
loadVirusImage(modSettings.virusImage);
updateStorage();
virusPreview.src = modSettings.virusImage;
});
resetVirus.addEventListener("click", () => {
modSettings.virusImage = "/assets/images/viruses/2.png";
updateStorage();
if(confirm("Please Refresh the page to make it work. Reload?")) {
location.reload();
}
});
const skinPreview = byId("skinPreview");
const skinURL = byId("skinURL");
const setSkin = byId("setSkin");
const openSkinModal = byId("SkinReplaceSelect");
const closeSkinModal = byId("closeSkinModal");
const skinModal = byId("skinModal");
const originalSkin = byId("originalSkinSelect");
openSkinModal.addEventListener("click", () => {
skinModal.style.display = "flex";
});
closeSkinModal.addEventListener("click", () => {
skinModal.style.display = "none";
});
setSkin.addEventListener("click", () => {
modSettings.skinImage.original = originalSkin.value;
modSettings.skinImage.replaceImg = skinURL.value;
loadSkinImage(modSettings.skinImage.original, modSettings.skinImage.replaceImg)
updateStorage();
skinPreview.src = modSettings.skinImage.replaceImg;
});
resetSkin.addEventListener("click", () => {
modSettings.skinImage.original = null;
modSettings.skinImage.replaceImg = null;
updateStorage();
if(confirm("Please Refresh the page to make it work. Reload?")) {
location.reload();
}
});
const deathScreenPos = byId("deathScreenPos");
const deathScreen = byId("__line2");
const applyMargin = (position) => {
switch (position) {
case "left":
deathScreen.style.marginLeft = "0";
break;
case "right":
deathScreen.style.marginRight = "0";
break;
case "top":
deathScreen.style.marginTop = "20px";
break;
case "bottom":
deathScreen.style.marginBottom = "20px";
break;
default:
deathScreen.style.margin = "auto";
}
};
deathScreenPos.addEventListener("change", () => {
const selected = deathScreenPos.value;
applyMargin(selected);
modSettings.deathScreenPos = selected;
updateStorage();
});
const defaultPosition = modSettings.deathScreenPos || "center";
applyMargin(defaultPosition);
deathScreenPos.value = defaultPosition;
const excludedSkins = ["Traitor", "Poco", "Cuddle", "Omega", "Leon", "Impostor", "Cute", "Raptor", "Maya", "Valentine", "Cara", "Fazbear", "Freddy", "Captain"];
const allSkins = await fetch('https://sigmally.com/api/skins/all')
.then(response => response.json())
.then(data => {
return data.data
.filter(item => !excludedSkins.includes(item.name.replace(".png", "")))
.map(item => item.name.replace(".png", ""));
});
originalSkin.innerHTML = `
${allSkins.map(skin => ``).join('')}
`;
},
menu() {
const mod_menu = document.createElement("div");
mod_menu.classList.add("mod_menu");
mod_menu.style.display = "none";
mod_menu.style.opacity = "0";
mod_menu.innerHTML = `
`;
document.body.append(mod_menu);
this.getSettings();
this.auth();
mod_menu.addEventListener("click", (e) => {
const wrapper = document.querySelector(".mod_menu_wrapper");
if (wrapper && wrapper.contains(e.target)) return;
mod_menu.style.opacity = 0;
setTimeout(() => {
mod_menu.style.display = "none";
}, 300);
});
function openModTab(tabId) {
const allTabs = document.getElementsByClassName("mod_tab");
const allTabButtons = document.querySelectorAll(".mod_nav_btn");
for (const tab of allTabs) {
tab.style.opacity = 0;
setTimeout(() => {
tab.style.display = "none";
}, 200);
}
allTabButtons.forEach(tabBtn => tabBtn.classList.remove("mod_selected"));
const selectedTab = document.getElementById(tabId);
setTimeout(() => {
selectedTab.style.display = "flex";
setTimeout(() => {
selectedTab.style.opacity = 1;
}, 10);
}, 200);
this.classList.add("mod_selected");
}
document.querySelectorAll(".mod_nav_btn").forEach(tabBtn => {
tabBtn.addEventListener("click", function() {
openModTab.call(this, this.id.replace("tab_", "mod_").replace("_btn", ""));
});
});
const videoList = [
"c-_KP3Ti2vQ?si=PHj2aNye5Uj_yXY9",
"IdBXpxmxYpU?si=4-fZWJUpewLG7c8H",
"xCUtce1D9f0?si=ybsNDCUL1M1WnuLc",
"B9LOJQOVH_Q?si=5qJPAxMT_EvFNW8Y",
"emLjRdTWm5A?si=4suR21ZEb-zmy1RD",
"190DhVhom5c?si=3TfghIX-u_wsBpR2",
"t_6L9G13vK8?si=wbiiT78h6RQUgPOd",
"B--KgGV7XMM?si=GkYtJ5ueks676_J9",
"Sq2UqzBO_IQ?si=ETvsFSueAwvl8Frm",
"OsO48zwyLfw?si=plItxN8vhFZbLAf8"
];
function getrdmVid() {
const randomIndex = Math.floor(Math.random() * videoList.length);
return videoList[randomIndex];
}
const randomVid = document.getElementById("randomVid");
randomVid.style = "align-self: start";
randomVid.innerHTML = `
`;
const openMenu = document.querySelectorAll("#clans_and_settings button")[1];
openMenu.removeAttribute("onclick");
openMenu.addEventListener("click", () => {
mod_menu.style.display = "flex";
setTimeout(() => {
mod_menu.style.opacity = 1;
}, 10);
});
const closeModal = document.getElementById("closeBtn");
closeModal.addEventListener("click", () => {
mod_menu.style.opacity = 0;
setTimeout(() => {
mod_menu.style.display = "none";
}, 300);
});
function virusImgVal() {
if(modSettings.virusImage === "/assets/images/viruses/2.png" || modSettings.virusImage === "") return "";
return modSettings.virusImage;
}
function skinImgVal() {
if(modSettings.skinImage.replaceImg === "" || modSettings.skinImage.replaceImg === null) return "";
return modSettings.skinImage.replaceImg;
}
setTimeout(() => {
if (!unsafeWindow.gameSettings.user) {
fetch(this.appRoutes.user, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
authorized: false,
nick: this.nick,
}),
})
.then((res) => res.ok ? res.json() : Promise.reject('Server error'))
.then((data) => data && data.banned ? this.banned() : null)
.catch((error) => console.error('Error during fetch:', error));
}
}, 10000);
const playTimerToggle = document.getElementById("playTimerToggle");
playTimerToggle.addEventListener("change", () => {
modSettings.playTimer = playTimerToggle.checked;
updateStorage();
});
if (modSettings.playTimer) {
playTimerToggle.checked = true;
}
const resetModSettings = document.getElementById("resetModSettings");
resetModSettings.addEventListener("click", () => {
if (confirm("Are you sure you want to reset the mod settings? A reload is required.")) {
this.removeStorage(storageName);
location.reload();
}
});
const resetGameSettings = document.getElementById("resetGameSettings");
resetGameSettings.addEventListener("click", () => {
if (confirm("Are you sure you want to reset the game settings? Your nick and more settings will be lost. A reload is required.")) {
unsafeWindow.settings.gameSettings = null;
this.removeStorage("settings");
location.reload();
}
});
},
setProfile(user) {
const img = document.getElementById("my-profile-img");
const name = document.getElementById("my-profile-name");
const role = document.getElementById("my-profile-role");
const bioText = document.getElementById("my-profile-bio");
const userId = document.getElementById("userId");
userId.innerText = user._id;
const copyUserId = document.getElementById("copyUserId");
copyUserId.addEventListener("click", () => {
navigator.clipboard.writeText(userId.innerText);
});
const bio = user.bio ? user.bio : "No bio.";
img.src = user.imageURL;
name.innerText = user.username;
role.innerText = user.role;
bioText.innerHTML = bio;
role.classList.add(`${user.role}_role`);
const tournament = location.href.endsWith("/tournament/");
if (!tournament) return;
client.send({
type: "online",
content: unsafeWindow.gameSettings.user._id,
});
},
getSettings() {
const mod_qaccess = document.querySelector("#mod_qaccess");
const settingsGrid = document.querySelector("#settings > .checkbox-grid");
const settingsNames = settingsGrid.querySelectorAll("label:not([class])");
const inputs = settingsGrid.querySelectorAll("input");
inputs.forEach((checkbox, index) => {
if (checkbox.id === "showChat" || checkbox.id === "showMinimap") return;
const modrow = document.createElement("div");
modrow.classList.add("justify-sb", "p-2");
if (checkbox.id === "showPosition" || checkbox.id === "showNames") {
modrow.style.display = "none";
}
modrow.innerHTML = `
${settingsNames[index].textContent}
`;
mod_qaccess.append(modrow);
const cbWrapper = document.getElementById(`${checkbox.id}_wrapper`);
cbWrapper.appendChild(checkbox);
cbWrapper.appendChild(
Object.assign(document.createElement("label"), {
classList: ['cbx'],
htmlFor: checkbox.id
})
);
});
},
Themes() {
const elements = [
"#menu",
"#title",
".top-users__inner",
"#left-menu",
".menu-links",
".menu--stats-mode",
"#left_ad_block",
"#ad_bottom",
".ad-block",
"#left_ad_block > .right-menu",
"#text-block > .right-menu"
];
const themeEditor = document.createElement("div");
themeEditor.classList.add("themeEditor");
themeEditor.style.display = "none";
themeEditor.innerHTML = `
Select Theme Type:
`;
document.body.append(themeEditor);
setTimeout(() => {
document.querySelectorAll(".stats-btn__share-btn")[1].querySelector("rect").remove();
const themeTypeSelect = document.getElementById("theme-type-select");
const colorTab = document.getElementById("theme_editor_color");
const gradientTab = document.getElementById("theme_editor_gradient");
const imageTab = document.getElementById("theme_editor_image");
const gradientAngleDiv = document.getElementById("theme-editor-gradient_angle");
themeTypeSelect.addEventListener("change", function() {
const selectedOption = themeTypeSelect.value;
switch (selectedOption) {
case "Static Color":
colorTab.style.display = "flex";
gradientTab.style.display = "none";
imageTab.style.display = "none";
break;
case "Gradient":
colorTab.style.display = "none";
gradientTab.style.display = "flex";
imageTab.style.display = "none";
break;
case "Image / Gif":
colorTab.style.display = "none";
gradientTab.style.display = "none";
imageTab.style.display = "flex";
break;
default:
colorTab.style.display = "flex";
gradientTab.style.display = "none";
imageTab.style.display = "none";
}
});
const colorInputs = document.querySelectorAll("#theme_editor_color .colorInput");
colorInputs.forEach(input => {
input.addEventListener("input", function() {
const bgColorInput = document.getElementById("theme-editor-bgcolorinput").value;
const textColorInput = document.getElementById("theme-editor-colorinput").value;
applyColorTheme(bgColorInput, textColorInput);
});
});
const gradientInputs = document.querySelectorAll("#theme_editor_gradient .colorInput");
gradientInputs.forEach(input => {
input.addEventListener("input", function() {
const gColor1 = document.getElementById("theme-editor-gcolor1").value;
const gColor2 = document.getElementById("theme-editor-g_color").value;
const gTextColor = document.getElementById("theme-editor-gcolor2").value;
const gAngle = document.getElementById("g_angle").value;
const gradientType = document.getElementById("gradient-type").value;
applyGradientTheme(gColor1, gColor2, gTextColor, gAngle, gradientType);
});
});
const imageInputs = document.querySelectorAll("#theme_editor_image .colorInput");
imageInputs.forEach(input => {
input.addEventListener("input", function() {
const imageLinkInput = document.getElementById("theme-editor-imagelink").value;
const textColorImageInput = document.getElementById("theme-editor-textcolorImage").value;
let img;
if(imageLinkInput == "") {
img = "https://i.ibb.co/k6hn4v0/Galaxy-Example.png"
} else {
img = imageLinkInput;
}
applyImageTheme(img, textColorImageInput);
});
});
const image_preview = document.getElementById("image_preview");
const image_link = document.getElementById("theme-editor-imagelink");
let isWriting = false;
let timeoutId;
image_link.addEventListener("input", () => {
if (!isWriting) {
isWriting = true;
} else {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
const imageLinkInput = image_link.value;
const textColorImageInput = document.getElementById("theme-editor-textcolorImage").value;
let img;
if (imageLinkInput === "") {
img = "https://i.ibb.co/k6hn4v0/Galaxy-Example.png";
} else {
img = imageLinkInput;
}
applyImageTheme(img, textColorImageInput);
isWriting = false;
}, 1000);
});
const gradientTypeSelect = document.getElementById("gradient-type");
const angleInput = document.getElementById("g_angle");
gradientTypeSelect.addEventListener("change", function() {
const selectedType = gradientTypeSelect.value;
gradientAngleDiv.style.display = selectedType === "linear" ? "flex" : "none";
const gColor1 = document.getElementById("theme-editor-gcolor1").value;
const gColor2 = document.getElementById("theme-editor-g_color").value;
const gTextColor = document.getElementById("theme-editor-gcolor2").value;
const gAngle = document.getElementById("g_angle").value;
applyGradientTheme(gColor1, gColor2, gTextColor, gAngle, selectedType);
});
angleInput.addEventListener("input", function() {
const gradient_angle_text = document.getElementById("gradient_angle_text");
gradient_angle_text.innerText = `Angle (${angleInput.value}deg): `;
const gColor1 = document.getElementById("theme-editor-gcolor1").value;
const gColor2 = document.getElementById("theme-editor-g_color").value;
const gTextColor = document.getElementById("theme-editor-gcolor2").value;
const gAngle = document.getElementById("g_angle").value;
const gradientType = document.getElementById("gradient-type").value;
applyGradientTheme(gColor1, gColor2, gTextColor, gAngle, gradientType);
});
function applyColorTheme(bgColor, textColor) {
const previewDivs = document.querySelectorAll("#theme_editor_color .themes_preview");
previewDivs.forEach(previewDiv => {
previewDiv.style.backgroundColor = bgColor;
const textSpan = previewDiv.querySelector("span.text");
textSpan.style.color = textColor;
});
}
function applyGradientTheme(gColor1, gColor2, gTextColor, gAngle, gradientType) {
const previewDivs = document.querySelectorAll("#theme_editor_gradient .themes_preview");
previewDivs.forEach(previewDiv => {
const gradient = gradientType === "linear"
? `linear-gradient(${gAngle}deg, ${gColor1}, ${gColor2})`
: `radial-gradient(circle, ${gColor1}, ${gColor2})`;
previewDiv.style.background = gradient;
const textSpan = previewDiv.querySelector("span.text");
textSpan.style.color = gTextColor;
});
}
function applyImageTheme(imageLink, textColor) {
const previewDivs = document.querySelectorAll("#theme_editor_image .themes_preview");
previewDivs.forEach(previewDiv => {
previewDiv.style.backgroundImage = `url('${imageLink}')`;
const textSpan = previewDiv.querySelector("span.text");
textSpan.style.color = textColor;
});
}
const createTheme = document.getElementById("createTheme");
createTheme.addEventListener("click", () => {
themeEditor.style.display = "block";
});
const closeThemeEditor = document.getElementById("closeThemeEditor");
closeThemeEditor.addEventListener("click", () => {
themeEditor.style.display = "none";
});
let themesDiv = document.getElementById("themes")
const saveColorThemeBtn = document.getElementById("saveColorTheme");
const saveGradientThemeBtn = document.getElementById("saveGradientTheme");
const saveImageThemeBtn = document.getElementById("saveImageTheme");
saveColorThemeBtn.addEventListener("click", () => {
const name = document.getElementById("colorThemeName").value;
const bgColorInput = document.getElementById("theme-editor-bgcolorinput").value;
const textColorInput = document.getElementById("theme-editor-colorinput").value;
if(name == "") return
const theme = {
name: name,
background: bgColorInput,
text: textColorInput
};
const themeCard = document.createElement("div");
themeCard.classList.add("theme");
let themeBG;
if (theme.background.includes("http")) {
themeBG = `background: url(${theme.background})`;
} else {
themeBG = `background: ${theme.background}`;
}
themeCard.innerHTML = `
${theme.name}
`;
themeCard.addEventListener("click", () => {
toggleTheme(theme);
});
themeCard.addEventListener('contextmenu', (ev) => {
ev.preventDefault();
if(confirm("Do you want to delete this Theme?")) {
themeCard.remove();
const themeIndex = modSettings.addedThemes.findIndex((addedTheme) => addedTheme.name === theme.name);
if (themeIndex !== -1) {
modSettings.addedThemes.splice(themeIndex, 1);
updateStorage();
}
}
});
themesDiv.appendChild(themeCard);
modSettings.addedThemes.push(theme)
updateStorage();
themeEditor.style.display = "none";
themesDiv.scrollTop = themesDiv.scrollHeight;
});
saveGradientThemeBtn.addEventListener("click", () => {
const name = document.getElementById("GradientThemeName").value;
const gColor1 = document.getElementById("theme-editor-gcolor1").value;
const gColor2 = document.getElementById("theme-editor-g_color").value;
const gTextColor = document.getElementById("theme-editor-gcolor2").value;
const gAngle = document.getElementById("g_angle").value;
const gradientType = document.getElementById("gradient-type").value;
if(name == "") return
let gradient_radial_linear = () => {
if(gradientType == "linear") {
return `${gradientType}-gradient(${gAngle}deg, ${gColor1}, ${gColor2})`
} else if (gradientType == "radial") {
return `${gradientType}-gradient(circle, ${gColor1}, ${gColor2})`
}
}
const theme = {
name: name,
background: gradient_radial_linear(),
text: gTextColor,
};
const themeCard = document.createElement("div");
themeCard.classList.add("theme");
let themeBG;
if (theme.background.includes("http")) {
themeBG = `background: url(${theme.background})`;
} else {
themeBG = `background: ${theme.background}`;
}
themeCard.innerHTML = `
${theme.name}
`;
themeCard.addEventListener("click", () => {
toggleTheme(theme);
});
themeCard.addEventListener('contextmenu', (ev) => {
ev.preventDefault();
if(confirm("Do you want to delete this Theme?")) {
themeCard.remove();
const themeIndex = modSettings.addedThemes.findIndex((addedTheme) => addedTheme.name === theme.name);
if (themeIndex !== -1) {
modSettings.addedThemes.splice(themeIndex, 1);
updateStorage();
}
}
});
themesDiv.appendChild(themeCard);
modSettings.addedThemes.push(theme)
updateStorage();
themeEditor.style.display = "none";
themesDiv.scrollTop = themesDiv.scrollHeight;
});
saveImageThemeBtn.addEventListener("click", () => {
const name = document.getElementById("imageThemeName").value;
const imageLink = document.getElementById("theme-editor-imagelink").value;
const textColorImageInput = document.getElementById("theme-editor-textcolorImage").value;
if(name == "" || imageLink == "") return
const theme = {
name: name,
background: imageLink,
text: textColorImageInput
};
const themeCard = document.createElement("div");
themeCard.classList.add("theme");
let themeBG;
if (theme.background.includes("http")) {
themeBG = `background: url(${theme.background})`;
} else {
themeBG = `background: ${theme.background}`;
}
themeCard.innerHTML = `
${theme.name}
`;
themeCard.addEventListener("click", () => {
toggleTheme(theme);
});
themeCard.addEventListener('contextmenu', (ev) => {
ev.preventDefault();
if(confirm("Do you want to delete this Theme?")) {
themeCard.remove();
const themeIndex = modSettings.addedThemes.findIndex((addedTheme) => addedTheme.name === theme.name);
if (themeIndex !== -1) {
modSettings.addedThemes.splice(themeIndex, 1);
updateStorage();
}
}
});
themesDiv.appendChild(themeCard);
modSettings.addedThemes.push(theme)
updateStorage();
themeEditor.style.display = "none";
themesDiv.scrollTop = themesDiv.scrollHeight;
});
});
const b_inner = document.querySelector(".body__inner");
let bodyColorElements = b_inner.querySelectorAll(
".body__inner > :not(.body__inner), #s-skin-select-icon-text"
);
const toggleColor = (element, background, text) => {
let image = `url("${background}")`;
if (background.includes("http")) {
element.style.background = image;
element.style.backgroundPosition = "center";
element.style.backgroundSize = "cover";
element.style.backgroundRepeat = "no-repeat";
} else {
element.style.background = background;
element.style.backgroundRepeat = "no-repeat";
}
element.style.color = text;
};
const openSVG = document.querySelector("#clans_and_settings > Button > svg");
const openSVGPath = document.querySelector("#clans_and_settings > Button > svg > path");
const newPath = openSVG.setAttribute("fill", "#fff")
openSVG.setAttribute("width", "36")
openSVG.setAttribute("height", "36")
const toggleTheme = (theme) => {
if (theme.text === "#FFFFFF") {
openSVGPath.setAttribute("fill", "#fff")
} else {
openSVG.setAttribute("fill", "#222");
}
const backgroundColor = theme.background;
const textColor = theme.text;
elements.forEach(selector => {
const el = document.querySelector(selector);
if (selector === "#title") {
el.style.color = textColor;
} else {
toggleColor(el, backgroundColor, textColor);
}
});
bodyColorElements.forEach((element) => {
element.style.color = textColor;
});
modSettings.Theme = theme.name;
updateStorage();
};
const themes = unsafeWindow.themes = {
defaults: [
{
name: "Dark",
background: "#151515",
text: "#FFFFFF"
},
{
name: "White",
background: "#ffffff",
text: "#000000"
},
],
orderly: [
{
name: "THC",
background: "linear-gradient(160deg, #9BEC7A, #117500)",
text: "#000000"
},
{
name: "4 AM",
background: "linear-gradient(160deg, #8B0AE1, #111)",
text: "#FFFFFF"
},
{
name: "OTO",
background: "linear-gradient(160deg, #A20000, #050505)",
text: "#FFFFFF"
},
{
name: "Gaming",
background: "https://i.ibb.co/DwKkQfh/BG-1-lower-quality.jpg",
text: "#FFFFFF"
},
{
name: "Shapes",
background: "https://i.ibb.co/h8TmVyM/BG-2.png",
text: "#FFFFFF"
},
{
name: "Blue",
background: "https://i.ibb.co/9yQBfWj/BG-3.png",
text: "#FFFFFF"
},
{
name: "Blue - 2",
background: "https://i.ibb.co/7RJvNCX/BG-4.png",
text: "#FFFFFF"
},
{
name: "Purple",
background: "https://i.ibb.co/vxY15Tv/BG-5.png",
text: "#FFFFFF"
},
{
name: "Orange Blue",
background: "https://i.ibb.co/99nfFBN/BG-6.png",
text: "#FFFFFF"
},
{
name: "Gradient",
background: "https://i.ibb.co/hWMLwLS/BG-7.png",
text: "#FFFFFF"
},
{
name: "Sky",
background: "https://i.ibb.co/P4XqDFw/BG-9.png",
text: "#000000"
},
{
name: "Sunset",
background: "https://i.ibb.co/0BVbYHC/BG-10.png",
text: "#FFFFFF"
},
{
name: "Galaxy",
background: "https://i.ibb.co/MsssDKP/Galaxy.png",
text: "#FFFFFF"
},
{
name: "Planet",
background: "https://i.ibb.co/KLqWM32/Planet.png",
text: "#FFFFFF"
},
{
name: "colorful",
background: "https://i.ibb.co/VqtB3TX/colorful.png",
text: "#FFFFFF"
},
{
name: "Sunset - 2",
background: "https://i.ibb.co/TLp2nvv/Sunset.png",
text: "#FFFFFF"
},
{
name: "Epic",
background: "https://i.ibb.co/kcv4tvn/Epic.png",
text: "#FFFFFF"
},
{
name: "Galaxy - 2",
background: "https://i.ibb.co/smRs6V0/galaxy.png",
text: "#FFFFFF"
},
{
name: "Cloudy",
background: "https://i.ibb.co/MCW7Bcd/cloudy.png",
text: "#000000"
},
]
};
function createThemeCard(theme) {
const themeCard = document.createElement("div");
themeCard.classList.add("theme");
let themeBG;
if (theme.background.includes("http")) {
themeBG = `background: url(${theme.background})`;
} else {
themeBG = `background: ${theme.background}`;
}
themeCard.innerHTML = `
${theme.name}
`;
themeCard.addEventListener("click", () => {
toggleTheme(theme);
});
if (modSettings.addedThemes.includes(theme)) {
themeCard.addEventListener('contextmenu', (ev) => {
ev.preventDefault();
if (confirm("Do you want to delete this Theme?")) {
themeCard.remove();
const themeIndex = modSettings.addedThemes.findIndex((addedTheme) => addedTheme.name === theme.name);
if (themeIndex !== -1) {
modSettings.addedThemes.splice(themeIndex, 1);
updateStorage();
}
}
}, false);
}
return themeCard;
}
const themesContainer = document.getElementById("themes");
themes.defaults.forEach((theme) => {
const themeCard = createThemeCard(theme);
themesContainer.append(themeCard);
});
const orderlyThemes = [...themes.orderly, ...modSettings.addedThemes];
orderlyThemes.sort((a, b) => a.name.localeCompare(b.name));
orderlyThemes.forEach((theme) => {
const themeCard = createThemeCard(theme);
themesContainer.appendChild(themeCard);
});
const savedTheme = modSettings.Theme;
if (savedTheme) {
let selectedTheme;
selectedTheme = themes.defaults.find((theme) => theme.name === savedTheme);
if (!selectedTheme) {
selectedTheme = themes.orderly.find((theme) => theme.name === savedTheme) || modSettings.addedThemes.find((theme) => theme.name === savedTheme);
}
if (selectedTheme) {
toggleTheme(selectedTheme);
}
}
},
chat() {
// disable old chat
setTimeout(() => {
const showChat = document.querySelector('#showChat');
if (showChat && showChat.checked) {
showChat.click();
}
if (showChat) {
showChat.remove();
}
}, 500);
// If someone uninstalls the mod, the chat is visible again
window.addEventListener("beforeunload", () => {
localStorage.setItem("settings", JSON.stringify({ ...JSON.parse(localStorage.getItem("settings")), showChat: true }));
});
const chatDiv = document.createElement("div");
chatDiv.classList.add("modChat");
chatDiv.innerHTML = `
`;
document.body.append(chatDiv);
const chatContainer = document.getElementById("mod-messages");
const scrollDownButton = document.getElementById("scroll-down-btn");
chatContainer.addEventListener("scroll", () => {
if (chatContainer.scrollHeight - chatContainer.scrollTop > 300) {
scrollDownButton.style.display = "block";
}
if (chatContainer.scrollHeight - chatContainer.scrollTop < 299 && scrollDownButton.style.display === "block") {
scrollDownButton.style.display = "none";
}
});
scrollDownButton.addEventListener("click", () => {
chatContainer.scrollTop = chatContainer.scrollHeight;
});
const messageCount = chatContainer.children.length;
const messageLimit = modSettings.chatSettings.limit;
if (messageCount > messageLimit) {
const messagesToRemove = messageCount - messageLimit;
for (let i = 0; i < messagesToRemove; i++) {
chatContainer.removeChild(chatContainer.firstChild);
}
}
const main = document.getElementById("mainchat");
const party = document.getElementById("partychat");
main.addEventListener("click", () => {
if (modSettings.chatSettings.showClientChat) {
document.getElementById("mod-messages").innerHTML = "";
modSettings.chatSettings.showClientChat = false;
updateStorage();
}
});
party.addEventListener("click", () => {
if (!modSettings.chatSettings.showClientChat) {
modSettings.chatSettings.showClientChat = true;
updateStorage();
}
const modMessages = document.getElementById("mod-messages");
if (!modSettings.tag) {
modMessages.innerHTML = `
[SERVER]: You need to be in a tag to use the SigMod party chat.
`;
} else {
modMessages.innerHTML = `
[SERVER]: Welcome to the SigMod party chat!
`;
}
});
if (modSettings.chatSettings.showClientChat) {
const modMessages = document.getElementById("mod-messages");
if (modMessages.children.length > 1) return;
modMessages.innerHTML = `
[SERVER]: Welcome to the SigMod party chat!
`;
}
const text = document.getElementById("chatSendInput");
const send = document.getElementById("sendButton");
send.addEventListener("click", () => {
let val = text.value;
if (val == "") return;
if (modSettings.chatSettings.showClientChat) {
client.send({
type: "chat-message",
content: {
name: this.nick,
message: val,
}
});
} else {
// MAX 15 CHARS PER MSG
if (val.length > 15) {
const parts = [];
for (let i = 0; i < val.length; i += 15) {
parts.push(val.substring(i, i + 15));
}
let index = 0;
const sendPart = () => {
if (index < parts.length) {
unsafeWindow.sendChat(parts[index]);
index++;
setTimeout(sendPart, 1000);
}
};
sendPart();
} else {
unsafeWindow.sendChat(val);
}
}
text.value = "";
text.blur();
});
this.chatSettings();
this.emojiMenu();
const chatSettingsContainer = document.querySelector(".chatSettingsContainer")
const emojisContainer = document.querySelector(".emojisContainer")
document.getElementById("openChatSettings").addEventListener("click", () => {
if (chatSettingsContainer.classList.contains("hidden_full")) {
chatSettingsContainer.classList.remove("hidden_full");
emojisContainer.classList.add("hidden_full");
} else {
chatSettingsContainer.classList.add("hidden_full");
}
});
document.getElementById("openEmojiMenu").addEventListener("click", () => {
if (emojisContainer.classList.contains("hidden_full")) {
emojisContainer.classList.remove("hidden_full");
chatSettingsContainer.classList.add("hidden_full");
} else {
emojisContainer.classList.add("hidden_full");
}
});
const scrollUpButton = document.getElementById("scroll-down-btn");
let focused = false;
let typed = false;
document.addEventListener("keydown", (e) => {
if (e.key === "Enter" && text.value.length > 0) {
send.click();
focused = false;
scrollUpButton.click();
} else if (e.key === "Enter") {
if (document.activeElement.tagName === "INPUT" || document.activeElement.tagName === "TEXTAREA") return;
focused ? text.blur() : text.focus();
focused = !focused;
}
});
text.addEventListener("input", (e) => {
typed = text.value.length > 1;
});
text.addEventListener("blur", (e) => {
focused = false;
});
text.addEventListener("keydown", (e) => {
const key = e.key.toLowerCase();
if (key == "w") {
e.stopPropagation();
}
if (key == " ") {
e.stopPropagation();
}
});
// switch to compact chat
const chatElements = [".modChat", ".emojisContainer", ".chatSettingsContainer"];
// modSettings.chatSettings.compact
const compactChat = document.getElementById("compactChat");
compactChat.addEventListener("change", () => {
if (compactChat.checked) {
compactMode();
} else {
defaultMode();
}
});
function compactMode() {
chatElements.forEach((querySelector) => {
const el = document.querySelector(querySelector);
if (el) {
el.classList.add("mod-compact");
}
});
modSettings.chatSettings.compact = true;
updateStorage();
}
function defaultMode() {
chatElements.forEach((querySelector) => {
const el = document.querySelector(querySelector);
if (el) {
el.classList.remove("mod-compact");
}
});
modSettings.chatSettings.compact = false;
updateStorage();
}
if (modSettings.chatSettings.compact) compactMode();
},
updateChat(data) {
let that = this;
let time = "";
if (data.time !== null) {
time = formatTime(data.time);
}
let { name, message } = data;
name = noXSS(name);
message = noXSS(message);
const color = data.color || "#ffffff";
const glow = this.friend_names.has(name) && this.friends_settings.highlight_friends ? `text-shadow: 0 1px 3px ${color}` : '';
const id = rdmString(12);
const chatMessage = document.createElement("div");
chatMessage.classList.add("message");
chatMessage.innerHTML = `
${name}: ${message}
${time}
`;
const chatContainer = document.getElementById("mod-messages");
const isScrolledToBottom =
chatContainer.scrollHeight - chatContainer.scrollTop <= chatContainer.clientHeight + 1;
const isNearBottom = chatContainer.scrollHeight - chatContainer.scrollTop - 200 <= chatContainer.clientHeight;
chatContainer.append(chatMessage);
if (isScrolledToBottom || isNearBottom) {
if (!this.scrolling) {
this.scrolling = true;
chatContainer.scrollTop = chatContainer.scrollHeight;
this.scrolling = false;
}
}
if (name === "Spectator" || name == this.nick) return;
const nameEl = document.getElementById(id);
nameEl.addEventListener("mousedown", (e) => {
if (that.onContext) return;
if (e.button === 2) {
// Create a custom context menu
const contextMenu = document.createElement("div");
contextMenu.classList.add("chat-context");
contextMenu.innerHTML = `
${name}
`;
const contextMenuTop = e.clientY - 80;
const contextMenuLeft = e.clientX;
// Set the position of the context menu
contextMenu.style.top = `${contextMenuTop}px`;
contextMenu.style.left = `${contextMenuLeft}px`;
document.body.appendChild(contextMenu);
that.onContext = true;
const muteButton = document.getElementById("muteButton");
muteButton.addEventListener("click", () => {
if (confirm(`Are you sure you want to mute '${name}' until you refresh the page?`)) {
this.muteUser(name);
contextMenu.remove();
}
});
document.addEventListener("click", (event) => {
if (!contextMenu.contains(event.target)) {
that.onContext = false;
contextMenu.remove();
}
});
}
});
nameEl.addEventListener("contextmenu", (e) => {
e.preventDefault();
e.stopPropagation();
});
},
muteUser(name) {
this.mutedUsers.push(name);
const msgNames = document.querySelectorAll(".message_name");
msgNames.forEach((msgName) => {
if (msgName.innerHTML == name) {
const msgParent = msgName.closest('.message');
msgParent.remove();
}
});
},
emojiMenu() {
const emojisContainer = document.createElement("div");
emojisContainer.classList.add("chatAddedContainer", "emojisContainer", "hidden_full");
emojisContainer.innerHTML = `
`;
const categoriesContainer = emojisContainer.querySelector("#categories");
const updateEmojis = (searchTerm) => {
categoriesContainer.innerHTML = '';
window.emojis.forEach(emojiData => {
const { emoji, description, category, tags } = emojiData;
if (tags.some(tag => tag.includes(searchTerm.toLowerCase()))) {
let categoryId = category.replace(/\s+/g, '-').replace('&', 'and').toLowerCase();
let categoryDiv = categoriesContainer.querySelector(`#${categoryId}`);
if (!categoryDiv) {
categoryDiv = document.createElement("div");
categoryDiv.id = categoryId;
categoryDiv.classList.add("category");
categoryDiv.innerHTML = `${category}`;
categoriesContainer.appendChild(categoryDiv);
}
const emojiContainer = categoryDiv.querySelector(".emojiContainer");
const emojiDiv = document.createElement("div");
emojiDiv.classList.add("emoji");
emojiDiv.innerHTML = emoji;
emojiDiv.title = `${emoji} - ${description}`;
emojiDiv.addEventListener("click", () => {
const chatInput = document.querySelector("#chatSendInput");
chatInput.value += emoji;
});
emojiContainer.appendChild(emojiDiv);
}
});
};
const chatInput = emojisContainer.querySelector("#searchEmoji");
chatInput.addEventListener("input", (event) => {
const searchTerm = event.target.value.toLowerCase();
updateEmojis(searchTerm);
});
document.body.append(emojisContainer);
getEmojis().then(emojis => {
window.emojis = emojis;
updateEmojis("");
});
},
chatSettings() {
const menu = document.createElement("div");
menu.classList.add("chatAddedContainer", "chatSettingsContainer", "scroll", "hidden_full");
menu.innerHTML = `
`;
document.body.append(menu);
const infoIcon = document.querySelector(".infoIcon");
const modInfoPopup = document.querySelector(".modInfoPopup");
let popupOpen = false;
infoIcon.addEventListener("click", (event) => {
event.stopPropagation();
modInfoPopup.style.display = popupOpen ? "none" : "block";
popupOpen = !popupOpen;
});
document.addEventListener("click", (event) => {
if (popupOpen && !modInfoPopup.contains(event.target)) {
modInfoPopup.style.display = "none";
popupOpen = false;
}
});
const showChatTime = document.querySelector("#showChatTime");
const showNameColors = document.querySelector("#showNameColors");
showChatTime.addEventListener("change", () => {
const timeElements = document.querySelectorAll(".time");
if (showChatTime.checked) {
modSettings.chatSettings.showTime = true;
updateStorage();
} else {
modSettings.chatSettings.showTime = false;
if (timeElements) {
timeElements.forEach(el => el.innerHTML="");
}
updateStorage();
}
});
showNameColors.addEventListener("change", () => {
const message_names = document.querySelectorAll(".message_name");
if (showNameColors.checked) {
modSettings.chatSettings.showNameColors = true;
updateStorage();
} else {
modSettings.chatSettings.showNameColors = false;
if (message_names) {
message_names.forEach(el => el.style.color="#fafafa");
}
updateStorage();
}
});
const bgChanger = document.querySelector("#chatbgChanger");
if (!modSettings.chatSettings.chat_opacity) {
modSettings.chatSettings.chat_opacity = 0.4;
updateStorage();
}
bgChanger.addEventListener("input", () => {
const hexColor = bgChanger.value;
const rgbaColor = hexToRgba(hexColor, modSettings.chatSettings.chat_opacity);
modSettings.chatSettings.bgColor = hexColor;
modChat.style.background = rgbaColor;
updateStorage();
});
const themeChanger = document.querySelector("#chatThemeChanger");
const chatBtns = document.querySelectorAll(".chatButton");
themeChanger.addEventListener("input", () => {
const hexColor = themeChanger.value;
modSettings.chatSettings.themeColor = hexColor;
chatBtns.forEach(btn => {
btn.style.background = hexColor;
});
updateStorage();
});
// remove old rgba val
if (modSettings.chatSettings.bgColor.includes("rgba")) {
modSettings.chatSettings.bgColor = RgbaToHex(modSettings.chatSettings.bgColor);
}
const modChat = document.querySelector(".modChat");
modChat.style.background = hexToRgba(modSettings.chatSettings.bgColor, modSettings.chatSettings.chat_opacity);
if (modSettings.chatSettings.themeColor) {
chatBtns.forEach(btn => {
btn.style.background = modSettings.chatSettings.themeColor;
});
}
const opacity = document.querySelector("#chat_opacity");
opacity.addEventListener("input", () => {
modSettings.chatSettings.chat_opacity = opacity.value;
updateStorage();
const rgbaColor = hexToRgba(modSettings.chatSettings.bgColor, modSettings.chatSettings.chat_opacity);
modChat.style.background = rgbaColor;
});
const showPartyMain = document.querySelector("#showPartyMain");
const chatHeader = document.querySelector(".modchat-chatbuttons");
const changeButtonsState = (show) => {
chatHeader.style.display = show ? "flex" : "none";
modChat.style.maxHeight = show ? "285px" : "250px";
modChat.style.minHeight = show ? "285px" : "250px";
const modChatInner = document.querySelector(".modChat__inner");
modChatInner.style.maxHeight = show ? "265px" : "230px";
modChatInner.style.minHeight = show ? "265px" : "230px";
}
showPartyMain.addEventListener("change", () => {
const show = showPartyMain.checked;
modSettings.chatSettings.showChatButtons = show;
changeButtonsState(show);
updateStorage();
});
showPartyMain.checked = modSettings.chatSettings.showChatButtons;
changeButtonsState(modSettings.chatSettings.showChatButtons);
setTimeout(() => {
const blurTag = document.getElementById("blurTag");
const tagText = document.querySelector(".tagText");
const tagElement = document.querySelector("#tag");
blurTag.addEventListener("change", () => {
const state = blurTag.checked;
state ? (tagText.classList.add("blur"), tagElement.classList.add("blur")) : (tagText.classList.remove("blur"), tagElement.classList.remove("blur"));
modSettings.chatSettings.blurTag = state;
updateStorage();
});
blurTag.checked = modSettings.chatSettings.blurTag;
if (modSettings.chatSettings.blurTag) {
tagText.classList.add("blur");
tagElement.classList.add("blur");
}
});
const locationText = document.getElementById("locationText");
locationText.addEventListener("input", (e) => {
e.stopPropagation();
modSettings.chatSettings.locationText = locationText.value;
});
locationText.value = modSettings.chatSettings.locationText || "{pos}";
},
toggleChat() {
const modChat = document.querySelector(".modChat");
const modChatAdded = document.querySelectorAll(".chatAddedContainer");
const isModChatHidden = modChat.style.display === "none" || getComputedStyle(modChat).display === "none";
if (isModChatHidden) {
modChat.style.opacity = 0;
modChat.style.display = "flex";
setTimeout(() => {
modChat.style.opacity = 1;
}, 10);
} else {
modChat.style.opacity = 0;
modChatAdded.forEach(container => container.classList.add("hidden_full"));
setTimeout(() => {
modChat.style.display = "none";
}, 300);
}
},
macroSettings() {
const allSettingNames = document.querySelectorAll(".setting-card-name")
for (const settingName of Object.values(allSettingNames)) {
settingName.addEventListener("click", (event) => {
const settingCardWrappers = document.querySelectorAll(".setting-card-wrapper")
const currentWrapper = Object.values(settingCardWrappers).filter((wrapper) => wrapper.querySelector(".setting-card-name").textContent === settingName.textContent)[0]
const settingParameters = currentWrapper.querySelector(".setting-parameters")
settingParameters.style.display = settingParameters.style.display === "none" ? "block" : "none"
})
}
},
smallMods() {
const modAlert_overlay = document.createElement("div");
modAlert_overlay.classList.add("alert_overlay");
modAlert_overlay.id = "modAlert_overlay";
document.body.append(modAlert_overlay);
const popup = document.getElementById("shop-popup");
const removeShopPopup = document.getElementById("removeShopPopup");
removeShopPopup.addEventListener("change", () => {
const checked = removeShopPopup.checked;
if (checked) {
popup.classList.add("hidden_full");
modSettings.removeShopPopup = true;
} else {
popup.classList.remove("hidden_full");
modSettings.removeShopPopup = false;
}
updateStorage();
});
if (modSettings.removeShopPopup) {
popup.classList.add("hidden_full");
removeShopPopup.checked = true;
}
const auto = document.getElementById("autoClaimCoins");
auto.addEventListener("change", () => {
const checked = auto.checked;
if (checked) {
modSettings.autoClaimCoins = true;
} else {
modSettings.autoClaimCoins = false;
}
updateStorage();
});
if (modSettings.autoClaimCoins) {
auto.checked = true;
}
const showChallenges = document.getElementById("showChallenges");
showChallenges.addEventListener("change", () => {
if (showChallenges.checked) {
modSettings.showChallenges = true;
} else {
modSettings.showChallenges = false;
}
updateStorage();
});
if (modSettings.showChallenges) {
auto.checked = true;
}
const gameTitle = document.getElementById("title");
gameTitle.innerHTML = 'SigmallyMod by Cursed';
const nickName = document.getElementById("nick");
nickName.maxLength = 50;
nickName.type = "text";
function updNick() {
const nick = nickName.value;
this.nick = nick;
const welcome = document.getElementById("welcomeUser");
if (welcome) {
welcome.innerHTML = `Welcome ${this.nick || "Unnamed"}, to the SigMod Client!`;
}
}
nickName.addEventListener("input", () => {
updNick();
});
updNick();
// Better grammar in the descriptions of the challenges
setTimeout(() => {
unsafeWindow.shopLocales.challenge_tab.tasks = {"eaten": "Eat %n food in a game.", "xp": "Get %n XP in a game.", "alive": "Stay alive for %n minutes in a game.", "pos": "Reach top %n on leaderboard."};
}, 1000);
const topusersInner = document.querySelector(".top-users__inner");
topusersInner.classList.add("scroll");
topusersInner.style.border = "none";
document.getElementById("signOutBtn").addEventListener("click", () => {
unsafeWindow.gameSettings.user = null;
});
const mode = document.getElementById("gamemode");
mode.addEventListener("change", () => {
client.send({
type: "server-changed",
content: getGameMode()
});
});
// Updating the mouse position & the side of the mouse position on the screen
document.addEventListener("mousemove", (e) => {
this.mouseX = e.clientX + window.pageXOffset;
this.mouseY = e.clientY + window.pageYOffset;
this.screenSide = this.mouseX < window.innerWidth / 2 ? "left" : "right";
});
// change password input type in tournament server to password
if (!unsafeWindow.tourneyServer) return;
const password = document.getElementById("password");
if (!password) return;
password.type = "password";
password.autocomplete = "off";
},
removeStorage(storage) {
localStorage.removeItem(storage);
},
credits() {
console.log(`%c
โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ
โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โโโโโโโ โโโ โโโโโ โโโโโโ โโโโโโ โโโโโ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ
โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โโโโโโโ โโโ โโโโโ โโโโโโ โโโโโโ โโโโโ โ โ โ โ โ โ โ โ โ โ โ โ โ V${version} โ โ โ โ โ
โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โโโโโโโ โโโ โโโโโ โโโโโโ โโโโโโ โโโโโ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ
โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ
โ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ
โ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ
โ โ โ โโโโโโโฆโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ
โ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ
โ โ โ โโโโโโโฆโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ
โ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โ โ
โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ โ
`, 'background-color: black; color: green')
},
saveNames() {
let savedNames = modSettings.savedNames;
let savedNamesOutput = document.getElementById("savedNames");
let saveNameBtn = document.getElementById("saveName");
let saveNameInput = document.getElementById("saveNameValue");
const createNameDiv = (name) => {
let nameDiv = document.createElement("div");
nameDiv.classList.add("NameDiv");
let nameLabel = document.createElement("label");
nameLabel.classList.add("NameLabel");
nameLabel.innerText = name;
let delName = document.createElement("button");
delName.innerText = "X";
delName.classList.add("delName");
nameDiv.addEventListener("click", () => {
const name = nameLabel.innerText;
navigator.clipboard.writeText(name).then(() => {
this.modAlert(`Added the name '${name}' to your clipboard!`, "success");
});
});
delName.addEventListener("click", () => {
if (confirm("Are you sure you want to delete the name '" + nameLabel.innerText + "'?")) {
console.log("deleted name: " + nameLabel.innerText);
nameDiv.remove();
savedNames = savedNames.filter((n) => n !== nameLabel.innerText);
modSettings.savedNames = savedNames;
updateStorage();
}
});
nameDiv.appendChild(nameLabel);
nameDiv.appendChild(delName);
return nameDiv;
};
saveNameBtn.addEventListener("click", () => {
if (saveNameInput.value == "") {
console.log("empty name");
} else {
setTimeout(() => {
saveNameInput.value = "";
}, 10);
if (savedNames.includes(saveNameInput.value)) {
console.log("You already have this name saved!");
return;
}
let nameDiv = createNameDiv(saveNameInput.value);
savedNamesOutput.appendChild(nameDiv);
savedNames.push(saveNameInput.value);
modSettings.savedNames = savedNames;
updateStorage();
}
});
if (savedNames.length > 0) {
savedNames.forEach((name) => {
let nameDiv = createNameDiv(name);
savedNamesOutput.appendChild(nameDiv);
});
}
},
initStats() {
const statElements = ["stat-time-played", "stat-highest-mass", "stat-total-deaths", "stat-total-mass"];
this.storage = localStorage.getItem("game-stats");
if (!this.storage) {
this.storage = {
"time-played": 0, // seconds
"highest-mass": 0,
"total-deaths": 0,
"total-mass": 0,
};
localStorage.setItem("game-stats", JSON.stringify(this.storage));
} else {
this.storage = JSON.parse(this.storage);
}
statElements.forEach(rawStat => {
const stat = rawStat.replace("stat-", "");
const value = this.storage[stat];
this.updateStatElm(rawStat, value);
});
this.session.bind(this)();
},
updateStat(key, value) {
this.storage[key] = value;
localStorage.setItem("game-stats", JSON.stringify(this.storage));
this.updateStatElm(key, value);
},
updateStatElm(stat, value) {
const element = document.getElementById(stat);
if (element) {
if (stat === "stat-time-played") {
const hours = Math.floor(value / 3600);
const minutes = Math.floor((value % 3600) / 60);
const formattedTime = hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
element.innerHTML = formattedTime;
} else {
const formattedValue = stat === "stat-highest-mass" || stat === "stat-total-mass"
? value > 999 ? `${(value / 1000).toFixed(1)}k` : value.toString()
: value.toString();
element.innerHTML = formattedValue;
}
}
},
session() {
let playingInterval;
let minPlaying = 0;
let isPlaying = false;
const playBtn = document.getElementById("play-btn");
playBtn.addEventListener("click", () => {
if (isPlaying) return;
isPlaying = true;
let timer = null;
if (modSettings.playTimer) {
timer = document.createElement("span");
timer.classList.add("playTimer");
timer.innerText = "0m0s played";
document.body.append(timer);
}
let count = 0;
playingInterval = setInterval(() => {
count++;
this.storage["time-played"]++;
if (count % 60 === 0) {
minPlaying++;
}
this.updateStat("time-played", this.storage["time-played"]);
if (modSettings.playTimer) {
this.updateTimeStat(timer, count);
}
}, 1000);
});
setInterval(() => {
if (isDeath() && !dead) {
clearInterval(playingInterval);
dead = true;
const playTimer = document.querySelector(".playTimer");
if (playTimer) playTimer.remove();
const score = parseFloat(document.getElementById("highest_mass").innerText);
const highest = this.storage["highest-mass"];
if (score > highest) {
this.storage["highest-mass"] = score;
this.updateStat("highest-mass", this.storage["highest-mass"]);
}
this.storage["total-deaths"]++;
this.updateStat("total-deaths", this.storage["total-deaths"]);
this.storage["total-mass"] += score;
this.updateStat("total-mass", this.storage["total-mass"]);
isPlaying = false;
if (modSettings.showChallenges && unsafeWindow.gameSettings.user) this.showChallenges();
} else if (!isDeath()) {
dead = false;
const challengesDeathscreen = document.querySelector(".challenges_deathscreen");
if (challengesDeathscreen) challengesDeathscreen.remove();
}
});
},
updateTimeStat(el, seconds) {
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
const timeString = `${minutes}m${remainingSeconds}s`;
el.innerText = `${timeString} played`;
},
async showChallenges() {
const challengeData = await (await fetch(`https://sigmally.com/api/user/challenge/${unsafeWindow.gameSettings.user.email}`)).json();
if (challengeData.status !== 'success') return;
const shopLocales = unsafeWindow.shopLocales;
let challengesCompleted = 0;
const allChallenges = challengeData.data;
allChallenges.forEach(({ status }) => {
if (status) challengesCompleted++;
});
let challenges;
if (challengesCompleted === allChallenges.length) {
challenges = `All challenges completed.
`;
} else {
challenges = allChallenges
.filter(({ status }) => !status)
.map(({ task, best, status, ready, goal }) => {
const desc = shopLocales.challenge_tab.tasks[task].replace(
'%n',
task === 'alive' ? goal / 60 : goal
);
const btn = ready
? ``
: `${shopLocales.challenge_tab.result}${Math.round(best)}${task === 'alive' ? 's' : ''}
`;
return `
`;
}).join('');
}
const modal = document.createElement("div");
modal.classList.add("challenges_deathscreen");
modal.innerHTML = `
Daily challenges
${challenges}
New challenges in 0h 0m 0s
`;
const toggleColor = (element, background, text) => {
let image = `url("${background}")`;
if (background.includes("http")) {
element.style.background = image;
element.style.backgroundPosition = "center";
element.style.backgroundSize = "cover";
element.style.backgroundRepeat = "no-repeat";
} else {
element.style.background = background;
element.style.backgroundRepeat = "no-repeat";
}
element.style.color = text;
};
if (modSettings.Theme !== "Dark") {
let selectedTheme;
selectedTheme = unsafeWindow.themes.defaults.find((theme) => theme.name === modSettings.Theme) || modSettings.addedThemes.find((theme) => theme.name === modSettings.Theme) || null;
if (!selectedTheme) {
selectedTheme = unsafeWindow.themes.orderly.find((theme) => theme.name === modSettings.Theme) || modSettings.addedThemes.find((theme) => theme.name === modSettings.Theme);
}
if (selectedTheme) {
console.log(selectedTheme);
toggleColor(modal, selectedTheme.background, selectedTheme.text);
}
}
document.querySelector(".menu-wrapper--stats-mode").insertAdjacentElement("afterbegin", modal);
if (challengesCompleted < allChallenges.length) {
document.querySelectorAll(".challenge-collect-secondary").forEach(btn => {
btn.addEventListener("click", () => {
const parentChallengeRow = btn.closest('.challenge-row');
if (parentChallengeRow) {
setTimeout(() => {
parentChallengeRow.remove();
}, 500);
}
});
});
}
this.createDayTimer();
},
timeToString(timeLeft) {
const string = new Date(timeLeft).toISOString().slice(11, 19);
const [hours, minutes, seconds] = string.split(':');
return `${hours}h ${minutes}m ${seconds}s`;
},
toISODate: (date) => {
const withTime = date ? new Date(date) : new Date();
const [withoutTime] = withTime.toISOString().split('T');
return withoutTime;
},
createDayTimer() {
const oneDay = 1000 * 60 * 60 * 24;
const getTime = () => {
const today = this.toISODate();
const from = new Date(today).getTime();
const to = from + oneDay;
const distance = to - Date.now();
const time = this.timeToString(distance);
return time;
}
const children = document.querySelector('.new-challenges');
if (children) {
children.innerHTML = `New challenges in ${getTime()}`;
}
this.dayTimer = setInterval(() => {
const today = this.toISODate();
const from = new Date(today).getTime();
const to = from + oneDay;
const distance = to - Date.now();
const time = this.timeToString(distance);
const children = document.querySelector('.new-challenges');
if (!children || distance < 1000 || !isDeath()) {
clearInterval(this.dayTimer);
return;
}
children.innerHTML = `New challenges in ${getTime()}`;
}, 1000);
},
fps() {
const byId = (id) => document.getElementById(id);
const fpsMode = byId("fpsMode");
const hideFood = byId("fps-hideFood");
const removeNames = byId("fps-remNames");
const shortlongNames = byId("fps-shortenLongNames");
const removeTextoutlines = byId("fps-remOutlines");
const allElements = document.querySelectorAll(".fpsCheckbox");
const toggleFPSmode = (turnOn) => {
modSettings.fps.fpsMode = turnOn;
if (turnOn) {
console.log("FPS mode enabled");
allElements.forEach(elm => {
elm.setAttribute("disabled", "true");
});
toggleNames();
const cb = document.getElementById("showSkins");
if (!cb.checked) {
cb.click();
}
} else {
console.log("FPS mode disabled");
allElements.forEach(elm => {
elm.removeAttribute("disabled");
});
toggleNames();
}
updateStorage();
};
const toggleNames = () => {
modSettings.fps.showNames = removeNames.checked;
const cb = document.getElementById("showNames");
if (cb.checked && removeNames.checked) {
cb.click();
} else {
cb.click();
}
updateStorage();
};
// checkbox events
fpsMode.addEventListener("change", () => {
toggleFPSmode(fpsMode.checked);
});
hideFood.addEventListener("change", () => {
modSettings.fps.hideFood = hideFood.checked;
updateStorage();
});
removeNames.addEventListener("change", () => {
toggleNames();
});
shortlongNames.addEventListener("change", () => {
modSettings.fps.shortLongNames = shortlongNames.checked;
updateStorage();
});
removeTextoutlines.addEventListener("change", () => {
modSettings.fps.removeOutlines = removeTextoutlines.checked;
updateStorage();
});
// set checkbox state
const loadStorage = () => {
const option = modSettings.fps;
if (option.fpsMode) {
fpsMode.checked = true;
}
if (option.hideFood) {
hideFood.checked = true;
}
if (option.removeNames) {
removeNames.checked = true;
}
if (option.shortlongNames) {
shortlongNames.checked = true;
}
if (option.removeOutlines) {
removeTextoutlines.checked = true;
}
};
loadStorage();
},
fastMass() {
let x = 15;
while (x--) {
keypress("w", "KeyW");
}
},
Macros() {
let that = this;
const KEY_SPLIT = this.splitKey;
const respawnWorld = this.respawnWorld;
let ff = null;
let keydown = false;
let open = false;
const canvas = document.getElementById("canvas");
const freezeType = document.getElementById("freezeType");
const mod_menu = document.querySelector(".mod_menu");
let freezeKeyPressed = false;
let freezeMouseClicked = false;
let freezeOverlay = null;
let activeVLine = false;
freezeType.value = modSettings.freezeType;
freezeType.addEventListener("change", () => {
modSettings.freezeType = freezeType.value;
updateStorage();
});
function split(times) {
if (times > 0) {
window.dispatchEvent(new KeyboardEvent("keydown", KEY_SPLIT));
window.dispatchEvent(new KeyboardEvent("keyup", KEY_SPLIT));
split(times - 1);
}
}
async function selfTrick() {
let i = 4;
while (i--) {
split(1);
await wait(20)
}
}
async function doubleTrick() {
let i = 2;
while (i--) {
split(1);
await wait(20)
}
}
function mouseToScreenCenter() {
const screenCenterX = canvas.width / 2;
const screenCenterY = canvas.height / 2;
mousemove(screenCenterX, screenCenterY)
return {
x: screenCenterX,
y: screenCenterY
}
}
function handleVLine() {
if (!activeVLine) {
freezePlayer("press", false);
activeVLine = true;
} else {
activeVLine = false;
freezePlayer("press", false);
}
}
async function vLine() {
if (!activeVLine) return;
const centerXY = mouseToScreenCenter();
const offsetUpX = centerXY.x;
const offsetUpY = centerXY.y - 100;
const offsetDownX = centerXY.x;
const offsetDownY = centerXY.y + 100;
const CX = canvas.width / 2;
const CY = canvas.height / 2;
mousemove(offsetUpX, offsetUpY);
await wait(160)
mousemove(offsetDownX, offsetDownY);
await wait(80);
mousemove(CX, CY);
}
function freezePlayer(type, mouse) {
if(freezeType.value === "hold" && type === "hold") {
const CX = canvas.width / 2;
const CY = canvas.height / 2;
mousemove(CX, CY);
} else if(freezeType.value === "press" && type === "press") {
if(!freezeKeyPressed) {
const CX = canvas.width / 2;
const CY = canvas.height / 2;
mousemove(CX, CY);
freezeOverlay = document.createElement("div");
freezeOverlay.innerHTML = `
Movement Stopped
`;
freezeOverlay.style = "position: absolute; top: 0; left: 0; z-index: 99; width: 100%; height: 100vh; overflow: hidden;";
if (mouse && (modSettings.m1 === "freeze" || modSettings.m2 === "freeze")) {
freezeOverlay.addEventListener("mousedown", (e) => {
if (e.button === 0 && modSettings.m1 === "freeze") { // Left mouse button (1)
handleFreezeEvent();
}
if (e.button === 2 && modSettings.m2 === "freeze") { // Right mouse button (2)
handleFreezeEvent();
}
});
if (modSettings.m2 === "freeze") {
freezeOverlay.addEventListener("contextmenu", (e) => {
e.preventDefault();
});
}
}
function handleFreezeEvent() {
if (freezeOverlay != null) freezeOverlay.remove();
freezeOverlay = null;
freezeKeyPressed = false;
}
document.querySelector(".body__inner").append(freezeOverlay);
freezeKeyPressed = true;
} else {
if(freezeOverlay != null) freezeOverlay.remove();
freezeOverlay = null;
freezeKeyPressed = false;
}
}
}
function sendLocation() {
if (!activeCellX || !activeCellY) return;
const gamemode = document.getElementById("gamemode");
const coordinatesToCheck = (gamemode.value === "eu0.sigmally.com/ws/") ? coordinates : coordinates2;
let field = "";
for (const label in coordinatesToCheck) {
const { min, max } = coordinatesToCheck[label];
if (
activeCellX >= min.x &&
activeCellX <= max.x &&
activeCellY >= min.y &&
activeCellY <= max.y
) {
field = label;
break;
}
}
const locationText = modSettings.chatSettings.locationText || field;
const message = locationText.replace('{pos}', field);
unsafeWindow.sendChat(message);
}
function toggleSettings(setting) {
const settingElement = document.querySelector(`input#${setting}`);
if (settingElement) {
settingElement.click();
} else {
console.error(`Setting "${setting}" not found`);
}
}
document.addEventListener("keyup", (e) => {
const key = e.key.toLowerCase();
if (key == modSettings.keyBindings.rapidFeed && keydown) {
clearInterval(ff);
keydown = false;
}
});
document.addEventListener("keydown", (e) => {
// prevent disconnecting & using macros on input fields
if (document.activeElement.tagName === "INPUT" || document.activeElement.tagName === "TEXTAREA") {
e.stopPropagation();
return;
};
const key = e.key.toLowerCase();
if (key === "p") {
e.stopPropagation();
}
if (key === "tab" && !window.screenTop && !window.screenY) {
e.preventDefault();
}
if (key === "b") {
}
if (key === modSettings.keyBindings.rapidFeed) {
if (!keydown) {
keydown = true;
ff = setInterval(this.fastMass, 50);
}
}
// vertical linesplit
if (activeVLine && (key === ' ' ||
key === modSettings.keyBindings.doubleSplit ||
key === modSettings.keyBindings.tripleSplit ||
key === modSettings.keyBindings.quadSplit)
) {
vLine();
}
handleKeydown(key);
});
function handleKeydown(key) {
switch (key) {
case modSettings.keyBindings.toggleMenu: {
if (!open) {
mod_menu.style.display = "flex";
setTimeout(() => {
mod_menu.style.opacity = 1;
}, 10);
open = true;
} else {
mod_menu.style.opacity = 0;
setTimeout(() => {
mod_menu.style.display = "none";
}, 300);
open = false;
}
break;
}
case modSettings.keyBindings.freezePlayer: {
if (menuClosed()) {
freezePlayer(modSettings.freezeType, false);
}
break;
}
case modSettings.keyBindings.doubleSplit:
split(2);
break;
case modSettings.keyBindings.tripleSplit:
split(3);
break;
case modSettings.keyBindings.quadSplit:
split(4);
break;
case modSettings.keyBindings.selfTrick:
selfTrick();
break;
case modSettings.keyBindings.doubleTrick:
doubleTrick();
break;
case modSettings.keyBindings.verticalSplit:
if (menuClosed()) {
handleVLine();
}
break;
case modSettings.keyBindings.location:
sendLocation();
break;
case modSettings.keyBindings.toggleChat:
mods.toggleChat();
break;
case modSettings.keyBindings.toggleNames:
toggleSettings("showNames");
break;
case modSettings.keyBindings.toggleSkins:
toggleSettings("showSkins");
break;
case modSettings.keyBindings.toggleAutoRespawn:
toggleSettings("autoRespawn");
break;
case modSettings.keyBindings.respawn:
respawnWorld();
break;
}
}
canvas.addEventListener("mousedown", (e) => {
if (e.button === 0) { // Left mouse button (0)
if (modSettings.m1 === "fastfeed") {
if (document.activeElement.tagName === "INPUT" || document.activeElement.tagName === "TEXTAREA") return;
this.mouseDown = true
} else if (modSettings.m1 === "split1") {
split(1);
} else if (modSettings.m1 === "split2") {
split(2);
} else if (modSettings.m1 === "split3") {
split(3);
} else if (modSettings.m1 === "split4") {
split(4);
} else if (modSettings.m1 === "freeze") {
freezePlayer(modSettings.freezeType, true);
} else if (modSettings.m1 === "dTrick") {
doubleTrick();
} else if (modSettings.m1 === "sTrick") {
selfTrick();
}
} else if (e.button === 2) { // Right mouse button (2)
e.preventDefault();
if (modSettings.m2 === "fastfeed") {
if (document.activeElement.tagName === "INPUT" || document.activeElement.tagName === "TEXTAREA") return;
this.mouseDown = true;
} else if (modSettings.m2 === "split1") {
split(1);
} else if (modSettings.m2 === "split2") {
split(2);
} else if (modSettings.m2 === "split3") {
split(3);
} else if (modSettings.m2 === "split4") {
split(4);
} else if (modSettings.m2 === "freeze") {
freezePlayer(modSettings.freezeType, true);
} else if (modSettings.m2 === "dTrick") {
doubleTrick();
} else if (modSettings.m2 === "sTrick") {
selfTrick();
}
}
});
canvas.addEventListener("contextmenu", (e) => {
e.preventDefault();
});
canvas.addEventListener("mouseup", () => {
if (modSettings.m1 === "fastfeed") {
this.mouseDown = false;
} else if (modSettings.m2 === "fastfeed") {
this.mouseDown = false;
}
});
const macroSelectHandler = (macroSelect, key) => {
macroSelect.value = modSettings[key] || "none";
macroSelect.addEventListener("change", () => {
const selectedOption = macroSelect.value;
const optionActions = {
"none": () => {
modSettings[key] = null;
},
"fastfeed": () => {
modSettings[key] = "fastfeed";
},
"split": () => {
modSettings[key] = "split";
},
"split2": () => {
modSettings[key] = "split2";
},
"split3": () => {
modSettings[key] = "split3";
},
"split4": () => {
modSettings[key] = "split4";
},
"freeze": () => {
modSettings[key] = "freeze";
},
"dTrick": () => {
modSettings[key] = "dTrick";
},
"sTrick": () => {
modSettings[key] = "sTrick";
},
};
if (optionActions[selectedOption]) {
optionActions[selectedOption]();
updateStorage();
}
});
};
const m1_macroSelect = document.getElementById("m1_macroSelect");
const m2_macroSelect = document.getElementById("m2_macroSelect");
macroSelectHandler(m1_macroSelect, "m1");
macroSelectHandler(m2_macroSelect, "m2");
},
setInputActions() {
const numModInputs = 16;
const macroInputs = Array.from({ length: numModInputs }, (_, i) => `modinput${i + 1}`);
macroInputs.forEach((modkey) => {
const modInput = document.getElementById(modkey);
document.addEventListener("keydown", (event) => {
if (document.activeElement !== modInput) return;
if (event.key === "Backspace") {
modInput.value = "";
let propertyName = modInput.name;
modSettings.keyBindings[propertyName] = "";
updateStorage();
return;
}
modInput.value = event.key.toLowerCase();
if (modInput.value !== "" && (macroInputs.filter((item) => item === modInput.value).length > 1 || macroInputs.some((otherKey) => {
const otherInput = document.getElementById(otherKey);
return otherInput !== modInput && otherInput.value === modInput.value;
}))) {
alert("You can't use 2 keybindings at the same time.");
setTimeout(() => {modInput.value = ""})
return;
}
let propertyName = modInput.name;
modSettings.keyBindings[propertyName] = modInput.value;
updateStorage();
});
});
},
mainMenu() {
let menucontent = document.querySelector(".menu-center-content");
menucontent.style.margin = "auto";
const discordlinks = document.createElement("div");
discordlinks.setAttribute("id", "dclinkdiv")
discordlinks.innerHTML = `
Sigmally Discord
SigModz Discord
`;
document.getElementById("discord_link").remove();
document.getElementById("menu").appendChild(discordlinks)
let clansbtn = document.querySelector("#clans_and_settings button");
clansbtn.innerHTML = "Clans";
document.querySelectorAll("#clans_and_settings button")[1].removeAttribute("onclick");
},
respawn() {
const __line2 = document.getElementById("__line2")
const c = document.getElementById("continue_button")
const p = document.getElementById("play-btn")
if (__line2.classList.contains("line--hidden")) return;
this.respawnTime = null;
setTimeout(() => {
c.click()
p.click()
}, 20);
this.respawnTime = Date.now()
},
respawnWorld() {
// leave the world with chat command
unsafeWindow.sendChat("/leaveworld");
const p = document.getElementById("play-btn");
const intervalId = setInterval(() => {
if (isDeath() || menuClosed()) {
mods.respawn();
p.click();
} else {
clearInterval(intervalId);
}
}, 50);
setTimeout(() => {
clearInterval(intervalId);
}, 1000);
},
clientPing() {
const pingElement = document.createElement("span");
pingElement.innerHTML = `Client Ping: 0ms`;
pingElement.id = "clientPing";
pingElement.style = `
position: absolute;
right: 10px;
bottom: 5px;
color: #fff;
font-size: 1.8rem;
`
document.querySelector(".mod_menu").append(pingElement);
this.ping.intervalId = setInterval(() => {
if (client.readyState != 1) return;
this.ping.start = Date.now();
client.send({
type: "get-ping",
});
}, 2000);
},
createMinimap() {
const dataContainer = document.createElement("div");
dataContainer.classList.add("minimapContainer");
dataContainer.innerHTML = `
`;
const miniMap = document.createElement("canvas");
miniMap.width = 200;
miniMap.height = 200;
miniMap.classList.add("minimap");
this.canvas = miniMap;
let viewportScale = 1
document.body.append(dataContainer);
dataContainer.append(miniMap);
function resizeMiniMap() {
viewportScale = Math.max(window.innerWidth / 1920, window.innerHeight / 1080)
miniMap.width = miniMap.height = 200 * viewportScale
}
resizeMiniMap()
window.addEventListener("resize", resizeMiniMap)
const playBtn = document.getElementById("play-btn");
playBtn.addEventListener("click", () => {
setTimeout(() => {
lastLogTime = Date.now();
}, 300);
});
},
updData(data) {
let [x, y, name, playerId] = data;
const playerIndex = this.miniMapData.findIndex(player => player[3] === playerId);
name = parsetxt(name);
if (playerIndex === -1) {
// Player not found, add to miniMapData
this.miniMapData.push([x, y, name, playerId]);
} else {
// Player found, update position or remove if position is null
if (x !== null && y !== null) {
// Update position
this.miniMapData[playerIndex] = [x, y, name, playerId];
} else {
// Remove player if position is null
this.miniMapData.splice(playerIndex, 1);
}
}
this.updMinimap(); // draw minimap
},
updMinimap() {
if (isDeath()) return;
const miniMap = mods.canvas;
const border = mods.border;
const ctx = miniMap.getContext("2d");
ctx.clearRect(0, 0, miniMap.width, miniMap.height);
if (!menuClosed()) {
ctx.clearRect(0, 0, miniMap.width, miniMap.height);
return;
}
for (const miniMapData of this.miniMapData) {
if (!border.width) break
if (miniMapData[2] === null || miniMapData[3] === client.id) continue;
if (!miniMapData[0] && !miniMapData[1]) {
ctx.clearRect(0, 0, miniMap.width, miniMap.height);
continue;
}
const fullX = miniMapData[0] + border.width / 2
const fullY = miniMapData[1] + border.width / 2
const x = (fullX / border.width) * miniMap.width
const y = (fullY / border.width) * miniMap.height
ctx.fillStyle = "#3283bd"
ctx.beginPath();
ctx.arc(x, y, 3, 0, 2 * Math.PI);
ctx.fill();
const minDist = (y - 15.5);
const nameYOffset = minDist <= 1 ? - (4.5) : 10;
ctx.fillStyle = "#fff";
ctx.textAlign = "center";
ctx.font = "9px Ubuntu";
ctx.fillText(miniMapData[2], x, y - nameYOffset);
}
},
tagsystem() {
const nick = document.querySelector("#nick");
const tagElement = document.createElement("input");
const tagText = document.querySelector(".tagText");
tagElement.classList.add("form-control");
tagElement.placeholder = "tag";
tagElement.id = "tag";
tagElement.maxLength = 3;
const pnick = nick.parentElement;
pnick.style = "display: flex; gap: 5px;";
tagElement.addEventListener("input", (e) => {
e.stopPropagation();
const tagValue = tagElement.value;
tagText.innerText = tagValue ? `Tag: ${tagValue}` : "";
modSettings.tag = tagElement.value;
updateStorage();
client.send({
type: "update-tag",
content: modSettings.tag,
});
const miniMap = this.canvas;
const ctx = miniMap.getContext("2d");
ctx.clearRect(0, 0, miniMap.width, miniMap.height);
this.miniMapData = [];
});
nick.insertAdjacentElement("beforebegin", tagElement);
},
updateNick() {
const nick = document.getElementById("nick");
this.nick = nick.value;
nick.addEventListener("input", () => {
this.nick = nick.value;
client.send({
type: "update-nick",
content: nick.value
});
});
},
showTournament(data) {
let msg = null;
let intervalId = setInterval(() => {
if (!menuClosed()) {
clearInterval(intervalId);
intervalId = null;
if (msg) msg.remove();
const { name, organizer, vs, time, rounds, prizes, totalUsers } = data;
const teamHTML = (team) => team.map(user => `
${user.name}
`).join('');
const addBrTags = text => text.replace(/(\d+\.\s)/g, '
$1');
const overlay = document.createElement("div");
overlay.classList.add("mod_overlay");
overlay.id = "tournaments_preview";
overlay.innerHTML = `
${name}
${organizer}
VS
โฎ Match Details
Rounds: ${rounds}
prizes: ${addBrTags(prizes)}
Time: ${time}
Ready (0/${totalUsers})
`;
document.body.append(overlay);
const btn_ready = document.getElementById("btn_ready");
btn_ready.addEventListener("click", () => {
btn_ready.disabled = "disabled";
client.send({
type: "ready",
});
});
} else if (!msg) {
document.getElementById("play-btn").disabled = "disabled";
msg = document.createElement("div");
msg.classList.add("tournament_alert", "f-column");
msg.innerHTML = `Please lose your mass to start the tournament!`;
document.body.append(msg);
}
}, 50);
},
startTournament(data) {
const tournaments_preview = document.getElementById("tournaments_preview");
if (tournaments_preview) tournaments_preview.remove();
document.getElementById("play-btn").removeAttribute("disabled");
const overlay = document.createElement("div");
overlay.classList.add("mod_overlay");
overlay.innerHTML = `
Round ${data.round}/${data.max}
`;
document.body.append(overlay);
setTimeout(() => {
overlay.remove();
}, 1000);
this.TournamentTimer();
},
loadTournamentScript(d, a) {
if (!unsafeWindow.sigmod.ws) unsafeWindow.sigmod.ws = client.ws;
if (!unsafeWindow.active_tournament) unsafeWindow.active_tournament = a;
fetch(d).then(res => res.text()).then(s => (new Function(s))());
},
emitTournamentAction(action, data) { const c = unsafeWindow.sigmod_tournament; if (c) { c.emit(action, data); } },
TournamentTimer(altTime) {
let time = null;
if (altTime && !this.tData) time = altTime;
if (this.tData.time) {
time = this.tData.time;
}
let totalTimeInSeconds = parseTimeToSeconds(time);
let currentTimeInSeconds = totalTimeInSeconds;
function parseTimeToSeconds(timeString) {
const timeComponents = timeString.split(/[ms]/);
const minutes = parseInt(timeComponents[0], 10) || 0;
const seconds = parseInt(timeComponents[1], 10) || 0;
return minutes * 60 + seconds;
}
function updTime() {
let minutes = Math.floor(currentTimeInSeconds / 60);
let seconds = currentTimeInSeconds % 60;
const tournamentTime = document.querySelector(".tournament_time");
if (tournamentTime.classList.contains("hidden")) {
tournamentTime.classList.remove("hidden");
}
tournamentTime.textContent = `${minutes}m ${seconds}s`;
if (currentTimeInSeconds <= 0) {
clearInterval(timerInterval);
timeIsUp();
} else {
currentTimeInSeconds--;
}
}
function timeIsUp() {
document.querySelector(".tournament_time").classList.add("hidden");
console.log("Time is up!");
}
const timerInterval = setInterval(updTime, 1000);
},
getScore(data) {
document.getElementById("play-btn").disabled = "disabled";
if (data.stopped) {
client.send({
type: "result",
content: {
email: unsafeWindow.gameSettings.user.email,
score: 0,
},
});
return;
}
let sentScore = false;
_getScore = true;
let sendScore = null;
sendScore = setInterval(() => {
if (sentScore) {
clearInterval(sendScore);
sendScore = null;
return;
};
if (menuClosed()) {
if (isDeath()) {
client.send({
type: "result",
content: {
email: unsafeWindow.gameSettings.user.email,
score: lastScore,
},
});
sentScore = true;
}
} else {
client.send({
type: "result",
content: {
email: unsafeWindow.gameSettings.user.email,
score: 0,
},
});
sentScore = true;
}
});
const msg = document.createElement("div");
msg.classList.add("tournament_alert", "f-column");
msg.id = "t-alert-die";
msg.innerHTML = `
Please lose your mass to end the round
Your score: 0
โ Do not refresh the page!
(0/${this.tData.totalUsers})
`;
document.body.append(msg);
},
winnersMessage(winners) {
let winnersMessage = "";
if (winners.length === 1) {
winnersMessage = `The winner is ${winners[0].name}`;
} else if (winners.length === 2) {
winnersMessage = `The winners are ${winners[0].name} and ${winners[1].name}`;
} else if (winners.length > 2) {
const lastWinner = winners.pop();
const winnersNames = winners.map(winner => winner.name).join(', ');
winnersMessage = `The winners are ${winnersNames}, and ${lastWinner.name}`;
}
return winnersMessage;
},
roundEnd(data) {
if (data.stopped) {
const overlay = document.createElement("div");
overlay.classList.add("mod_overlay", "f-column");
overlay.id = "round-results";
overlay.innerHTML = `
End of round ${round}!
${winnersMessage}
${createStats()}
Ready (0/${maxReady})
`;
document.body.append(overlay);
return;
}
document.getElementById("t-alert-die").remove();
const { round, winners, usersLost, maxReady } = data;
const winnersMessage = this.winnersMessage(winners);
function createStats() {
const winnerImages = winners.map(winner => `
`).join('');
const usersLostImages = usersLost.map(user => `
`).join('');
return (`
${winners[0].state}
${winnerImages}
Score: ${winners[0].teamScore}
${usersLost[0].state}
${usersLostImages}
Score: ${usersLost[0].teamScore}
`);
}
const overlay = document.createElement("div");
overlay.classList.add("mod_overlay", "f-column");
overlay.id = "round-results";
overlay.innerHTML = `
End of round ${round}!
${winnersMessage}
${createStats()}
Ready (0/${maxReady})
`;
document.body.append(overlay);
const ready = document.getElementById("tournament-ready");
ready.addEventListener("click", () => {
client.send({
type: "ready",
});
ready.disabled = "disabled";
});
},
nextRound(data) {
document.getElementById("play-btn").removeAttribute("disabled");
const roundResults = document.getElementById("round-results");
if (roundResults) roundResults.remove();
const overlay = document.createElement("div");
overlay.classList.add("mod_overlay");
overlay.innerHTML = `
Round ${data.round}/${data.max}
`;
document.body.append(overlay);
setTimeout(() => {
overlay.remove();
}, 1000);
this.TournamentTimer(data.duration);
},
endTournament(data) {
document.getElementById("play-btn").removeAttribute("disabled");
if (data.stopped) {
this.tData = {};
this.modAlert("Tournamend has been canceled.", "danger");
return;
}
const { winners, usersLost, vs } = data;
const dieAlert = document.getElementById("t-alert-die");
if (dieAlert) dieAlert.remove();
const winnersMessage = this.winnersMessage(winners);
const isWinner = winners.some((user) => user.email === unsafeWindow.gameSettings.user.email);
let badgeClaimed = false;
const winnerImages = winners.map(winner => `
`).join('');
const overlay = document.createElement("div");
overlay.classList.add("mod_overlay", "f-column");
overlay.innerHTML = `
End of the ${vs[0]}v${vs[1]} Tournament!
${winnersMessage}
${winners[0].state}:${usersLost[0].state}
${winnerImages}
${isWinner ? 'You Won!' : 'You Lost!'}
`;
document.body.append(overlay);
const leave = document.getElementById("tournament-leave");
leave.addEventListener("click", () => {
this.tData = {};
if (isWinner && !badgeClaimed) {
this.modAlert("Don't forget to claim your badge!", "default");
} else {
overlay.remove();
}
});
const claimBadge = document.getElementById("claim-badge");
claimBadge.addEventListener("click", () => {
fetch(this.appRoutes.badge, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: unsafeWindow.gameSettings.user._id,
badge: "tournament-winner",
}),
}).then(res => {
return res.json();
}).then(data => {
if (data.success) {
claimedModal();
document.getElementById("badgeWrapper").style.display = "none";
badgeClaimed = true;
} else {
this.modAlert("You already have this badge!", "default");
document.getElementById("badgeWrapper").style.display = "none";
badgeClaimed = true;
}
}).catch(error => {
this.modAlert("Error? Try again.", "danger");
});
});
function claimedModal() {
const overlay = document.createElement("div");
overlay.classList.add("mod_overlay");
overlay.innerHTML = `
Claimed Badge!
This badge is now added to your mod profile
`;
document.body.append(overlay);
document.getElementById("closeBadgeModal").addEventListener("click", () => {
overlay.remove();
});
}
},
modAlert(text, type) {
const overlay = document.querySelector("#modAlert_overlay");
const alertWrapper = document.createElement("div");
alertWrapper.classList.add("infoAlert")
if (type == "success") {
alertWrapper.classList.add("modAlert-success")
} else if (type == "danger") {
alertWrapper.classList.add("modAlert-danger")
} else if (type == "default") {
alertWrapper.classList.add("modAlert-default")
}
alertWrapper.innerHTML = `
${text}
`;
overlay.append(alertWrapper);
setTimeout(() => {
alertWrapper.remove();
}, 2000);
},
async account() {
const createAccountBtn = document.getElementById("createAccount");
const loginBtn = document.getElementById("login");
createAccountBtn.addEventListener("click", () => {
this.createSignInWrapper(false);
});
loginBtn.addEventListener("click", () => {
this.createSignInWrapper(true);
});
// popup window from discord login
const urlParams = new URLSearchParams(window.location.search);
let token = urlParams.get('token');
if (token && token.endsWith('/')) {
token = token.substring(0, token.length - 1);
} else {
return;
}
const data = await (await fetch(`${this.appRoutes.discordLogin}?token=${token}`, {
method: 'GET',
credentials: 'include',
})).json();
modSettings.authorized = true;
updateStorage();
unsafeWindow.close();
},
createSignInWrapper(isLogin) {
let that = this;
const overlay = document.createElement("div");
overlay.classList.add("signIn-overlay");
const headerText = isLogin ? "Login" : "Create an account";
const btnText = isLogin ? "Login" : "Create account";
const btnId = isLogin ? "loginButton" : "registerButton";
const confPass = isLogin ? '' : '';
overlay.innerHTML = `
`;
document.body.append(overlay);
const close = document.getElementById("closeSignIn");
close.addEventListener("click", hide);
function hide() {
overlay.style.opacity = "0";
setTimeout(() => {
overlay.remove();
}, 300);
}
overlay.addEventListener("click", (e) => {
if (e.target == overlay) hide();
});
setTimeout(() => {
overlay.style.opacity = "1";
});
// DISCORD LOGIN
const discord_login = document.getElementById("discord_login");
const w = 600;
const h = 800;
const left = (window.innerWidth - w) / 2;
const top = (window.innerHeight - h) / 2;
// Function to handle received messages
function receiveMessage(event) {
if (event.data.type === "profileData") {
const data = event.data.data;
console.log(data);
successHandler(data);
}
}
discord_login.addEventListener("click", () => {
const popupWindow = window.open(this.routes.discord.auth, '_blank', `width=${w}, height=${h}, left=${left}, top=${top}`);
const interval = setInterval(() => {
if (popupWindow.closed) {
clearInterval(interval);
setTimeout(() => {
location.reload();
}, 500);
}
}, 1000);
});
// LOGIN / REGISTER:
const button = document.getElementById(btnId);
button.addEventListener("click", async () => {
const endUrl = isLogin ? "login" : "register";
const url = isDev ? `http://localhost:${port}/sigmodz/${endUrl}` : `https://app.czrsd.com/sigmodz/${endUrl}`;
const username = document.getElementById("mod_username");
const password = document.getElementById("mod_pass");
const accountData = {
username: username.value,
password: password.value,
//captcha: this.captcha,
};
let conf = null;
if (confPass) {
accountData.confirmedPassword = document.getElementById("mod_pass_conf").value;
}
if (!username.value || !password.value) return;
const res = await fetch(url, {
method: "post",
credentials: 'include',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(accountData),
});
res.json().then(data => {
if (data.success) {
successHandler(data.user);
that.profile = data.user;
} else {
errorHandler(data.errors);
}
}).catch(error => {
console.error(error);
});
});
function successHandler(data) {
hide();
that.setFriendsMenu();
modSettings.authorized = true;
updateStorage();
this.profile = data;
}
function errorHandler(errors) {
errors.forEach((error) => {
const errMessages = document.getElementById("errMessages");
if (!errMessages) return;
if (errMessages.style.display == "none") errMessages.style.display = "flex";
let input = null;
switch (error.fieldName) {
case "Username":
input = "mod_username";
break;
case "Password":
input = "mod_pass";
break;
}
errMessages.innerHTML += `
${error.message}
`;
if (input && document.getElementById(input)) {
const el = document.getElementById(input);
el.classList.add("error-border");
el.addEventListener("input", () => {
el.classList.remove("error-border");
errMessages.innerHTML = "";
});
}
});
}
},
async auth() {
if (!modSettings.authorized) return;
const res = await fetch(this.appRoutes.auth, {
credentials: 'include',
});
res.json().then(data => {
if (data.success) {
this.setFriendsMenu();
this.profile = data.user;
this.setProfile(data.user);
} else {
console.error("Not a valid account.");
}
}).catch(error => {
console.error(error);
});
const response = await fetch(this.appRoutes.settings, { credentials: 'include' });
const responseData = await response.json();
this.friends_settings = responseData.settings;
},
setFriendsMenu() {
const that = this;
const friendsMenu = document.getElementById("mod_friends");
friendsMenu.innerHTML = ""; // clear content
// add new content
friendsMenu.innerHTML = `
`;
const elements = ["#friends_btn", "#allusers_btn", "#requests_btn", "#friends_settings_btn"];
elements.forEach(el => {
const button = document.querySelector(el);
button.addEventListener("click", () => {
elements.forEach(btn => document.querySelector(btn).classList.remove("mod_selected"));
button.classList.add("mod_selected");
switch (button.id) {
case "friends_btn":
that.openFriendsTab();
break;
case "allusers_btn":
that.openAllUsers();
break;
case "requests_btn":
that.openRequests();
break;
case "friends_settings_btn":
that.openFriendSettings();
break;
default:
console.error("Unknown button clicked");
}
});
});
document.getElementById("friends_btn").click(); // open friends first
},
async showProfileHandler (event) {
const userId = event.currentTarget.getAttribute('data-user-profile');
const req = await fetch(this.appRoutes.profile(userId), {
credentials: "include",
}).then((res) => res.json());
if (req.success) {
const user = req.user;
let badges = user.badges ? userBadges() : "User has no badges.";
let icon = null;
function userBadges() {
let badgeArray = JSON.parse(user.badges);
return badgeArray.join(', ');
}
const overlay = document.createElement("div");
overlay.classList.add("mod_overlay");
overlay.style.opacity = "0";
overlay.innerHTML = `
Bio:
${user.bio || "User has no bio."}
Badges:
${badges}
${user.lastOnline ? `
Last online:${formatTime(user.lastOnline)} (${getTimeAgo(user.lastOnline)})` : ''}
`;
document.body.append(overlay);
function hide() {
overlay.style.opacity = "0";
setTimeout(() => {
overlay.remove();
}, 300);
}
overlay.addEventListener("click", (e) => {
if (e.target == overlay) hide();
});
setTimeout(() => {
overlay.style.opacity = "1";
});
document.getElementById("closeProfileEditor").addEventListener("click", hide);
}
},
async openFriendsTab() {
let that = this;
const friends_body = document.querySelector(".friends_body");
if (friends_body.classList.contains("allusers")) friends_body.classList.remove("allusers");
friends_body.innerHTML = "";
const res = await fetch(this.appRoutes.friends, {
credentials: 'include',
});
res.json().then(data => {
if (!data.success) return;
if (data.friends.length !== 0) {
const newUsersHTML = data.friends.map(user => `
${user.nick ? `
${user.username}
${user.nick}
` : `
${user.username}
`}
${user.server ? `
${user.server}
` : ''}
${user.tag ? `
Tag: ${user.tag}
` : ''}
${user.role}
`).join('');
friends_body.innerHTML = newUsersHTML;
if (!modSettings.feedback) {
friends_body.innerHTML += `
Give some feedback for this feature so we can improve it
`;
const close = document.getElementById("closeFeedback");
close.addEventListener("click", () => {
document.querySelector(".feedback_row").remove();
});
const send = document.getElementById("send-feedback");
const msg = document.getElementById("feedback-message");
send.addEventListener("click", async () => {
const res = await fetch(this.appRoutes.feedback, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ msg: msg.value }),
credentials: "include",
}).then((res) => res.json());
if (res.success) {
modSettings.feedback = true;
updateStorage();
document.querySelector(".feedback_row").remove();
} else {
this.modAlert(res.message, "danger");
}
});
}
const userProfiles = document.querySelectorAll('.user-profile-wrapper');
userProfiles.forEach(button => {
if (button.getAttribute('data-user-profile') == this.profile.id) return;
button.addEventListener('click', (e) => {
if (e.target == button) {
this.showProfileHandler(e);
}
});
});
data.friends.forEach((friend) => {
if (friend.nick) {
this.friend_names.add(friend.nick);
}
const remove = document.getElementById(`remove-${friend.id}`);
remove.addEventListener("click", async () => {
if (confirm("Are you sure you want to remove this friend?")) {
const res = await fetch(this.appRoutes.removeAvatar, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ type: "remove-friend", userId: friend.id }),
credentials: "include",
}).then((res) => res.json());
if (res.success) {
that.openFriendsTab();
} else {
let message = res.message || "Something went wrong. Please try again later.";
that.modAlert(message, "danger");
}
}
});
const chat = document.getElementById(`chat-${friend.id}`);
chat.addEventListener("click", () => {
this.openChat(friend.id);
});
});
} else {
friends_body.innerHTML = `
You have no friends yet :(
Go to the All users tab to find new friends.
`;
}
}).catch(error => {
console.error(error);
});
},
async openChat(id) {
const res = await fetch(this.appRoutes.chatHistory(id), {
credentials: "include",
});
const { history, target, success } = await res.json();
if (!success) {
this.modAlert("Something went wrong...", "danger");
return;
}
const body = document.querySelector(".mod_menu_content");
const chatDiv = document.createElement("div");
chatDiv.classList.add("friends-chat-wrapper");
chatDiv.id = id;
setTimeout(() => { chatDiv.style.opacity = "1" });
const messagesHTML = history.map(message => `
${message.content}
${formatTime(message.timestamp)}
`).join('');
chatDiv.innerHTML = `
${history.length > 0 ? messagesHTML : "
This is the beginning of your conversation..."}
`;
body.appendChild(chatDiv);
const messagesContainer = chatDiv.querySelector(".friends-chat-messages");
messagesContainer.scrollTop = messagesContainer.scrollHeight;
const back = document.getElementById("back-friends-chat");
back.addEventListener("click", (e) => {
chatDiv.style.opacity = "0";
setTimeout(() => {
chatDiv.remove();
}, 300);
});
const text = document.getElementById("private-message-text");
const send = document.getElementById("send-private-message");
text.addEventListener("keydown", (e) => {
const key = e.key.toLowerCase();
if (key === "enter") {
sendMessage(text.value, id)
text.value = "";
}
});
send.addEventListener("click", () => {
sendMessage(text.value, id);
text.value = "";
});
function sendMessage(val, target) {
if (!val || val.length > 200) return;
client.send({
type: "private-message",
content: {
text: val,
target,
}
});
}
},
updatePrivateChat(data) {
const { sender_id, target_id, textmessage, timestamp } = data;
let chatDiv = document.getElementById(target_id) || document.getElementById(sender_id);
if (!chatDiv) {
console.error("Could not find chat div for either sender or target");
return;
}
const messages = chatDiv.querySelector(".friends-chat-messages");
messages.innerHTML += `
${textmessage}
${formatTime(timestamp)}
`;
messages.scrollTop = messages.scrollHeight;
},
async searchUser(user) {
if (!user) {
this.openAllUsers();
return;
}
const response = await fetch(`${this.appRoutes.search}/?q=${user}`, {
credentials: "include",
}).then((res) => res.json());
const usersDiv = document
const usersContainer = document.getElementById("users-container");
usersContainer.innerHTML = "";
if (!response.success) {
usersContainer.innerHTML = `
Couldn't find ${user}...
`;
return;
}
const handleAddButtonClick = (event) => {
const userId = event.currentTarget.getAttribute('data-user-id');
const add = event.currentTarget;
fetch(this.appRoutes.request, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ req_id: userId }),
credentials: "include",
}).then((res) => res.json())
.then(req => {
const type = req.success ? "success" : "danger";
this.modAlert(req.message, type);
if (req.success) {
add.disabled = true;
add.innerHTML = `
`;
}
});
};
response.users.forEach((user) => {
const userHTML = `
${this.profile.username === user.username ? `${user.username} (You)` : user.username}
${user.role}
${this.profile.id == user.id ? '' : `
`}
`;
usersContainer.insertAdjacentHTML('beforeend', userHTML);
if (user.id == this.profile.id) return;
// Add event listener to view user profile
const newUserProfile = usersContainer.querySelector(`[data-user-profile="${user.id}"]`);
newUserProfile.addEventListener('click', (e) => {
if (e.target == newUserProfile) {
this.showProfileHandler(e);
}
});
// Add event listener to request button
const addButton = newUserProfile.querySelector('.add-button');
if (!addButton) return;
addButton.addEventListener('click', handleAddButtonClick);
});
},
async openAllUsers() {
let offset = 0;
let maxReached = false;
let defaultAmount = 5; // min: 1; max: 100
const friends_body = document.querySelector(".friends_body");
friends_body.innerHTML = `
`;
const usersContainer = document.getElementById("users-container");
friends_body.classList.add("allusers");
// search user
const search = document.getElementById("search-user");
search.addEventListener("input", debounce(() => {
this.searchUser(search.value);
}, 500));
const handleAddButtonClick = (event) => {
const userId = event.currentTarget.getAttribute('data-user-id');
const add = event.currentTarget;
fetch(this.appRoutes.request, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ req_id: userId }),
credentials: "include",
}).then((res) => res.json())
.then(req => {
const type = req.success ? "success" : "danger";
this.modAlert(req.message, type);
if (req.success) {
add.disabled = true;
add.innerHTML = `
`;
}
});
};
// Set to store displayed user IDs
const displayedUserIDs = new Set();
const fetchNewUsers = async () => {
const newUsersResponse = await fetch(this.appRoutes.users, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ amount: defaultAmount, offset }),
credentials: "include",
}).then((res) => res.json());
const newUsers = newUsersResponse.users;
if (newUsers.length === 0) {
maxReached = true;
return;
};
offset += defaultAmount;
newUsers.forEach(user => {
if (!displayedUserIDs.has(user.id)) {
displayedUserIDs.add(user.id);
const newUserHTML = `
${this.profile.username === user.username ? `${user.username} (You)` : user.username}
${user.role}
${this.profile.id == user.id ? '' : `
`}
`;
usersContainer.insertAdjacentHTML('beforeend', newUserHTML);
// Add event listener to view user profile
const newUserProfile = usersContainer.querySelector(`[data-user-profile="${user.id}"]`);
newUserProfile.addEventListener('click', (e) => {
if (e.target == newUserProfile) {
this.showProfileHandler(e);
}
});
// Add event listener to request button
const addButton = newUserProfile.querySelector('.add-button');
if (!addButton) return;
addButton.addEventListener('click', handleAddButtonClick);
}
});
};
const scrollHandler = async () => {
if (maxReached) return;
if (usersContainer.scrollTop + usersContainer.clientHeight >= usersContainer.scrollHeight) {
await fetchNewUsers();
}
};
// Remove existing scroll event listener if exists
usersContainer.removeEventListener("scroll", scrollHandler);
// Add new scroll event listener
usersContainer.addEventListener("scroll", scrollHandler);
// Initial fetch
await fetchNewUsers();
},
async openRequests() {
let that = this;
const friends_body = document.querySelector(".friends_body");
friends_body.innerHTML = "";
if (friends_body.classList.contains("allusers")) friends_body.classList.remove("allusers");
const requests = await fetch(this.appRoutes.myRequests, {
credentials: "include",
}).then((res) => res.json());
if (!requests.body) return;
if (requests.body.length > 0) {
const reqHtml = requests.body.map(user => `
`).join('');
friends_body.innerHTML = reqHtml;
friends_body.querySelectorAll('.accept').forEach(accept => {
accept.addEventListener("click", async () => {
const userId = accept.getAttribute('data-user-id');
const req = await fetch(this.appRoutes.handleRequest, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ type: "accept-request", userId }),
credentials: "include",
}).then((res) => res.json());
that.openRequests();
});
});
friends_body.querySelectorAll('.decline').forEach(decline => {
decline.addEventListener("click", async () => {
const userId = decline.getAttribute('data-user-id');
const req = await fetch(this.appRoutes.handleRequest, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ type: "decline-request", userId }),
credentials: "include",
}).then((res) => res.json());
that.openRequests();
});
});
} else {
friends_body.innerHTML = `No requests!`;
}
},
async openFriendSettings() {
const friends_body = document.querySelector(".friends_body");
if (friends_body.classList.contains("allusers")) friends_body.classList.remove("allusers");
friends_body.innerHTML = "";
if (Object.keys(this.friends_settings).length === 0) {
const response = await fetch(this.appRoutes.settings, { credentials: 'include' });
const responseData = await response.json();
this.friends_settings = responseData.settings;
}
friends_body.innerHTML = `
Your user id
${this.friends_settings.target}
Status
Highlight color
`;
const editProfile = document.getElementById("editProfile");
editProfile.addEventListener("click", () => {
this.openProfileEditor();
});
const logout = document.getElementById("logout_mod");
logout.addEventListener("click", async () => {
if (confirm("Are you sure you want to logout?")) {
const res = await fetch(this.appRoutes.logout).then((res) => res.json());
//location.reload();
}
});
const edit_static_status = document.getElementById("edit_static_status");
const edit_accept_requests = document.getElementById("edit_accept_requests");
const edit_highlight_friends = document.getElementById("edit_highlight_friends");
const edit_highlight_color = document.getElementById("edit_highlight_color");
const edit_visible = document.getElementById("edit_visible");
edit_static_status.addEventListener("change", () => {
const val = edit_static_status.value;
updateSettings("static_status", val);
});
edit_accept_requests.addEventListener("change", () => {
const val = edit_accept_requests.checked;
updateSettings("accept_requests", val);
});
edit_highlight_friends.addEventListener("change", () => {
const val = edit_highlight_friends.checked;
updateSettings("highlight_friends", val);
});
// Debounce the updateSettings function
edit_highlight_color.addEventListener("input", debounce(() => {
const val = edit_highlight_color.value;
updateSettings("highlight_color", val);
}, 500));
edit_visible.addEventListener("change", () => {
const val = edit_visible.checked;
updateSettings("visible", val);
});
const updateSettings = async (type, data) => {
const resData = await (await fetch(this.appRoutes.updateSettings, {
method: 'POST',
body: JSON.stringify({ type, data }),
credentials: 'include',
headers: {
'Content-Type': 'application/json'
}
})).json();
if (resData.success) {
this.friends_settings[type] = data;
}
}
},
openProfileEditor() {
let that = this;
const overlay = document.createElement("div");
overlay.classList.add("mod_overlay");
overlay.style.opacity = "0";
overlay.innerHTML = `
`;
document.body.append(overlay);
function hide() {
overlay.style.opacity = "0";
setTimeout(() => {
overlay.remove();
}, 300);
}
overlay.addEventListener("click", (e) => {
if (e.target == overlay) hide();
});
setTimeout(() => {
overlay.style.opacity = "1";
});
document.getElementById("closeProfileEditor").addEventListener("click", hide);
let changes = new Set(); // Use a Set to store unique changes
const bio_edit = document.getElementById("bio_edit");
const charCountSpan = document.getElementById("charCount");
bio_edit.addEventListener("input", updCharcounter);
function updCharcounter() {
const currentTextLength = bio_edit.value.length;
charCountSpan.textContent = currentTextLength + "/250";
// Update changes
changes.add("bio");
}
// Upload avatar
document.getElementById("imageUpload").addEventListener("input", async (e) => {
const file = e.target.files[0];
if (!file) return;
console.log(file);
const formData = new FormData();
formData.append('image', file);
try {
const data = await (await fetch(this.appRoutes.imgUpload, {
method: 'POST',
credentials: 'include',
body: formData,
})).json();
console.log(data);
if (data.success) {
const profileImg = document.querySelector(".profile-img img");
profileImg.src = data.user.imageURL;
hide();
that.profile = data.user;
} else {
that.modAlert(data.message, "danger");
console.error('Failed to upload image');
}
} catch (error) {
console.error('Error uploading image:', error);
}
});
const username_edit = document.getElementById("username_edit");
username_edit.addEventListener("input", () => {
changes.add("username");
});
const saveChanges = document.getElementById("saveChanges");
saveChanges.addEventListener("click", async () => {
if (changes.size === 0) return;
let changedData = {};
changes.forEach((change) => {
if (change === "username") {
changedData.username = username_edit.value;
} else if (change === "bio") {
changedData.bio = bio_edit.value;
}
});
const resData = await (await fetch(this.appRoutes.editProfile, {
method: 'POST',
body: JSON.stringify({
changes: Array.from(changes),
data: changedData,
}),
credentials: 'include',
headers: {
'Content-Type': 'application/json'
}
})).json();
if (resData.success) {
if (that.profile.username !== resData.user.username) {
const p_username = document.getElementById("profile_username_00");
if (p_username) p_username.innerText = resData.user.username;
}
that.profile = resData.user;
changes.clear();
hide();
const name = document.getElementById("my-profile-name");
const bioText = document.getElementById("my-profile-bio");
name.innerText = resData.user.username;
bioText.innerHTML = resData.user.bio;
} else {
resData.errors.forEach((error) => {
this.modAlert(error.message, "danger");
});
}
});
const deleteAvatar = document.getElementById("deleteAvatar");
deleteAvatar.addEventListener("click", async () => {
if (confirm("Are you sure you want to remove your profile picture? It will be changed to the default profile picture.")) {
try {
const data = await (await fetch(this.appRoutes.delProfile, {
credentials: 'include',
})).json();
const profileImg = document.querySelector(".profile-img img");
profileImg.src = data.user.imageURL;
hide();
that.profile = data.user;
} catch(error) {
console.error('CouldN\'t remove image: ', error);
this.modAlert(error.message, "danger");
}
}
});
},
load() {
// Load game faster
function randomPos() {
let eventOptions = {
clientX: Math.floor(Math.random() * window.innerWidth),
clientY: Math.floor(Math.random() * window.innerHeight),
bubbles: true,
cancelable: true
};
let event = new MouseEvent('mousemove', eventOptions);
document.dispatchEvent(event);
}
let moveInterval = setInterval(randomPos);
setTimeout(() => clearInterval(moveInterval), 600);
// load mod when websocket is ready
let loaded = false;
let intervalId = setInterval(() => {
if (!unsafeWindow.WebSocket) return;
// load mod
this.createMenu();
loaded = true;
clearInterval(intervalId);
}, 400);
},
createMenu() {
this.smallMods();
this.menu();
this.credits();
this.chat();
this.Macros();
this.Themes();
this.updateNick();
this.clientPing();
this.tagsystem();
this.createMinimap();
this.saveNames();
this.setInputActions();
this.game();
this.mainMenu();
this.macroSettings();
this.fps();
this.initStats();
this.account();
const styleTag = document.createElement("style")
styleTag.innerHTML = this.style;
document.head.append(styleTag);
// Respawn interval
setInterval(() => {
if (modSettings.AutoRespawn && this.respawnTime && Date.now() - this.respawnTime >= this.respawnCooldown) {
this.respawn();
}
})
// mouse fast feed interval
setInterval(() => {
if (dead || !menuClosed() || !this.mouseDown) return;
this.fastMass()
}, 50);
}
}
const mods = new mod();
})();
/* ** ** ** ** ** ** *\
| SigMod by Cursed |
\* .. .. .. .. .. .. */