// ==UserScript==
// @name Advanced Agma
// @namespace http://tampermonkey.net/
// @version 0.1.1
// @author Big watermelon (credits: Nersai, Vintrex)
// @description clickable chat links, discord in game chat (/discord ... hi), remove specific animations, remove food completely (toggle mouse), advanced user stats (agma.io/stats.php), increase number of stackable animations
// @match https://agma.io/*
// @match https://discord.com/*
// @require https://cdn.jsdelivr.net/npm/pako@2.0.4/dist/pako.min.js
// @license GPL-3.0-or-later
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAMAAADDpiTIAAAC9FBMVEUAAAC9vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb0VZcATXrgNR6ENR6EVZcAVZcAVZcAVZcARVrEOSaMNR6ENR6ENR6ENR6EVZcAVZcAVY74QUq0NR6ENR6EVZcATXrgOS6UNR6ENR6G9vb0RVK+9vb0VZcANR6ESWrQNR6EVZcAUX7oPTacNR6EVZcAQUKu0tLSrq6uwsLAVZcC5ubmenp5+fn51dXV6enqQkJCTp74qcMCnp6ezuL1Uhr8NR6GVlZWioqKJor4ga8CMjIyosr01dr+Dg4PGxsbJycnDw8NfjL/c3Nzu7u7o6Oh+nL7MzMzr6+vi4uKerb7W1tZKgb91dXV1dXXS0tLl5eXAwMBpkb8PT6l1dXV1dXWZmZmJiYl1dXV1dXV1dXV1dXV1dXV1dXXZ2dk/e791dXV1dXVvcniusbdbaoAUSp4YTqOGmLTf398SWLJIYYhEbKqytruHh4cRV7IUYbzPz88VZcCRoLZae60uXaanrroVZcA5ZagjVqWcp7hwibFPc6wWaMMad9MbftoYcc0Xa8YdhOAhlvMTXLZ7kbMgkO0VZcAcgd0NR6EVZcAXbsofjekaetYdh+N1dXUeiuYgk/AZdNBlgq+ZmZm9vb2apbcNR6Gosr2yt70ha8Cbq751l77/wQf/wQf/wQdTfo//wQf/wQf/wQfFqjVQfJL/wQf/wQe2pEEycamKk2Qka7Tith5egobwuxN7jW//wQf/wQdtiHuZmVinn0zTsCpBdp0PTqgSWbQjabOHhlbwuRErVo6kk0FKZnvDoy5FY33/wQccT5d3fF6GhFT/wQf/wQcQUasOSaMOSqQOSaMOSqQPTacvX6goWaVpaWmPj4+bm5usrKxhYWFhYWFnZ2eEhISgoKBhYWFtbW23t7d4eHhhYWFhYWGysrJhYWFhYWFycnJhYWFhYWGGhoZnZ2dhYWGpqalhYWGMjIx6enphYWFhYWFhYWFhYWFhYWFiRaieAAAA/HRSTlMAMIC/3//Pn2AQr0DvjzBAQBAQcM//////v49QQO///++fj///32BQ/3CvIP+AgP//zyD/////UP//////////////MP/////////////////////////////fv///////nzAgr89AYI/vIP//EK////////////////+v//9g/////5////////////////////+//3Df/////4D//////yBQr4Dv3+9wEFCA74/v////MN///////////3C///////+PUP/////////PYP///59AMM+P769Q/8+v////QP////+/////IJ//EO//YHDv71Dfj+/vzzDfgK9Air+ZAAAYg0lEQVR4AezBtQHDMAAAsMRM/79bmkprJks6AAAAAAAAAAC41hliyi+ltn6wlR5S/jDmwTZ6yL/iPNjDXPmvOzt3oeTGDkQBtAMdRq8VK2R2mDkxhJk83jAzMzMv/PWCrDGM3LJf0ZO2+vzCvSW1BjQX7ObNX7AQvMcmI2UaPQrE+uJCiEUJuXjJUmA+m460OZOgs2XLhZJMSSnTmQUw8XD+dANiWdGQy8sxhRXAPM6fNmclGObFRYvkKul/BTh/2gyI6FsulMgiIAs+DwOcP201tIqtEYZkSiqL14L3OH/TdGP6M6xLSGU9eI7ztzdggyBs3CSVzbwIeJ8//UBgS1yQklulkuZh0Nf8t23fvoNswOTJMybtXC5sFsm6zEJgzps5Ddvs2r2nOKZU3oakyl5htU7yNuBr/vtKxVB5F1L2HxBWuYRU0geBeZX/oWKL0mEkHTkqbDYmeBDwMP9dx4pa90Xg+ImeGiC5AR7lf7IYdTI6CZw6ffr0GVTOTuwGcP5KqfU8cKYaKLXqKRzTb90GctLrBnD+ZgPOnQ8aLoxX4KJ1G1jncwM4f7MBZ3T+2iVE3H9ZWKzyswGc/5WrV0sdGnAtaHf9BiLeFBa3pObRaZDzv30HAO7eKzbtQ+VSEFE71WUQSIaDYHotOIVNmkrkf/8B1D0shvYgUYDgvBoEjvYwCG5eCA5hk+YQ+T+ChjuPi3WHwhkg6NyA/Sd6GAMy4D7O//FDaPHkflHZjtrTwFC7Md6AZ4K0yaNBkPO/A22evyiOefkKQxcCw3Ucd0BQNnozBnD+959A1KNi8fWbt+9Qu/E+MFxCtB4GPkhtMTiN87/6HEwPP8oxnz6jVg0Mp3Bcv6Dc4k3A5fzxS3j6gw5iX6Xy9h09B1xAewO+SS29EJhz+ZeN8b/9u//cJinbFoHvQdRpVCpHyQ+EtCXAXM3/IXTwY3lLfm9/Gm8EtPeokA8Eknmp8Rzo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
// @grant unsafeWindow
// @grant GM_setValue
// @grant GM_getValue
// @run-at document-start
// ==/UserScript==
/* WARNING:
This script defines properties on certain objects
so if other scripts define the same properties some stuff may break
Overwritten Properties
| localChatMessage.cache
| localChatMessage.cache.v
| localChatMessage.cache.ie
| localChatMessage.cache.color2
| localChatMessage.cache.ctx
| localChatMessage.cache.ctx.fillText
*/
/*
FIXIT: token isnt always grabbed
FIXIT: GM_ functions don't seem to work always so maybe use localStorage
but that's kinda risky so maybe hash it with some values inside the script
TODO: message edit => edit message
TODO: message too long to fit in chat => wrap arround (well maybe not worth it)
*/
(function() {
"use strict";
if (unsafeWindow.top !== unsafeWindow.self || document.querySelector("title")?.textContent?.includes("Just a moment")) {
return;
}
const settings = GM_getValue("settings", {
removeFood: true,
removeAnimations: [3, 6, 7, 8, 11],
maxStackableAnimations: 3,
discordChat: false,
discordSavedChannels: [],
discordPresence: false
});
const discordToken = GM_getValue("discordToken", null);
if (settings.discordChat && unsafeWindow.location.href.startsWith("https://discord.com")) {
if (!discordToken) {
GM_setValue("discordToken", JSON.parse(unsafeWindow.localStorage.token));
unsafeWindow.alert("Discord Chat for agma.io has updated your token !");
}
return;
}
const numberFormat = Intl.NumberFormat("fr-FR");
const userprofiles = unsafeWindow.localStorage.userprofiles ? JSON.parse(unsafeWindow.localStorage.userprofiles) : {};
if (!discordToken) {
unsafeWindow.alert("Discord Chat can not work since you didnt log in into your browser with discord.\nIf you want to use the discord chat feature wait for an alert saying that your token has been saved.\n\nhttps://discord.com");
settings.discordChat = false;
}
const discordPresence = {
status: "online",
since: 0,
activities: [{
name: "Agma.io",
type: 0,
url: "https://agma.io",
details: "Playing Agma.io",
timestamps: {
start: Date.now()
}
}],
afk: false
}
const animations = {
1: { name: "Recombine", style: "border-color: #337ab7; background-image: url('./img/store/recombine-min.png'); padding-left: 30px; padding-left: 30px;" },
2: { name: "Cell Select", style: "border-color: #fe3f3f;" },
3: { name: "Spin", style: "border-color: #b3b3b3;" },
4: { name: "360 Shot", style: "border-color: #337ab7; background-image: url('./img/push_lo.png'); padding-left: 30px;" },
5: { name: "Level Up", style: "border-color: #fe3f3f;" },
6: { name: "Flip Spin", style: "border-color: #b3b3b3;" },
7: { name: "Flip", style: "border-color: #b3b3b3;" },
8: { name: "Shake", style: "border-color: #b3b3b3;" },
9: { name: "Explosion", style: "border-color: #f0ad4e; background-image: url('./emotes/1f4a5.png'); padding-left: 30px;" },
10: { name: "1st Medal", style: "border-color: #f0ad4e;" },
11: { name: "Jump", style: "border-color: #b3b3b3;" },
12: { name: "Wacky", style: "border-color: #f0ad4e; background-image: url('./emotes/1f61c.png'); padding-left: 30px;" },
13: { name: "White cell for 1 frame", style: "border-color: #fe3f3f;" },
14: { name: "Freeze", style: "border-color: #337ab7; background-image: url('./img/inv_freeze2.png'); padding-left: 30px;" },
15: { name: "Speed", style: "border-color: #337ab7; background-image: url('./img/store/speed-min.png'); padding-left: 30px;" },
16: { name: "Idk", style: "border-color: #fe3f3f;" }, // weird nothing
17: { name: "Upgrade", style: "border-color: #fe3f3f;" },
18: { name: "Snowball", style: "border-color: #fe3f3f;" },
20: { name: "Anti freeze", style: "border-color: #337ab7; background-image: url('./skins/objects/20.png'); padding-left: 30px;" },
21: { name: "Anti recombine", style: "border-color: #337ab7; background-image: url('./skins/objects/21.png'); padding-left: 30px;" },
23: { name: "Shield", style: "border-color: #337ab7; background-image: url('img/inv_shield5.png'); color: rgba(82, 152, 203, 0.6); padding-left: 30px;" },
24: { name: "Shield", style: "border-color: #337ab7; background-image: url('img/inv_shield5.png'); color: rgba(84, 211, 77, 0.6); padding-left: 30px;" },
25: { name: "Shield", style: "border-color: #337ab7; background-image: url('img/inv_shield5.png'); color: rgba(243, 46, 46, 0.6); padding-left: 30px;" },
26: { name: "Shield", style: "border-color: #337ab7; background-image: url('img/inv_shield5.png'); color: rgba(127, 59, 227, 0.6); padding-left: 30px;" },
30: { name: "Wave", style: "border-color: #f0ad4e; background-image: url('./emotes/1f44b.png'); padding-left: 30px;" },
31: { name: "Head Explosion", style: "border-color: #f0ad4e; background-image: url('./emotes/1f61cd.png'); padding-left: 30px;" },
32: { name: "Hearts Face", style: "border-color: #f0ad4e; background-image: url('./emotes/1f60d.png'); padding-left: 30px;" },
41: { name: "Angry Pumpkin", style: "border-color: #f0ad4e; background-image: url('./emotes/angry_emote3.png'); padding-left: 30px;" },
42: { name: "Scared Pumpkin", style: "border-color: #f0ad4e; background-image: url('./emotes/scared_emote.png'); padding-left: 30px;" },
43: { name: "Yawn Pumpkin", style: "border-color: #f0ad4e; background-image: url('./emotes/yawn_emote.png'); padding-left: 30px;" },
44: { name: "Throwup", style: "border-color: #f0ad4e; background-image: url('./emotes/throwup.png'); padding-left: 30px;" },
45: { name: "Hot face", style: "border-color: #f0ad4e; background-image: url('./emotes/hotface.png'); padding-left: 30px;" },
46: { name: "Tears Joy", style: "border-color: #f0ad4e; background-image: url('./emotes/tearsjoy.png'); padding-left: 30px;" },
47: { name: "No No", style: "border-color: #f0ad4e; background-image: url('./emotes/nonu.png'); padding-left: 30px;" },
48: { name: "Clap", style: "border-color: #f0ad4e;" },
49: { name: "Crying", style: "border-color: #f0ad4e;" },
50: { name: "Devil Smile", style: "border-color: #f0ad4e;" },
51: { name: "Eatman", style: "border-color: #f0ad4e;" },
52: { name: "Trophy", style: "border-color: #f0ad4e;" },
53: { name: "Hearts", style: "border-color: #f0ad4e;" }
};
const animationsIds = [
1, 4, 14, 15, 20, 21, 23, 24, 25, 26, // Powers
3, 6, 7, 8, 11, // Annoying
9, 10, 12, 30, 31, 32, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, // Emotes
2, 5, 13, 16, 17, 18 // System
];
const discordIcon = new Image();
discordIcon.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAMAAADTRh9nAAAAS1BMVEVHcExYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfJYZfLaTvQiAAAAGHRSTlMAGTDyq+e2/N/4CMgjf1vXSTaJZ5HSEHVuv+kNAAAAqElEQVQY02VQSRLDMAgjXvGSxGvC/19acNpDphwQyIA0BgDYDoN7Virv1hwbrFApEGm0FjVRSEq4aOgVJjJZwpsM5X9wjVYrhX/6BbbCLuiOxiK6HU66HQQsK/IVA5BlzwFyPtncIBps+eQWQYtgj2rym4pdrARYt3WSBcKkl9wivf/ZeSpwDDgc6hA0usEb3sHVp6eUt1pK3XIiP/sln3TPBt9o82YnH6drET/OdjF6AAAAAElFTkSuQmCC";
const urlRegex = /https?:\/\/[^\s]+/g;
const invisibleChar = "᠋";
const wordsToReplace = ["https", "www", ".gg", ".com", ".io", ".net", ".biz", "miracle", "palestine"].map(word => [
new RegExp(`\\b(${word})\\b`, "gi"),
word[0] + invisibleChar + word.slice(1)
]);
var discordUsername;
var discordUserContext = null;
var discordWebSocket;
var discordHeartbeatInterval;
var discordReconnectRetryCount = 0;
const discordGatewayUrl = "wss://gateway.discord.gg/?v=9&encoding=json";
const sentMessagesIds = [];
const originalSend = WebSocket.prototype.send;
const sendWebsocketDiscordMessage = (op, d) => originalSend.call(discordWebSocket, JSON.stringify({ op, d }));
var chtTabs;
var currentTab = '';
var localChatMessages;
var cellProtoOverwritten = false;
function initDiscordWebSocket() {
discordWebSocket = new WebSocket(discordGatewayUrl);
discordWebSocket.onopen = () => console.debug("[🔵] Connected");
discordWebSocket.onmessage = ({ data }) => {
if (data instanceof Blob) {
const reader = new FileReader();
reader.onload = () => {
handleMessage(JSON.parse(pako.inflate(new Uint8Array(reader.result), { to: 'string' })));
};
reader.readAsArrayBuffer(data);
} else {
handleMessage(JSON.parse(data));
}
};
discordWebSocket.onclose = () => {
console.debug("[🔵] Disconnected");
clearInterval(discordHeartbeatInterval);
if (++discordReconnectRetryCount < 5) {
initDiscordWebSocket();
}
};
}
function createDiscordChatMessage(message) {
if (!message.channel_id || ![0, 19, 1, 2, 3, 6].includes(message.type) || sentMessagesIds.includes(message.id)) {
return;
}
const channel = settings.discordSavedChannels.find(channel => channel.id === message.channel_id);
if (!channel) {
return;
}
sentMessagesIds.push(message.id);
console.debug("[🔵] New message:", message);
const tab = chtTabs.querySelector(`div[data-username="discord-${channel.id}"]`);
if (!tab) {
newDiscordTab(channel.name, channel.id);
} else if (!tab.classList.contains('selected')) {
tab.classList.add('blink');
setTimeout(() => tab.classList.remove('blink'), 2000);
}
const author = message.author.global_name || message.author.username;
switch (message.type) {
case 0: // DEFAULT
case 19: // REPLY
var content = message.content || '';
message.mentions.forEach(mention => content = content.replaceAll(
`<@${mention.id}>`,
mention.global_name || mention.username
));
if (message.attachments.length) {
content += ` +${message.attachments.length} files`;
}
localChatMessages.push({
O: true,
get v() {
discordUserContext = this.discordAuthor;
return -1;
},
o: 0,
P: 0,
U: 0,
name: author,
G: "discord-" + channel.id,
color: discordUsername === message.author.username ? "#313338" : "#5662E9",
message: content,
category: 2,
goldMember: 0,
L: 0,
Y: 0,
q: 0,
j: 0,
J: 0,
time: Date.now(),
_cache: null,
get cache() {
return this._cache;
},
set cache(value) {
value.icons = [ 14 ];
return this._cache = value;
},
discordAuthor: message.author
});
break;
case 1: // RECIPIENT_ADD
case 2: // RECIPIENT_REMOVE
const member = message.mentions[0];
localChatMessages.push({
O: false,
v: 0,
o: 0,
P: 0,
U: 0,
name: '',
G: "discord-" + channel.id,
color: message.type === 1 ? "#00FF00" : "#FF0000",
message: `${message.type === 1 ? "➡️" : "⬅️"} ${member.global_name || member.username} ${message.type === 1 ? "joined" : "left"} the group`,
category: 2,
goldMember: 0,
L: 0,
Y: 0,
q: 0,
j: 0,
J: 0,
time: Date.now(),
_cache: null,
get cache() {
return this._cache;
},
set cache(value) {
value.icons = [ 14 ];
Object.defineProperties(value, {
ie: { get: () => this.message },
color2: { get: () => this.color }
});
return this._cache = value;
}
});
break;
case 3: // CALL
localChatMessages.push({
O: false,
v: 0,
o: 0,
P: 0,
U: 0,
name: '',
G: "discord-" + channel.id,
color: "#00FF00",
message: `${author} started a call`,
category: 2,
goldMember: 0,
L: 0,
Y: 0,
q: 0,
j: 0,
J: 0,
time: Date.now(),
_cache: null,
get cache() {
return this._cache;
},
set cache(value) {
value.icons = [ 14 ];
Object.defineProperties(value, {
ie: { get: () => this.message },
color2: { get: () => this.color }
});
return this._cache = value;
}
});
break;
case 6: // CHANNEL_PINNED_MESSAGE
// message_reference: { message_id: "1259902171630145651", channel_id: "853556382417420298" }
localChatMessages.push({
O: false,
v: 0,
o: 0,
P: 0,
U: 0,
name: '',
G: "discord-" + channel.id,
color: "#00FF00",
message: `${author} pinned a message`,
category: 2,
goldMember: 0,
L: 0,
Y: 0,
q: 0,
j: 0,
J: 0,
time: Date.now(),
_cache: null,
get cache() {
return this._cache;
},
set cache(value) {
value.icons = [ 14 ];
Object.defineProperties(value, {
ie: { get: () => this.message },
color2: { get: () => this.color }
});
return this._cache = value;
}
});
break;
}
}
function handleMessage(message) {
const { op, t, d } = message;
switch (op) {
case 10: // Hello
console.debug("[🔵] Connection accepted");
discordHeartbeatInterval = setInterval(() => sendWebsocketDiscordMessage(1, null), d.heartbeat_interval);
sendWebsocketDiscordMessage(2, {
token: discordToken,
capabilities: 30717,
properties: {}
});
settings.discordPresence && setTimeout(() => sendWebsocketDiscordMessage(3, discordPresence), 2000);
break;
case 0: // Dispatch
switch (t) {
case "MESSAGE_CREATE":
createDiscordChatMessage(d);
break;
case "READY":
discordUsername = d.user?.username || discordUsername;
console.debug("[🔵] Logged as", discordUsername);
break;
// default:
// console.debug("[🔵] Unhandled message type:", t);
}
break;
case 1: // HEARTBEAT
sendWebsocketDiscordMessage(1, null);
break;
case 11: // HEARTBEAT_ACK
break;
default:
console.debug("[🔵] Unhandled opcode type:", op);
}
}
function findUrlToOpen(event) {
const x = event.clientX - event.target.offsetLeft,
y = event.clientY - event.target.offsetTop;
for (const message of localChatMessages) {
if (message.cache && message.cache.urls) {
for (const { url, rect } of message.cache.urls) {
if (x >= rect.x0 && y >= rect.y0 && x <= rect.x1 && y <= rect.y1) {
unsafeWindow.open(url, '_blank');
}
}
}
}
}
function timeFormat(s) {
const h = Math.floor(s / 3600);
const m = Math.floor(s % 3600 / 60);
return (h ? h + 'h ' : '') + (m ? m + 'm ' : '') + Math.floor(s % 3600 % 60) + 's';
}
function getTable(payload) {
if (payload === null) {
return "<table style=\"width: 100%; text-align: left;\"><tr><td>Player not registered</td><tr><td>You need to play at least 1 game of batle royale to be registered on <a href=\"https://agma.io/stats.php\" target=\"_blank\">Agma Stats</a></td></tr></table>";
}
return (
"<table style=\"width: 100%; text-align: left;\"><tr><td>Players Consumed: </td><td>"
+ numberFormat.format(payload.players_consumed)
+ "</td></tr><tr><td>Death Count: </td><td>"
+ numberFormat.format(payload.death_count)
+ "</td></tr><tr><td>K/D: </td><td>"
+ (payload.players_consumed / payload.death_count).toFixed(2)
+ "</td></tr><tr><td>Splits count: </td><td>"
+ numberFormat.format(payload.splits_count)
+ "</td></tr><tr><td>Total time alive: </td><td>"
+ timeFormat(payload.total_time_alive)
+ "</td></tr><tr><td>Splits per seconds: </td><td>"
+ (payload.splits_count / payload.total_time_alive).toFixed(2)
+ "</td></tr></table>"
);
}
const originalDrawImage = CanvasRenderingContext2D.prototype.drawImage;
unsafeWindow.CanvasRenderingContext2D.prototype.drawImage = function() {
if (arguments[0] instanceof Image && arguments[0].src.startsWith("https://agma.io/img/chaticons") && arguments[1] === 280) {
arguments[0] = discordIcon;
arguments[1] = 0;
arguments[6] += 3;
}
return originalDrawImage.apply(this, arguments);
}
const originalReplace = unsafeWindow.String.prototype.replace;
unsafeWindow.String.prototype.replace = function(pattern, replacement) {
return originalReplace.call(this, pattern, replacement instanceof Function && pattern instanceof RegExp && pattern.source.startsWith(":rolling") ? (match, offset) => match === ":/" && this?.[offset + 1] === '/' ? match : replacement(match, offset) : replacement);
}
const originalPush = unsafeWindow.Array.prototype.push;
unsafeWindow.Array.prototype.push = function(elem) {
if (elem?.time !== undefined && elem?.cache === null) {
if (localChatMessages === undefined) {
unsafeWindow.localChatMessages = localChatMessages = this;
}
if ((elem.message = elem.message.replaceAll(invisibleChar, "")).includes("https://")) {
Object.defineProperty(elem, "cache", {
get: function() {
return this._cache;
},
set: function(cache) {
if (elem._cache !== undefined) {
cache.icons = [ 14 ];
// see if this breaks calls and stuff but shouldnt
}
Object.defineProperty(cache, "ctx", {
get: function() {
return this._ctx;
},
set: function(ctx) {
ctx.fillText = function(text, x, y) {
if (this.fillStyle !== "#f5f6ce" && this.fillStyle !== "#444444") {
return CanvasRenderingContext2D.prototype.fillText.call(this, text, x, y);
}
// ngl I asked chatgpt cuz Im lazy (and I edited some stuff)
let match;
let lastIndex = 0;
let currentX = x;
cache.urls = [];
while ((match = urlRegex.exec(text)) !== null) {
const url = match[0];
const urlStart = match.index;
const urlEnd = urlStart + url.length;
const preText = text.slice(lastIndex, urlStart);
if (preText) {
CanvasRenderingContext2D.prototype.fillText.call(this, preText, currentX, y);
currentX += ctx.measureText(preText).width;
}
ctx.save();
ctx.fillStyle = '#1E90FF';
CanvasRenderingContext2D.prototype.fillText.call(this, url, currentX, y);
const urlWidth = ctx.measureText(url).width;
const textSize = parseInt(ctx.font.match(/\d+/), 10);
const underlineY = y + 2;
ctx.beginPath();
ctx.moveTo(currentX, underlineY);
ctx.lineTo(currentX + urlWidth, underlineY);
ctx.strokeStyle = '#1E90FF';
ctx.lineWidth = 1;
ctx.stroke();
ctx.restore();
cache.urls.push({
url,
rect: {
x0: currentX,
yd0: y - textSize,
x1: currentX + urlWidth,
yd1: y
}
});
currentX += urlWidth;
lastIndex = urlEnd;
}
const remainingText = text.slice(lastIndex);
if (remainingText) {
CanvasRenderingContext2D.prototype.fillText.call(this, remainingText, currentX, y);
}
}
return this._ctx = ctx;
}
});
return this._cache = cache;
}
});
}
} else if (elem?.ch !== undefined && elem?.x0 !== undefined) {
elem.ch.cache?.urls?.forEach(urlObject => {
urlObject.rect.y0 = urlObject.rect.yd0 + elem.y0;
urlObject.rect.y1 = urlObject.rect.yd1 + elem.y0;
});
} else if (elem?.namePart !== undefined && elem?.clanPart !== undefined) {
if (!cellProtoOverwritten) {
if (settings.removeAnimations.length) {
elem.constructor.prototype.ge = function(animation) {
if (1 == this.a || settings.removeAnimations.includes(animation.H)) {
return;
}
animation = { H: animation.H, K: animation.K, received: animation.received };
if (this.Ne) {
for (var i = 0; i < this.Ne.length; i++) {
if (this.Ne[i].received > animation.received) {
this.Ne.splice(i, 0, animation);
if (this.Ne.length > settings.maxStackableAnimations) {
this.Ne.splice(this.Ne.length - 2, 1);
}
return;
}
}
if (this.Ne.length < settings.maxStackableAnimations) {
originalPush.call(this.Ne, animation);
} else {
this.Ne[this.Ne.length - 1] = animation;
}
} else {
this.Ne = [animation];
}
}
}
cellProtoOverwritten = true;
}
if (settings.removeFood && elem.Pe) { // elem.a === 1
return 0;
}
}
return originalPush.apply(this, arguments);
}
unsafeWindow.setAnimation = (id, value) => settings.removeAnimations[settings.removeAnimations.includes(id) ? 'remove' : 'push'](id);
unsafeWindow.setMaxStackableAnimations = value => settings.maxStackableAnimations = parseInt(value);
unsafeWindow.setRemoveFood = value => settings.removeFood = value;
unsafeWindow.setDiscordChat = value => {
if (settings.discordChat = value) {
!discordWebSocket && initDiscordWebSocket();
} else if (discordWebSocket !== null) {
discordWebSocket.close();
discordWebSocket = null;
}
};
unsafeWindow.setDiscordPresenceChat = value => settings.discordPresence = value;
unsafeWindow.newDiscordTab = (name, channel) => chtTabs && (chtTabs.innerHTML += `<div data-category="2" data-username="discord-${channel}" data-insert data-tooltip="Discord chat: ${name}" class="chat-tab semi-selected">${name}</div>`);
/*
// could make your own messages show up faster but too annoying so no
createDiscordChatMessage({
id: null,
channel_id: channel,
type: 0,
author: discordUser,
content
});
*/
unsafeWindow.sendDiscordMessage = (channel, content) => settings.discordChat && discordUsername && fetch(`https://discord.com/api/v9/channels/${channel}/messages`, {
method: 'POST',
headers: {
'Authorization': discordToken,
'Content-Type': 'application/json'
},
body: JSON.stringify({
content,
tts: false
})
})
.then(async response => createDiscordChatMessage(await response.json()))
.catch(error => console.error('[🔵] Error while trying to send a message:', error));
var loaded = false;
unsafeWindow.addEventListener("load", () => {
if (loaded || typeof swal === "undefined") return;
loaded = true;
const chtCanvas = document.getElementById("chtCanvas");
chtCanvas.addEventListener("dblclick", findUrlToOpen);
chtCanvas.addEventListener("click", event => event.ctrlKey && findUrlToOpen(event));
document.getElementById("chtbox").addEventListener("keydown", function(event) {
if (event.keyCode === 13) {
if (!currentTab && this.value.startsWith("/discord ")) {
const args = this.value.slice(9).split(' ');
const channelName = args.shift();
this.value = args.join(' ').trim();
const channel = settings.discordSavedChannels.find(channel => channel.name === channelName);
if (channel && !chtTabs.querySelector(`div[data-username="discord-${channel.id}"]`)) {
newDiscordTab(channelName, channel.id);
}
if (this.value) {
sendDiscordMessage(channel.id, this.value);
this.value = '';
}
} else if (currentTab.startsWith("discord-")) {
if (this.value = this.value.trim()) {
sendDiscordMessage(currentTab.slice(8), this.value);
this.value = '';
}
} else {
for (const [reg, rep] of wordsToReplace) {
this.value = this.value.replaceAll(reg, rep);
}
}
}
});
// Script devs so annoying can't even use that for settings pages
// typeof GM_info === "undefined" ? Date.now() : GM_info?.script?.position + 3;
const settingPageId = Date.now();
chtTabs = document.getElementById("chtTabs");
chtTabs.addEventListener("click", () => setTimeout(() => currentTab = chtTabs.querySelector("div.chat-tab.selected").dataset.username, 1));
$('#settingTab2').after(`<button id="settingTab${settingPageId}" class="setting-tablink" onclick="openSettingPage(${settingPageId});">Advanced</button>`);
$('#settingPage3').after(`
<div id="settingPage${settingPageId}" class="setting-tabcontent">
<div class="col-md-10 col-md-offset-1 stng" style="padding-left:20px;padding-right:10px;max-height:550px;overflow-y:auto;overflow-x:hidden;margin:0;width:calc(100% - 5px);">
<span style="margin:0;" class="hotkey-paragraph"> Animations</span>
<div class="row stng-row" style="font-size:14px;">
<div style="width:100%;padding:4px;">
<div style="display:flex;flex-wrap:wrap;padding:0px;width:100%;">
${animationsIds.map(id => `<div style="${animations[id].style}" onclick="setAnimation(${id}, !this.classList.toggle('disabled'));" class="emote${settings.removeAnimations.includes(id) ? " disabled" : ''}">${animations[id].name}</div>`).join('')}
</div>
</div>
</div>
<span style="margin:0;" class="hotkey-paragraph"> Other</span>
<div class="row stng-row" style="font-size:14px;">
<label>
<input type="number" min="0" style="max-width:30px" value="${settings.maxStackableAnimations}" onchange="setMaxStackableAnimations(this.value);">
<span> Stackable Animations *</span>
</label>
<br>
<label>
<input type="checkbox" onchange="setRemoveFood(this.checked);" ${settings.removeFood ? " checked" : ''}>
<span> Remove Food *</span>
</label>
</div>
<span style="margin:0;" class="hotkey-paragraph"> Discord</span>
<div class="row stng-row" style="font-size:14px;">
<label>
<input type="checkbox" onchange="setDiscordChat(this.checked);" ${settings.discordChat ? " checked" : ''}>
<span> Discord Chat *</span>
</label>
<br>
<label>
<input type="checkbox" onchange="setDiscordPresenceChat(this.checked);" ${settings.discordPresence ? " checked" : ''}>
<span> Discord Agma.io Presence *</span>
</label>
<br>
<label>
<span> Discord Saved Channels *</span>
<textarea id="discordSavedChannels" style="resize: vertical; min-height: 100px; width: 100%;" placeholder="agma.io,942193976063197214\nname,channelId">${settings.discordSavedChannels.map(channel => channel.name + ',' + channel.id).join('\n')}</textarea>
</label>
</div>
</div>
</div>
`);
const discordSavedChannelsTextarea = document.getElementById("discordSavedChannels");
discordSavedChannelsTextarea.addEventListener("blur", function(event) {
settings.discordSavedChannels = [];
for (const line of this.value.split('\n')) {
let [name, id] = line.split(',');
name = name?.trim();
id = id?.trim();
if (name && id) {
settings.discordSavedChannels.push({ name, id });
} else {
swal('Invalid channels', 'Please ensure each line has exactly one comma separating the key and value.', 'error');
break;
}
}
});
discordSavedChannelsTextarea.addEventListener("keydown", function(event) {
event.stopPropagation();
});
const style = document.createElement("style");
style.innerHTML = `
div.chat-tab[data-username^="discord-"] {
background: #4954c5;
}
#settingPage${settingPageId} > div::-webkit-scrollbar {
width: 8px;
height: 8px;
}
#settingPage${settingPageId} > div::-webkit-scrollbar-track {
background: #282934;
border-radius: 10px;
}
#settingPage${settingPageId} > div::-webkit-scrollbar-thumb {
background-color: #df8500;
border-radius: 10px;
border: 2px solid #282934;
}
#settingPage${settingPageId} div.emote {
min-width: 30px;
height: 30px;
padding: 3px;
border-radius: 5px;
border-width: 1px;
border-style: solid;
margin: 4px;
background-size: contain;
background-repeat: no-repeat;
cursor: pointer;
text-overflow: ellipsis;
}
#settingPage${settingPageId} div.emote.disabled {
text-decoration: line-through;
text-decoration-thickness: 3px;
text-decoration-color: red;
}
`;
document.body.appendChild(style);
const originalFind = $.prototype.find;
unsafeWindow.$.prototype.find = function() {
const res = originalFind.apply(this, arguments);
if (
discordUserContext
&& this.selector === "#contextMenu"
&& arguments?.[0] === "li.enabled.hover"
&& res?.length
) {
if (res[0].id === "contextUserProfile") {
swal({
title: `<img src="https://cdn.discordapp.com/avatars/${discordUserContext.id}/${discordUserContext.avatar}" width="128" height="128" style="border-radius:50%;"><br><br><span>${discordUserContext.global_name || discordUserContext.username}</span><br><span style="font-size:12px;">${discordUserContext.username}</span>`,
html: true
});
return [];
} else if (res[0].id === "contextDiscordMention") {
document.getElementById("chtbox").value += `<@${discordUserContext.id}> `;
return [];
}
}
return res;
}
const originalAddClass = $.prototype.addClass;
unsafeWindow.$.prototype.addClass = function() {
if (discordUserContext && this.selector === "#contextMute") {
$("#contextDiscordMention").show();
originalAddClass.call($("#contextUserProfile"), "enabled");
$("#contextPlayerSkin").css({ 'background-image': `url(https://cdn.discordapp.com/avatars/${discordUserContext.id}/${discordUserContext.avatar})` });
$("#contextPartyLeave").hide();
$("#contextPartyMessage").hide();
$("#contextModerate").hide();
$("#contextPartyInvite").hide();
$("#contextFriendAdd").hide();
$("#contextPrivateMessage").hide();
$("#contextSpectate").hide();
$("#contextPickpocket").hide();
$("#contextMute").hide();
return this;
}
return originalAddClass.apply(this, arguments);
}
const originalHide = $.prototype.hide;
unsafeWindow.$.prototype.hide = function() {
if (discordUserContext && this.selector === "#contextMenu") {
$("#contextDiscordMention").hide();
$("#contextPartyLeave").show();
$("#contextPartyMessage").show();
$("#contextModerate").show();
$("#contextPartyInvite").show();
$("#contextFriendAdd").show();
$("#contextPrivateMessage").show();
$("#contextSpectate").show();
$("#contextPickpocket").show();
$("#contextMute").show();
discordUserContext = null;
}
return originalHide.apply(this, arguments);
}
$("#contextUserProfile").after('<li id="contextDiscordMention" class="contextmenu-item enabled" style="display: none;"><div class="fa fa-at fa-2x context-icon"></div><p>Mention</p></li>');
let waitingResponse = false;
const originalSwal = unsafeWindow.swal;
unsafeWindow.swal = function() {
if (
!discordUserContext
&& typeof arguments[0] === "object"
&& "title" in arguments[0]
&& arguments[0].title.startsWith("<img src=\"")
) {
if (waitingResponse) {
return;
}
const username = arguments[0].title.match(/>([^>]+)<\/span>/)?.[1];
if (!username) {
return originalSwal.apply(this, arguments);
}
if (Date.now() - userprofiles[username]?.at < 86400000) {
arguments[0].text += getTable(userprofiles[username].data);
} else {
waitingResponse = true;
$.getJSON("https://agma.io/royale_stats.php?user=" + username, payload => {
userprofiles[username] = { at: Date.now(), data: payload };
arguments[0].text += getTable(payload);
waitingResponse = false;
originalSwal.apply(this, arguments);
}).fail(() => {
userprofiles[username] = { at: Date.now(), data: null };
arguments[0].text += getTable(null);
waitingResponse = false;
originalSwal.apply(this, arguments);
}).always(() => {
waitingResponse = false;
});
return;
}
}
return originalSwal.apply(this, arguments);
}
unsafeWindow.swal.close = originalSwal.close;
});
unsafeWindow.addEventListener("beforeunload", () => {
discordWebSocket && discordWebSocket.close();
GM_setValue("settings", settings);
unsafeWindow.localStorage.userprofiles = JSON.stringify(userprofiles);
});
settings.discordChat && initDiscordWebSocket();
console.log("%cAdvanced Agma - 0.0.2 Loaded", "font-weight: bold; font-size: 20pt; color: black;");
})();