198 lines
5.8 KiB
TypeScript
198 lines
5.8 KiB
TypeScript
import { getAccountBalance, initAccounts, setAccountBalance } from "./account";
|
|
import { makeResultEmbed } from "./discord";
|
|
import { env } from "./env";
|
|
import {
|
|
checkForNewQuest,
|
|
getClanMembers,
|
|
getLatestQuest,
|
|
type QuestResult,
|
|
} from "./wov";
|
|
|
|
import { ChannelType, Client, GatewayIntentBits, Message } from "discord.js";
|
|
|
|
const client = new Client({
|
|
intents: [
|
|
GatewayIntentBits.Guilds,
|
|
GatewayIntentBits.GuildMessages,
|
|
GatewayIntentBits.MessageContent,
|
|
],
|
|
});
|
|
|
|
const askForGrinders = async (quest: QuestResult) => {
|
|
const adminChannel = await client.channels.fetch(env.DISCORD_ADMIN_CHANNEL);
|
|
if (!adminChannel || adminChannel.type !== ChannelType.GuildText)
|
|
throw "Invalid admin channel provided";
|
|
|
|
const top10 = quest.participants
|
|
.filter((x) => !env.QUEST_EXCLUDE.includes(x.username))
|
|
.sort((a, b) => b.xp - a.xp)
|
|
.slice(0, 10)
|
|
.map((p, i) => `${i + 1}. ${p.username} - ${p.xp}xp`)
|
|
.join("\n");
|
|
|
|
const color = parseInt(quest.quest.promoImagePrimaryColor.substring(1), 16);
|
|
|
|
await adminChannel.send({
|
|
content: `-# ||${env.DISCORD_ADMIN_MENTION}||`,
|
|
embeds: [
|
|
{
|
|
title: "Quête terminée !",
|
|
color,
|
|
},
|
|
{
|
|
title: "Top 10 XP",
|
|
description: top10,
|
|
color,
|
|
},
|
|
{
|
|
title: "Qui a grind ?",
|
|
description:
|
|
"Merci d'entrer les pseudos des joueurs qui ont grind.\n\nFormat:```@LBF laulau,Yuno,...```\n**Attention les majuscules comptent**\nPour entrer la liste des joueurs, il faut __mentionner le bot__, si personne n'a grind, `@LBF tg`",
|
|
color,
|
|
},
|
|
],
|
|
});
|
|
|
|
const filter = (msg: Message) =>
|
|
msg.channel.id === adminChannel.id &&
|
|
!msg.author.bot &&
|
|
msg.content.startsWith(`<@${client.user!.id}>`);
|
|
|
|
let confirmed = false;
|
|
let answer: string | null = null;
|
|
while (!confirmed) {
|
|
const collected = await adminChannel.awaitMessages({ filter, max: 1 });
|
|
answer = collected.first()?.content || null;
|
|
if (!answer) continue;
|
|
|
|
answer = answer.replace(`<@${client.user!.id}>`, "").trim();
|
|
if (answer.toLowerCase() === "tg") {
|
|
answer = "";
|
|
break;
|
|
}
|
|
|
|
const players = answer
|
|
.split(",")
|
|
.map((x) => x.trim())
|
|
.filter(Boolean);
|
|
await adminChannel.send({
|
|
embeds: [
|
|
{
|
|
title: "Joueurs entrés",
|
|
description: players.length
|
|
? players.map((name) => `- ${name}`).join("\n")
|
|
: "*Aucun joueur entré*",
|
|
color,
|
|
},
|
|
],
|
|
content: `Est-ce correct ? (oui/non)`,
|
|
});
|
|
const confirmFilter = (msg: Message) =>
|
|
msg.channel.id === adminChannel.id &&
|
|
!msg.author.bot &&
|
|
["oui", "non", "yes", "no"].includes(msg.content.toLowerCase());
|
|
const confirmCollected = await adminChannel.awaitMessages({
|
|
filter: confirmFilter,
|
|
max: 1,
|
|
});
|
|
const confirmation = confirmCollected.first()?.content.toLowerCase();
|
|
if (confirmation === "oui" || confirmation === "yes") {
|
|
confirmed = true;
|
|
await adminChannel.send({ content: "Ok" });
|
|
} else {
|
|
await adminChannel.send({
|
|
content: "D'accord, veuillez réessayer. Qui a grind ?",
|
|
});
|
|
}
|
|
}
|
|
|
|
if (answer === null) throw "unreachable";
|
|
|
|
const exclude = answer
|
|
.split(",")
|
|
.map((x) => x.trim())
|
|
.filter(Boolean);
|
|
const embed = await makeResultEmbed(quest, [...env.QUEST_EXCLUDE, ...exclude]);
|
|
const rewardChannel = await client.channels.fetch(
|
|
env.DISCORD_REWARDS_CHANNEL,
|
|
);
|
|
if (rewardChannel && rewardChannel.type === ChannelType.GuildText) {
|
|
await rewardChannel.send(embed);
|
|
} else {
|
|
throw "Invalid reward channel";
|
|
}
|
|
|
|
await adminChannel.send("Envoyé !");
|
|
console.log(`Quest result posted at: ${new Date().toISOString()}`);
|
|
};
|
|
|
|
const fn = async () => {
|
|
const quest = await checkForNewQuest();
|
|
if (quest) {
|
|
await askForGrinders(quest);
|
|
}
|
|
};
|
|
|
|
client.on("ready", async (client) => {
|
|
console.log(`Logged in as ${client.user.username}`);
|
|
|
|
await initAccounts();
|
|
|
|
await fn();
|
|
setInterval(fn, env.WOV_FETCH_INTERVAL);
|
|
});
|
|
|
|
client.on("messageCreate", async (message) => {
|
|
if (message.author.bot) return;
|
|
|
|
if (message.content.startsWith(`<@${client.user!.id}>`)) {
|
|
const [command, ...args] = message.content
|
|
.replace(`<@${client.user!.id}>`, "")
|
|
.trim()
|
|
.split(" ");
|
|
if (command === "ping") {
|
|
await message.reply("pong");
|
|
} else if (command === "result") {
|
|
const quest = await getLatestQuest();
|
|
await askForGrinders(quest);
|
|
} else if (command === "gemmes") {
|
|
let playerName = message.author.displayName.replace("🕸 |", "").trim();
|
|
if (args.length >= 1) {
|
|
playerName = args[0];
|
|
}
|
|
|
|
const clanMembers = await getClanMembers();
|
|
|
|
let clanMember = clanMembers.find((x) => x.username === playerName);
|
|
if (!clanMember) {
|
|
await message.reply(
|
|
`'${args[0]}' n'est pas dans le clan (la honte). **Attention les majuscules sont importantes**`,
|
|
);
|
|
} else {
|
|
if(args.length === 2) {
|
|
if (
|
|
(args[1][0] !== "+" && args[1][0] !== "-") ||
|
|
!args[1] ||
|
|
isNaN(Number(args[1].substring(1)))
|
|
) {
|
|
await message.reply(
|
|
`Format: \`@LBF gemmes <pseudo> <+GEMMES|-GEMMES>\`.\nExemple:\`@LBF gemmes Yuno -10000\`. **Attention les majuscules sont importantes**`,
|
|
);
|
|
return;
|
|
}
|
|
|
|
const mult = args[1][0] === '+' ? 1 : -1;
|
|
const delta = Number(args[1].substring(1)) * mult;
|
|
const balance = await getAccountBalance(clanMember.playerId);
|
|
await setAccountBalance(clanMember.playerId, Math.max(0, balance + delta));
|
|
}
|
|
|
|
const balance = await getAccountBalance(clanMember.playerId);
|
|
await message.reply(`Gemmes accumulées par ${playerName}: ${balance}`);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
await client.login(env.DISCORD_BOT_TOKEN);
|